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