1 /* Copyright (c) 2010-13 The Regents of the University of California
2 * Barret Rhoden <brho@cs.berkeley.edu>
3 * See LICENSE for details.
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. */
11 #include <ros/common.h>
13 #include <sys/queue.h>
24 TAILQ_HEAD(kthread_tailq, kthread);
25 TAILQ_HEAD(semaphore_tailq, semaphore);
27 #define GENBUF_SZ 128 /* plan9 uses this as a scratch space, per syscall */
29 #define KTH_IS_KTASK (1 << 0)
30 #define KTH_SAVE_ADDR_SPACE (1 << 1)
31 #define KTH_KTASK_FLAGS (KTH_IS_KTASK)
32 #define KTH_DEFAULT_FLAGS (KTH_SAVE_ADDR_SPACE)
34 /* This captures the essence of a kernel context that we want to suspend. When
35 * a kthread is running, we make sure its stacktop is the default kernel stack,
36 * meaning it will receive the interrupts from userspace. */
38 struct jmpbuf context;
42 struct errbuf *errbuf;
43 TAILQ_ENTRY(kthread) link;
44 /* ID, other shit, etc */
47 char generic_buf[GENBUF_SZ];
48 struct systrace_record *strace;
51 /* Semaphore for kthreads to sleep on. 0 or less means you need to sleep */
53 struct kthread_tailq waiters;
57 #ifdef CONFIG_SEMAPHORE_DEBUG
58 TAILQ_ENTRY(semaphore) link;
59 bool is_on_list; /* would like better sys/queue.h */
60 uintptr_t bt_pc; /* program counter of last down */
61 uintptr_t bt_fp; /* frame pointer of last down */
62 uint32_t calling_core;
66 /* omitted elements (the sem debug stuff) are initialized to 0 */
67 #define SEMAPHORE_INITIALIZER(name, n) \
69 .waiters = TAILQ_HEAD_INITIALIZER((name).waiters), \
71 .lock = SPINLOCK_INITIALIZER, \
75 #define SEMAPHORE_INITIALIZER_IRQSAVE(name, n) \
77 .waiters = TAILQ_HEAD_INITIALIZER((name).waiters), \
79 .lock = SPINLOCK_INITIALIZER_IRQSAVE, \
85 spinlock_t *lock; /* usually points to internal_ */
86 spinlock_t internal_lock;
87 unsigned long nr_waiters;
91 struct cv_lookup_elm {
92 TAILQ_ENTRY(cv_lookup_elm) link;
93 TAILQ_ENTRY(cv_lookup_elm) abortall_link; /* only used in abort_all */
95 struct kthread *kthread;
98 atomic_t abort_in_progress; /* 0 = no */
100 TAILQ_HEAD(cv_lookup_tailq, cv_lookup_elm);
102 uintptr_t get_kstack(void);
103 void put_kstack(uintptr_t stacktop);
104 uintptr_t *kstack_bottom_addr(uintptr_t stacktop);
105 void kthread_init(void);
106 struct kthread *__kthread_zalloc(void);
107 void restart_kthread(struct kthread *kthread);
108 void kthread_runnable(struct kthread *kthread);
109 void kthread_yield(void);
110 void kthread_usleep(uint64_t usec);
111 void ktask(char *name, void (*fn)(void*), void *arg);
113 static inline bool is_ktask(struct kthread *kthread)
115 return kthread->flags & KTH_IS_KTASK;
119 void check_poison(char *msg);
121 void sem_init(struct semaphore *sem, int signals);
122 void sem_init_irqsave(struct semaphore *sem, int signals);
123 bool sem_trydown(struct semaphore *sem);
124 void sem_down(struct semaphore *sem);
125 bool sem_up(struct semaphore *sem);
126 bool sem_trydown_irqsave(struct semaphore *sem, int8_t *irq_state);
127 void sem_down_irqsave(struct semaphore *sem, int8_t *irq_state);
128 bool sem_up_irqsave(struct semaphore *sem, int8_t *irq_state);
129 void print_sem_info(struct semaphore *sem);
130 void print_all_sem_info(void);
132 void cv_init(struct cond_var *cv);
133 void cv_init_irqsave(struct cond_var *cv);
134 void cv_init_with_lock(struct cond_var *cv, spinlock_t *lock);
135 void cv_init_irqsave_with_lock(struct cond_var *cv, spinlock_t *lock);
136 void cv_lock(struct cond_var *cv);
137 void cv_unlock(struct cond_var *cv);
138 void cv_lock_irqsave(struct cond_var *cv, int8_t *irq_state);
139 void cv_unlock_irqsave(struct cond_var *cv, int8_t *irq_state);
140 void cv_wait_and_unlock(struct cond_var *cv); /* does not mess with irqs */
141 void cv_wait(struct cond_var *cv);
142 void __cv_signal(struct cond_var *cv);
143 void __cv_broadcast(struct cond_var *cv);
144 void cv_signal(struct cond_var *cv);
145 void cv_broadcast(struct cond_var *cv);
146 void cv_signal_irqsave(struct cond_var *cv, int8_t *irq_state);
147 void cv_broadcast_irqsave(struct cond_var *cv, int8_t *irq_state);
149 bool abort_sysc(struct proc *p, struct syscall *sysc);
150 void abort_all_sysc(struct proc *p);
151 int abort_all_sysc_fd(struct proc *p, int fd);
152 void __reg_abortable_cv(struct cv_lookup_elm *cle, struct cond_var *cv);
153 void dereg_abortable_cv(struct cv_lookup_elm *cle);
154 bool should_abort(struct cv_lookup_elm *cle);
156 uintptr_t switch_to_ktask(void);
157 void switch_back_from_ktask(uintptr_t old_ret);
159 /* qlocks are plan9's binary sempahore, which are wrappers around our sems.
160 * Not sure if they'll need irqsave or normal sems. */
161 typedef struct semaphore qlock_t;
162 #define qlock_init(x) sem_init((x), 1)
163 #define qlock(x) sem_down(x)
164 #define qunlock(x) sem_up(x)
165 #define canqlock(x) sem_trydown(x)
166 #define QLOCK_INITIALIZER(name) SEMAPHORE_INITIALIZER(name, 1)