pkgin_all: script to auto-install all packages
[minix.git] / lib / libddekit / src / thread.c
blobc8b2ba141701fd93b630e057374d722fbddb3acd
1 #include "common.h"
2 #include <ddekit/assert.h>
3 #include <ddekit/condvar.h>
4 #include <ddekit/memory.h>
5 #include <ddekit/panic.h>
6 #include <ddekit/timer.h>
8 #ifdef DDEBUG_LEVEL_THREAD
9 #undef DDEBUG
10 #define DDEBUG DDEBUG_LEVEL_THREAD
11 #endif
13 #include "debug.h"
14 #include "util.h"
15 #include "thread.h"
16 #include "timer.h"
19 /* Incremented to generate unique thread IDs */
20 static unsigned id;
22 static ddekit_thread_t *ready_queue[DDEKIT_THREAD_PRIOS];
24 static ddekit_thread_t *sleep_queue;
26 /* Handle to the running thread, set in _dde_kit_thread_schedule() */
27 static ddekit_thread_t *current = NULL;
29 static void _ddekit_thread_start(ddekit_thread_t *th);
30 static void _ddekit_thread_sleep(unsigned long until);
32 /*****************************************************************************
33 * _ddekit_thread_start *
34 ****************************************************************************/
35 static void _ddekit_thread_start(ddekit_thread_t *th)
37 /* entry point of newly created threads */
38 th->fun(th->arg);
39 ddekit_thread_exit();
42 /*****************************************************************************
43 * _ddekit_thread_sleep *
44 ****************************************************************************/
45 static void _ddekit_thread_sleep(unsigned long until)
47 current->next = sleep_queue;
48 sleep_queue = current;
49 current->sleep_until = until;
50 _ddekit_thread_schedule();
54 /*****************************************************************************
55 * DDEKIT public thread API (ddekit/thread.h) *
56 ****************************************************************************/
58 /*****************************************************************************
59 * ddekit_yield *
60 ****************************************************************************/
61 void ddekit_yield()
63 ddekit_thread_schedule();
66 /*****************************************************************************
67 * ddekit_thread_schedule *
68 ****************************************************************************/
69 void ddekit_thread_schedule()
71 _ddekit_thread_enqueue(current);
72 _ddekit_thread_schedule();
75 /*****************************************************************************
76 * ddekit_thread_create *
77 ****************************************************************************/
78 ddekit_thread_t *
79 ddekit_thread_create(void (*fun)(void *), void *arg, const char *name)
81 ddekit_thread_t *th =
82 (ddekit_thread_t *) ddekit_simple_malloc(sizeof(ddekit_thread_t));
84 strncpy(th->name, name, DDEKIT_THREAD_NAMELEN);
85 th->name[DDEKIT_THREAD_NAMELEN-1] = 0;
87 th->stack = ddekit_large_malloc(DDEKIT_THREAD_STACKSIZE);
89 th->arg = arg;
90 th->fun = fun;
92 th->id = id++;
93 th->prio = DDEKIT_THREAD_STDPRIO;
94 th->next = NULL;
95 th->sleep_sem = ddekit_sem_init(0);
98 /* setup stack */
100 void **ptr = (void **)(th->stack + DDEKIT_THREAD_STACKSIZE);
101 *(--ptr) = th;
102 --ptr;
103 --ptr;
105 /* TAKEN FROM P_THREAD (written by david?)*/
106 #ifdef __ACK__
107 th->jb[0].__pc = _ddekit_thread_start;
108 th->jb[0].__sp = ptr;
109 #else /* !__ACK__ */
110 #include <sys/jmp_buf.h>
111 #if defined(JB_PC) && defined(JB_SP)
112 /* um, yikes. */
114 *((void (**)(void))(&((char *)th->jb)[JB_PC])) =
115 (void *)_ddekit_thread_start;
117 *((void **)(&((char *)th->jb)[JB_SP])) = ptr;
118 #else
119 #error "Unsupported Minix architecture"
120 #endif
121 #endif /* !__ACK__ */
123 DDEBUG_MSG_VERBOSE("created thread %s, stack at: %p\n", name,
124 th->stack + DDEKIT_THREAD_STACKSIZE);
125 _ddekit_thread_enqueue(th);
127 return th;
130 /*****************************************************************************
131 * ddekit_thread_get_data *
132 ****************************************************************************/
133 void *ddekit_thread_get_data(ddekit_thread_t *thread)
135 return thread->data;
138 /*****************************************************************************
139 * ddekit_thread_get_my_data *
140 ****************************************************************************/
141 void *ddekit_thread_get_my_data(void)
143 return current->data;
146 /*****************************************************************************
147 * ddekit_thread_myself *
148 ****************************************************************************/
150 ddekit_thread_t *ddekit_thread_myself(void)
152 return current;
155 /*****************************************************************************
156 * ddekit_thread_setup_myself *
157 ****************************************************************************/
159 ddekit_thread_t *ddekit_thread_setup_myself(const char *name) {
160 ddekit_thread_t *th =
161 (ddekit_thread_t *) ddekit_simple_malloc(sizeof(ddekit_thread_t));
163 strncpy(th->name, name, DDEKIT_THREAD_NAMELEN);
164 th->name[DDEKIT_THREAD_NAMELEN-1] = 0;
165 th->stack = NULL;
166 th->next = NULL;
167 th->id = id++;
168 th->prio = DDEKIT_THREAD_STDPRIO;
169 th->sleep_sem = ddekit_sem_init(0);
170 #if DDEBUG >= 4
171 _ddekit_print_backtrace(th);
172 #endif
173 return th;
176 /*****************************************************************************
177 * ddekit_thread_set_data *
178 ****************************************************************************/
179 void ddekit_thread_set_data(ddekit_thread_t *thread, void *data)
181 thread->data=data;
184 /*****************************************************************************
185 * ddekit_thread_set_my_data *
186 ****************************************************************************/
187 void ddekit_thread_set_my_data(void *data)
189 current->data = data;
192 /*****************************************************************************
193 * ddekit_thread_usleep *
194 ****************************************************************************/
195 void ddekit_thread_usleep(unsigned long usecs)
198 * Cannot use usleep here, because it's implemented in vfs.
199 * Assuming the anyway no finder granularity than system's HZ value
200 * can be reached. So we use dde_kit_thread_msleep for now.
203 /* If no timeout is 0 return immediately */
204 if (usecs == 0)
205 return;
207 unsigned long to = usecs/1000;
209 /* round up to to possible granularity */
211 if (to == 0)
212 to = 1;
214 ddekit_thread_msleep(to);
217 /*****************************************************************************
218 * ddekit_thread_nsleep *
219 ****************************************************************************/
220 void ddekit_thread_nsleep(unsigned long nsecs)
223 * Cannot use usleep here, because it's implemented in vfs.
224 * Assuming the anyway no finder granularity than system's HZ value
225 * can be reached. So we use dde_kit_thread_msleep.
228 /* If no timeout is 0 return immediately */
229 if (nsecs == 0)
230 return;
232 unsigned long to = nsecs/1000;
234 /* round up to to possible granularity */
236 if (to == 0)
237 to = 1;
239 ddekit_thread_usleep(to);
242 /*****************************************************************************
243 * ddekit_thread_msleep *
244 ****************************************************************************/
245 void ddekit_thread_msleep(unsigned long msecs)
247 unsigned long to;
249 to = (msecs*HZ/1000);
251 if (to == 0) {
252 to = 1;
255 ddekit_thread_t *th = ddekit_thread_myself();
257 if (th == NULL) {
258 ddekit_panic("th==NULL!");
261 if (th->sleep_sem == NULL) {
262 ddekit_panic("th->sleepsem==NULL! %p %s ", th, th->name);
265 /* generate a timer interrupt at to */
266 ddekit_add_timer(NULL, NULL, to+jiffies);
267 _ddekit_thread_sleep(to+jiffies);
270 /*****************************************************************************
271 * ddekit_thread_sleep *
272 ****************************************************************************/
273 void ddekit_thread_sleep(ddekit_lock_t *lock)
275 WARN_UNIMPL;
278 /*****************************************************************************
279 * ddekit_thread_exit *
280 ****************************************************************************/
281 void ddekit_thread_exit()
283 ddekit_sem_down(current->sleep_sem);
284 ddekit_panic("thread running after exit!\n");
285 /* not reached */
286 while(1);
289 /*****************************************************************************
290 * ddekit_thread_terminate *
291 ****************************************************************************/
292 void ddekit_thread_terminate(ddekit_thread_t *thread)
294 /* todo */
297 /*****************************************************************************
298 * ddekit_thread_get_name *
299 ****************************************************************************/
300 const char *ddekit_thread_get_name(ddekit_thread_t *thread)
302 return thread->name;
305 /*****************************************************************************
306 * ddekit_thread_get_id *
307 ****************************************************************************/
308 int ddekit_thread_get_id(ddekit_thread_t *thread)
310 return thread->id;
313 /*****************************************************************************
314 * ddekit_init_threads *
315 ****************************************************************************/
316 void ddekit_init_threads(void)
318 int i;
320 for (i =0 ; i < DDEKIT_THREAD_PRIOS ; i++) {
321 ready_queue[i] = NULL;
324 current = ddekit_thread_setup_myself("main");
326 DDEBUG_MSG_INFO("ddekit thread subsystem initialized");
329 /*****************************************************************************
330 * DDEKIT internals (src/thread.h) *
331 *****************************************************************************/
333 /*****************************************************************************
334 * _ddekit_thread_schedule *
335 ****************************************************************************/
336 void _ddekit_thread_schedule()
339 DDEBUG_MSG_VERBOSE("called schedule id: %d name %s, prio: %d",
340 current->id, current->name, current->prio);
342 /* get our tcb */
343 ddekit_thread_t * th = current;
345 #if DDEBUG >= 4
346 _ddekit_print_backtrace(th);
347 #endif
349 /* save our context */
350 if (_setjmp(th->jb) == 0) {
352 int i;
354 /* find a runnable thread */
356 current = NULL;
358 for (i = DDEKIT_THREAD_PRIOS-1; i >= 0; i--) {
359 if (ready_queue[i]!=NULL) {
360 current = ready_queue[i];
361 ready_queue[i] = current->next;
362 current->next=NULL;
363 break;
367 if (current == NULL) {
368 ddekit_panic("No runable threads?!");
371 DDEBUG_MSG_VERBOSE("switching to id: %d name %s, prio: %d",
372 current->id, current->name, current->prio);
373 #if DDEBUG >= 4
374 _ddekit_print_backtrace(current);
375 #endif
376 _longjmp(current->jb, 1);
381 /*****************************************************************************
382 * _ddekit_thread_enqueue *
383 ****************************************************************************/
384 void _ddekit_thread_enqueue(ddekit_thread_t *th)
387 DDEBUG_MSG_VERBOSE("enqueueing thread: id: %d name %s, prio: %d",
388 th->id, th->name, th->prio);
390 #if DDEBUG >= 4
391 _ddekit_print_backtrace(th);
392 #endif
394 ddekit_assert(th->next==NULL);
396 if (ready_queue[th->prio] != NULL) {
397 ddekit_thread_t *pos = ready_queue[th->prio];
398 while (pos->next != NULL) {
399 pos = pos->next;
401 pos->next = th;
402 } else {
403 ready_queue[th->prio] = th;
407 /*****************************************************************************
408 * _ddekit_thread_set_myprio *
409 ****************************************************************************/
410 void _ddekit_thread_set_myprio(int prio)
412 DDEBUG_MSG_VERBOSE("changing thread prio, id: %d name %s, old prio: %d, "
413 "new prio: %d", current->id, current->name, current->prio);
415 current->prio = prio;
416 ddekit_thread_schedule();
419 /*****************************************************************************
420 * _ddekit_thread_wakeup_sleeping *
421 ****************************************************************************/
422 void _ddekit_thread_wakeup_sleeping()
424 ddekit_thread_t *th = sleep_queue;
426 sleep_queue = NULL;
428 while (th != NULL) {
429 ddekit_thread_t *th1 = th->next;
430 if (th->sleep_until > jiffies) {
431 th->next = sleep_queue;
432 sleep_queue = th;
433 } else {
434 th->next = NULL;
435 _ddekit_thread_enqueue(th);
437 th = th1;
440 ddekit_thread_schedule();
443 #define FUNC_STACKTRACE(statement) \
445 reg_t bp, pc, hbp; \
446 extern reg_t get_bp(void); \
448 bp= get_bp(); \
449 while(bp) \
451 pc= ((reg_t *)bp)[1]; \
452 hbp= ((reg_t *)bp)[0]; \
453 statement; \
454 if (hbp != 0 && hbp <= bp) \
456 pc = -1; \
457 statement; \
458 break; \
460 bp= hbp; \
464 /*****************************************************************************
465 * _ddekit_print_backtrace *
466 ****************************************************************************/
467 void _ddekit_print_backtrace(ddekit_thread_t *th)
469 unsigned long bp, pc, hbp;
471 ddekit_printf("%s: ", th->name);
473 #ifdef __ACK__
474 bp =th->jb[0].__bp;
475 #else /* !__ACK__ */
476 #include <sys/jmp_buf.h>
477 #if defined(JB_BP)
478 /* um, yikes. */
479 bp = (unsigned long) *((void **)(&((char *)th->jb)[JB_BP]));
480 #else
481 #error "Unsupported Minix architecture"
482 #endif
483 #endif /* !__ACK__ */
485 while (bp) {
486 pc = ((unsigned long *)bp)[1];
487 hbp = ((unsigned long *)bp)[0];
489 ddekit_printf("0x%lx ", (unsigned long) pc);
491 if (hbp != 0 && hbp <= bp) {
492 pc = -1;
493 ddekit_printf("0x%lx ", (unsigned long) pc);
494 break;
496 bp= hbp;
498 ddekit_printf("\n");