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>
9 #ifdef DDEBUG_LEVEL_THREAD
11 #define DDEBUG DDEBUG_LEVEL_THREAD
14 //#define DDEBUG DDEBUG_VERBOSE
22 /* Incremented to generate unique thread IDs */
25 static ddekit_thread_t
*ready_queue
[DDEKIT_THREAD_PRIOS
];
27 static ddekit_thread_t
*sleep_queue
;
29 /* Handle to the running thread, set in _dde_kit_thread_schedule() */
30 static ddekit_thread_t
*current
= NULL
;
32 static void _ddekit_thread_start(ddekit_thread_t
*th
);
33 static void _ddekit_thread_sleep(unsigned long until
);
34 static void _ddekit_dump_queues(void);
36 /*****************************************************************************
37 * _ddekit_thread_start *
38 ****************************************************************************/
39 static void _ddekit_thread_start(ddekit_thread_t
*th
)
41 /* entry point of newly created threads */
46 /*****************************************************************************
47 * _ddekit_thread_sleep *
48 ****************************************************************************/
49 static void _ddekit_thread_sleep(unsigned long until
)
51 current
->next
= sleep_queue
;
52 sleep_queue
= current
;
53 current
->sleep_until
= until
;
54 _ddekit_thread_schedule();
58 /*****************************************************************************
59 * _ddekit_dump_queues *
60 ****************************************************************************/
62 _ddekit_dump_queues(void)
64 #if DDEBUG >= DDEBUG_VERBOSE
65 ddekit_thread_t
* current_thread
;
68 for (i
= 0; i
< DDEKIT_THREAD_PRIOS
; i
++) {
69 current_thread
= ready_queue
[i
];
71 ddekit_printf("Ready queue #%d: ", i
);
73 while (NULL
!= current_thread
) {
74 ddekit_printf("0x%08X ", (int)current_thread
);
75 current_thread
= current_thread
->next
;
82 current_thread
= sleep_queue
;
84 ddekit_printf("Sleep queue: ");
86 while (NULL
!= current_thread
) {
87 ddekit_printf("0x%08X ", (int)current_thread
);
88 current_thread
= current_thread
->next
;
94 ddekit_printf("Current thread: 0x%08X\n", (int)current
);
98 /*****************************************************************************
99 * DDEKIT public thread API (ddekit/thread.h) *
100 ****************************************************************************/
102 /*****************************************************************************
104 ****************************************************************************/
107 ddekit_thread_schedule();
110 /*****************************************************************************
111 * ddekit_thread_schedule *
112 ****************************************************************************/
113 void ddekit_thread_schedule()
115 _ddekit_thread_enqueue(current
);
116 _ddekit_thread_schedule();
119 /*****************************************************************************
120 * ddekit_thread_create *
121 ****************************************************************************/
123 ddekit_thread_create(void (*fun
)(void *), void *arg
, const char *name
)
125 ddekit_thread_t
*th
=
126 (ddekit_thread_t
*) ddekit_simple_malloc(sizeof(ddekit_thread_t
));
127 memset(th
,0,sizeof(ddekit_thread_t
));
128 strncpy(th
->name
, name
, DDEKIT_THREAD_NAMELEN
);
129 th
->name
[DDEKIT_THREAD_NAMELEN
-1] = 0;
131 th
->stack
= ddekit_simple_malloc(DDEKIT_THREAD_STACKSIZE
);
137 th
->prio
= DDEKIT_THREAD_STDPRIO
;
139 th
->sleep_sem
= ddekit_sem_init(0);
141 /* Setup thread context */
142 th
->ctx
.uc_flags
|= _UC_IGNSIGM
| _UC_IGNFPU
;
143 if (getcontext(&th
->ctx
) != 0) {
144 panic("ddekit thread create thread getcontext error");
146 th
->ctx
.uc_stack
.ss_sp
= th
->stack
;/* makecontext will determine sp */
147 th
->ctx
.uc_stack
.ss_size
= DDEKIT_THREAD_STACKSIZE
;
148 makecontext(&th
->ctx
,_ddekit_thread_start
,1 /* argc */,th
/* pass thread as argument */);
149 DDEBUG_MSG_VERBOSE("created thread %s, stack at: %p\n", name
,
150 th
->stack
+ DDEKIT_THREAD_STACKSIZE
);
151 _ddekit_thread_enqueue(th
);
156 /*****************************************************************************
157 * ddekit_thread_get_data *
158 ****************************************************************************/
159 void *ddekit_thread_get_data(ddekit_thread_t
*thread
)
164 /*****************************************************************************
165 * ddekit_thread_get_my_data *
166 ****************************************************************************/
167 void *ddekit_thread_get_my_data(void)
169 return current
->data
;
172 /*****************************************************************************
173 * ddekit_thread_myself *
174 ****************************************************************************/
176 ddekit_thread_t
*ddekit_thread_myself(void)
181 /*****************************************************************************
182 * ddekit_thread_setup_myself *
183 ****************************************************************************/
185 ddekit_thread_t
*ddekit_thread_setup_myself(const char *name
) {
186 ddekit_thread_t
*th
=
187 (ddekit_thread_t
*) ddekit_simple_malloc(sizeof(ddekit_thread_t
));
188 memset(th
,0,sizeof(ddekit_thread_t
));
189 strncpy(th
->name
, name
, DDEKIT_THREAD_NAMELEN
);
190 th
->name
[DDEKIT_THREAD_NAMELEN
-1] = 0;
194 th
->prio
= DDEKIT_THREAD_STDPRIO
;
195 th
->sleep_sem
= ddekit_sem_init(0);
197 _ddekit_print_backtrace(th
);
202 /*****************************************************************************
203 * ddekit_thread_set_data *
204 ****************************************************************************/
205 void ddekit_thread_set_data(ddekit_thread_t
*thread
, void *data
)
210 /*****************************************************************************
211 * ddekit_thread_set_my_data *
212 ****************************************************************************/
213 void ddekit_thread_set_my_data(void *data
)
215 current
->data
= data
;
218 /*****************************************************************************
219 * ddekit_thread_usleep *
220 ****************************************************************************/
221 void ddekit_thread_usleep(unsigned long usecs
)
224 * Cannot use usleep here, because it's implemented in vfs.
225 * Assuming the anyway no finder granularity than system's HZ value
226 * can be reached. So we use dde_kit_thread_msleep for now.
229 /* If no timeout is 0 return immediately */
233 unsigned long to
= usecs
/1000;
235 /* round up to to possible granularity */
240 ddekit_thread_msleep(to
);
243 /*****************************************************************************
244 * ddekit_thread_nsleep *
245 ****************************************************************************/
246 void ddekit_thread_nsleep(unsigned long nsecs
)
249 * Cannot use usleep here, because it's implemented in vfs.
250 * Assuming the anyway no finder granularity than system's HZ value
251 * can be reached. So we use dde_kit_thread_msleep.
254 /* If no timeout is 0 return immediately */
258 unsigned long to
= nsecs
/1000;
260 /* round up to to possible granularity */
265 ddekit_thread_usleep(to
);
268 /*****************************************************************************
269 * ddekit_thread_msleep *
270 ****************************************************************************/
271 void ddekit_thread_msleep(unsigned long msecs
)
275 to
= (msecs
*HZ
/1000);
281 ddekit_thread_t
*th
= ddekit_thread_myself();
284 ddekit_panic("th==NULL!");
287 if (th
->sleep_sem
== NULL
) {
288 ddekit_panic("th->sleepsem==NULL! %p %s ", th
, th
->name
);
291 /* generate a timer interrupt at to */
292 ddekit_add_timer(NULL
, NULL
, to
+jiffies
);
293 _ddekit_thread_sleep(to
+jiffies
);
296 /*****************************************************************************
297 * ddekit_thread_sleep *
298 ****************************************************************************/
299 void ddekit_thread_sleep(ddekit_lock_t
*lock
)
304 /*****************************************************************************
305 * ddekit_thread_exit *
306 ****************************************************************************/
307 void ddekit_thread_exit()
309 ddekit_sem_down(current
->sleep_sem
);
310 ddekit_panic("thread running after exit!\n");
315 /*****************************************************************************
316 * ddekit_thread_terminate *
317 ****************************************************************************/
319 ddekit_thread_terminate(ddekit_thread_t
* thread
)
321 if (thread
== ddekit_thread_myself()) {
322 /* TODO: Whether or not this is an error, is to be decided.
323 * Memory (especially stack) freeing should be somehow
324 * postponed when such termination is legal. */
325 ddekit_panic("Thread attempted termination of itself!\n");
328 _ddekit_thread_dequeue(thread
);
330 ddekit_sem_deinit(thread
->sleep_sem
);
332 ddekit_simple_free(thread
->stack
);
334 ddekit_simple_free(thread
);
337 /*****************************************************************************
338 * ddekit_thread_get_name *
339 ****************************************************************************/
340 const char *ddekit_thread_get_name(ddekit_thread_t
*thread
)
345 /*****************************************************************************
346 * ddekit_thread_get_id *
347 ****************************************************************************/
348 int ddekit_thread_get_id(ddekit_thread_t
*thread
)
353 /*****************************************************************************
354 * ddekit_init_threads *
355 ****************************************************************************/
356 void ddekit_init_threads(void)
360 for (i
=0 ; i
< DDEKIT_THREAD_PRIOS
; i
++) {
361 ready_queue
[i
] = NULL
;
364 current
= ddekit_thread_setup_myself("main");
366 DDEBUG_MSG_INFO("ddekit thread subsystem initialized");
369 /*****************************************************************************
370 * DDEKIT internals (src/thread.h) *
371 *****************************************************************************/
373 /*****************************************************************************
374 * _ddekit_thread_schedule *
375 ****************************************************************************/
376 void _ddekit_thread_schedule()
379 DDEBUG_MSG_VERBOSE("called schedule id: %d name %s, prio: %d",
380 current
->id
, current
->name
, current
->prio
);
383 ddekit_thread_t
* th
= current
;
384 volatile int is_callback
;
387 _ddekit_print_backtrace(th
);
389 /* getcontext saves the current context in ctx. When setcontext is called
390 * with that ctx it will return execution at getcontext here. To
391 * discriminate between the initial call to getcontext that simply returns
392 * and the situation where getcontext returns because of a setcontext call
393 * we use the is_callback variable.
395 * When the program flow passes via the assignment bellow it will enter
396 * the scheduling loop and set is_callback to 1. When the function returns
397 * because of a setcontext call the program skip the scheduling and return
398 * from this method to continue normal execution.
401 /* save our context */
402 th
->ctx
.uc_flags
|= _UC_IGNSIGM
| _UC_IGNFPU
;
403 if (getcontext(&th
->ctx
) != 0){
404 panic("ddekit thread schedule getcontext error");
406 if (is_callback
== 0) {
410 /* find a runnable thread */
414 for (i
= DDEKIT_THREAD_PRIOS
-1; i
>= 0; i
--) {
415 if (ready_queue
[i
]!=NULL
) {
416 current
= ready_queue
[i
];
417 ready_queue
[i
] = current
->next
;
423 if (current
== NULL
) {
424 ddekit_panic("No runnable threads?!");
427 DDEBUG_MSG_VERBOSE("switching to id: %d name %s, prio: %d",
428 current
->id
, current
->name
, current
->prio
);
430 _ddekit_print_backtrace(current
);
432 //th->ctx.uc_flags |= _UC_IGNSIGM | _UC_IGNFPU;
433 if (setcontext(¤t
->ctx
) == -1){
434 panic("ddekit threading setcontext error");
436 panic("unreachable code");
438 DDEBUG_MSG_VERBOSE("continuing thread execution id: %d name %s, prio: %d",
439 current
->id
, current
->name
, current
->prio
);
443 /*****************************************************************************
444 * _ddekit_thread_enqueue *
445 ****************************************************************************/
446 void _ddekit_thread_enqueue(ddekit_thread_t
*th
)
448 DDEBUG_MSG_VERBOSE("Enqueuing thread 0x%08X: id %d, name %s, prio %d",
449 (int)th
, th
->id
, th
->name
, th
->prio
);
452 _ddekit_print_backtrace(th
);
455 ddekit_assert(th
->next
==NULL
);
457 if (ready_queue
[th
->prio
] != NULL
) {
458 ddekit_thread_t
*pos
= ready_queue
[th
->prio
];
459 while (pos
->next
!= NULL
) {
464 ready_queue
[th
->prio
] = th
;
468 /*****************************************************************************
469 * _ddekit_thread_dequeue *
470 ****************************************************************************/
472 _ddekit_thread_dequeue(ddekit_thread_t
* th
)
474 ddekit_thread_t
* current_thread
;
475 ddekit_thread_t
* previous_thread
;
477 DDEBUG_MSG_VERBOSE("Dequeuing thread 0x%08X: id %d, name %s, prio %d",
478 (int)th
, th
->id
, th
->name
, th
->prio
);
480 ddekit_assert((th
->prio
< DDEKIT_THREAD_PRIOS
) && (th
->prio
>= 0));
482 /* Dump queues when debugging */
483 _ddekit_dump_queues();
485 /* Check ready queue (based on thread's priority) for thread */
486 current_thread
= ready_queue
[th
->prio
];
487 previous_thread
= NULL
;
489 while (NULL
!= current_thread
) {
492 if (th
== current_thread
) {
494 if (previous_thread
) {
495 /* ...fix previous element to remove current */
496 previous_thread
->next
= current_thread
->next
;
498 /* ...alter queue start to reflect removal */
499 ready_queue
[th
->prio
] = current_thread
->next
;
502 /* Thread found and dequeued */
503 DDEBUG_MSG_VERBOSE("Dequeued 'ready[%d]': 0x%08X",
509 previous_thread
= current_thread
;
510 current_thread
= current_thread
->next
;
513 /* When previous loop fails, check if thread is sleeping */
514 current_thread
= sleep_queue
;
515 previous_thread
= NULL
;
517 while (NULL
!= current_thread
) {
520 if (th
== current_thread
) {
522 if (previous_thread
) {
523 /* ...fix previous element to remove current */
524 previous_thread
->next
= current_thread
->next
;
526 /* ...alter queue start to reflect removal */
527 sleep_queue
= current_thread
->next
;
530 /* Thread found and dequeued */
531 DDEBUG_MSG_VERBOSE("Dequeued 'sleep': 0x%08X", (int)th
);
536 previous_thread
= current_thread
;
537 current_thread
= current_thread
->next
;
540 /* Thread may exist and not be enqueued at
541 * all (is bound to semaphore for instance) */
542 DDEBUG_MSG_VERBOSE("Thread 0x%08X was not enqueued!", (int)th
);
545 /*****************************************************************************
546 * _ddekit_thread_set_myprio *
547 ****************************************************************************/
548 void _ddekit_thread_set_myprio(int prio
)
550 DDEBUG_MSG_VERBOSE("changing thread prio, id: %d name %s, old prio: %d, "
551 "new prio: %d", current
->id
, current
->name
, current
->prio
, prio
);
553 current
->prio
= prio
;
554 ddekit_thread_schedule();
557 /*****************************************************************************
558 * _ddekit_thread_wakeup_sleeping *
559 ****************************************************************************/
560 void _ddekit_thread_wakeup_sleeping()
562 ddekit_thread_t
*th
= sleep_queue
;
567 ddekit_thread_t
*th1
= th
->next
;
568 if (th
->sleep_until
> jiffies
) {
569 th
->next
= sleep_queue
;
573 _ddekit_thread_enqueue(th
);
578 ddekit_thread_schedule();
581 #define FUNC_STACKTRACE(statement) \
584 extern reg_t get_bp(void); \
589 pc= ((reg_t *)bp)[1]; \
590 hbp= ((reg_t *)bp)[0]; \
592 if (hbp != 0 && hbp <= bp) \
602 /*****************************************************************************
603 * _ddekit_print_backtrace *
604 ****************************************************************************/
605 void _ddekit_print_backtrace(ddekit_thread_t
*th
)
608 unsigned long bp
, pc
, hbp
;
610 ddekit_printf("%s: ", th
->name
);
612 bp
= th
->ctx
.uc_mcontext
.__gregs
[_REG_EBP
];
614 pc
= ((unsigned long *)bp
)[1];
615 hbp
= ((unsigned long *)bp
)[0];
617 ddekit_printf("0x%lx ", (unsigned long) pc
);
619 if (hbp
!= 0 && hbp
<= bp
) {
621 ddekit_printf("0x%lx ", (unsigned long) pc
);