Condition variables
[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 syscall                          *sysc;
29         TAILQ_ENTRY(kthread)            link;
30         /* ID, other shit, etc */
31 };
32
33 /* Semaphore for kthreads to sleep on.  0 or less means you need to sleep */
34 struct semaphore {
35         struct kthread_tailq            waiters;
36         int                                             nr_signals;
37         spinlock_t                                      lock;
38 };
39
40 struct cond_var {
41         struct semaphore                        sem;
42         spinlock_t                                      lock;
43         unsigned long                           nr_waiters;
44 };
45
46 /* This doesn't have to be inline, but it doesn't matter for now */
47 static inline void init_sem(struct semaphore *sem, int signals)
48 {
49         TAILQ_INIT(&sem->waiters);
50         sem->nr_signals = signals;
51         spinlock_init(&sem->lock);
52 }
53
54 /* Down and up for the semaphore are a little more low-level than usual, since
55  * they are meant to be called by functions that manage the sleeping of a
56  * kthread.  For instance, __down_sem() always returns right away.  For now,
57  * these are just examples, since the actual usage will probably need lower
58  * access. */
59
60 /* Down : decrement, if it was 0 or less, we need to sleep.  Returns false if
61  * the kthread did not need to sleep (the signal was already there). */
62 static inline bool __down_sem(struct semaphore *sem, struct kthread *kthread)
63 {
64         /* Don't actually use this, this is an example of how to build a sem */
65         assert(0);
66         bool retval = FALSE;
67         spin_lock_irqsave(&sem->lock);
68         if (sem->nr_signals-- <= 0) {
69                 /* Need to sleep */
70                 retval = TRUE;
71                 TAILQ_INSERT_TAIL(&sem->waiters, kthread, link);
72         }
73         spin_unlock_irqsave(&sem->lock);
74         return retval;
75 }
76
77 /* Ups the semaphore.  If it was < 0, we need to wake up someone, which is the
78  * return value.  If you think there should be at most one, set exactly_one. */
79 static inline struct kthread *__up_sem(struct semaphore *sem, bool exactly_one)
80 {
81         struct kthread *kthread = 0;
82         spin_lock_irqsave(&sem->lock);
83         if (sem->nr_signals++ < 0) {
84                 /* could do something with 'priority' here */
85                 kthread = TAILQ_FIRST(&sem->waiters);
86                 TAILQ_REMOVE(&sem->waiters, kthread, link);
87                 if (exactly_one)
88                         assert(TAILQ_EMPTY(&sem->waiters));
89         } else {
90                 assert(TAILQ_EMPTY(&sem->waiters));
91         }
92         spin_unlock_irqsave(&sem->lock);
93         return kthread;
94 }
95
96 void kthread_init(void);
97 void sleep_on(struct semaphore *sem);
98 void restart_kthread(struct kthread *kthread);
99 void kthread_runnable(struct kthread *kthread);
100 /* Kmsg handler to launch/run a kthread.  This must be a routine message, since
101  * it does not return. */
102 void __launch_kthread(struct trapframe *tf, uint32_t srcid, long a0, long a1,
103                           long a2);
104 void kthread_yield(void);
105
106 void cv_init(struct cond_var *cv);
107 void cv_lock(struct cond_var *cv);
108 void cv_unlock(struct cond_var *cv);
109 void cv_wait_and_unlock(struct cond_var *cv);
110 void cv_wait(struct cond_var *cv);
111 void cv_signal(struct cond_var *cv);
112 void cv_broadcast(struct cond_var *cv);
113
114 #endif /* ROS_KERN_KTHREAD_H */