612831791716c445a0b2768c1a6b56e971638972
[akaros.git] / kern / include / kthread.h
1 /* Copyright (c) 2010 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Kernel threading.  These are for blocking within the kernel for whatever
6  * reason, usually during blocking IO operations.  Check out
7  * Documentation/kthreads.txt for more info than you care about. */
8
9 #ifndef ROS_KERN_KTHREAD_H
10 #define ROS_KERN_KTHREAD_H
11
12 #include <ros/common.h>
13 #include <trap.h>
14 #include <sys/queue.h>
15 #include <atomic.h>
16
17 struct proc;
18 struct kthread;
19 TAILQ_HEAD(kthread_tailq, kthread);
20
21 /* This captures the essence of a kernel context that we want to suspend.  When
22  * a kthread is running, we make sure its stacktop is the default kernel stack,
23  * meaning it will receive the interrupts from userspace. */
24 struct kthread {
25         struct trapframe                        context;
26         uintptr_t                                       stacktop;
27         struct proc                                     *proc;
28         struct trapframe                        *proc_tf;                       /* TODO: change this? */
29         /* TODO: put in the sys_return, if we decide to keep this shit */
30         TAILQ_ENTRY(kthread)            link;
31         /* ID, other shit, etc */
32 };
33
34 /* Semaphore for kthreads to sleep on.  0 or less means you need to sleep */
35 struct semaphore {
36         struct kthread_tailq            waiters;
37         int                                             nr_signals;
38         spinlock_t                                      lock;
39 };
40
41 /* This doesn't have to be inline, but it doesn't matter for now */
42 static inline void init_sem(struct semaphore *sem, int signals)
43 {
44         TAILQ_INIT(&sem->waiters);
45         sem->nr_signals = signals;
46         spinlock_init(&sem->lock);
47 }
48
49 /* Down and up for the semaphore are a little more low-level than usual, since
50  * they are meant to be called by functions that manage the sleeping of a
51  * kthread.  For instance, __down_sem() always returns right away.  For now,
52  * these are just examples, since the actual usage will probably need lower
53  * access. */
54
55 /* Down : decrement, if it was 0 or less, we need to sleep.  Returns false if
56  * the kthread did not need to sleep (the signal was already there). */
57 static inline bool __down_sem(struct semaphore *sem, struct kthread *kthread)
58 {
59         bool retval = FALSE;
60         spin_lock(&sem->lock);
61         if (sem->nr_signals-- <= 0) {
62                 /* Need to sleep */
63                 retval = TRUE;
64                 TAILQ_INSERT_TAIL(&sem->waiters, kthread, link);
65         }
66         spin_unlock(&sem->lock);
67         return retval;
68 }
69
70 /* Ups the semaphore.  If it was < 0, we need to wake up someone, which is the
71  * return value. */
72 static inline struct kthread *__up_sem(struct semaphore *sem)
73 {
74         struct kthread *kthread = 0;
75         spin_lock(&sem->lock);
76         if (sem->nr_signals++ < 0) {
77                 /* could do something with 'priority' here */
78                 kthread = TAILQ_FIRST(&sem->waiters);
79                 TAILQ_REMOVE(&sem->waiters, kthread, link);
80         } else {
81                 assert(TAILQ_EMPTY(&sem->waiters));
82         }
83         spin_unlock(&sem->lock);
84         return kthread;
85 }
86
87 void kthread_init(void);
88 void sleep_on(struct semaphore *sem);
89 void restart_kthread(struct kthread *kthread);
90
91 #endif /* ROS_KERN_KTHREAD_H */