1*433d6423SLionel Sambuc #include "common.h"
2*433d6423SLionel Sambuc #include <ddekit/assert.h>
3*433d6423SLionel Sambuc #include <ddekit/condvar.h>
4*433d6423SLionel Sambuc #include <ddekit/memory.h>
5*433d6423SLionel Sambuc #include <ddekit/panic.h>
6*433d6423SLionel Sambuc #include <ddekit/timer.h>
7*433d6423SLionel Sambuc
8*433d6423SLionel Sambuc
9*433d6423SLionel Sambuc #ifdef DDEBUG_LEVEL_THREAD
10*433d6423SLionel Sambuc #undef DDEBUG
11*433d6423SLionel Sambuc #define DDEBUG DDEBUG_LEVEL_THREAD
12*433d6423SLionel Sambuc #endif
13*433d6423SLionel Sambuc
14*433d6423SLionel Sambuc //#define DDEBUG DDEBUG_VERBOSE
15*433d6423SLionel Sambuc
16*433d6423SLionel Sambuc #include "debug.h"
17*433d6423SLionel Sambuc #include "util.h"
18*433d6423SLionel Sambuc #include "thread.h"
19*433d6423SLionel Sambuc #include "timer.h"
20*433d6423SLionel Sambuc
21*433d6423SLionel Sambuc
22*433d6423SLionel Sambuc /* Incremented to generate unique thread IDs */
23*433d6423SLionel Sambuc static unsigned id;
24*433d6423SLionel Sambuc
25*433d6423SLionel Sambuc static ddekit_thread_t *ready_queue[DDEKIT_THREAD_PRIOS];
26*433d6423SLionel Sambuc
27*433d6423SLionel Sambuc static ddekit_thread_t *sleep_queue;
28*433d6423SLionel Sambuc
29*433d6423SLionel Sambuc /* Handle to the running thread, set in _dde_kit_thread_schedule() */
30*433d6423SLionel Sambuc static ddekit_thread_t *current = NULL;
31*433d6423SLionel Sambuc
32*433d6423SLionel Sambuc static void _ddekit_thread_start(ddekit_thread_t *th);
33*433d6423SLionel Sambuc static void _ddekit_thread_sleep(unsigned long until);
34*433d6423SLionel Sambuc static void _ddekit_dump_queues(void);
35*433d6423SLionel Sambuc
36*433d6423SLionel Sambuc /*****************************************************************************
37*433d6423SLionel Sambuc * _ddekit_thread_start *
38*433d6423SLionel Sambuc ****************************************************************************/
_ddekit_thread_start(ddekit_thread_t * th)39*433d6423SLionel Sambuc static void _ddekit_thread_start(ddekit_thread_t *th)
40*433d6423SLionel Sambuc {
41*433d6423SLionel Sambuc /* entry point of newly created threads */
42*433d6423SLionel Sambuc th->fun(th->arg);
43*433d6423SLionel Sambuc ddekit_thread_exit();
44*433d6423SLionel Sambuc }
45*433d6423SLionel Sambuc
46*433d6423SLionel Sambuc /*****************************************************************************
47*433d6423SLionel Sambuc * _ddekit_thread_sleep *
48*433d6423SLionel Sambuc ****************************************************************************/
_ddekit_thread_sleep(unsigned long until)49*433d6423SLionel Sambuc static void _ddekit_thread_sleep(unsigned long until)
50*433d6423SLionel Sambuc {
51*433d6423SLionel Sambuc current->next = sleep_queue;
52*433d6423SLionel Sambuc sleep_queue = current;
53*433d6423SLionel Sambuc current->sleep_until = until;
54*433d6423SLionel Sambuc _ddekit_thread_schedule();
55*433d6423SLionel Sambuc
56*433d6423SLionel Sambuc }
57*433d6423SLionel Sambuc
58*433d6423SLionel Sambuc /*****************************************************************************
59*433d6423SLionel Sambuc * _ddekit_dump_queues *
60*433d6423SLionel Sambuc ****************************************************************************/
61*433d6423SLionel Sambuc static void
_ddekit_dump_queues(void)62*433d6423SLionel Sambuc _ddekit_dump_queues(void)
63*433d6423SLionel Sambuc {
64*433d6423SLionel Sambuc #if DDEBUG >= DDEBUG_VERBOSE
65*433d6423SLionel Sambuc ddekit_thread_t * current_thread;
66*433d6423SLionel Sambuc int i;
67*433d6423SLionel Sambuc
68*433d6423SLionel Sambuc for (i = 0; i < DDEKIT_THREAD_PRIOS; i++) {
69*433d6423SLionel Sambuc current_thread = ready_queue[i];
70*433d6423SLionel Sambuc
71*433d6423SLionel Sambuc ddekit_printf("Ready queue #%d: ", i);
72*433d6423SLionel Sambuc
73*433d6423SLionel Sambuc while (NULL != current_thread) {
74*433d6423SLionel Sambuc ddekit_printf("0x%08X ", (int)current_thread);
75*433d6423SLionel Sambuc current_thread = current_thread->next;
76*433d6423SLionel Sambuc }
77*433d6423SLionel Sambuc
78*433d6423SLionel Sambuc ddekit_printf("\n");
79*433d6423SLionel Sambuc }
80*433d6423SLionel Sambuc
81*433d6423SLionel Sambuc {
82*433d6423SLionel Sambuc current_thread = sleep_queue;
83*433d6423SLionel Sambuc
84*433d6423SLionel Sambuc ddekit_printf("Sleep queue: ");
85*433d6423SLionel Sambuc
86*433d6423SLionel Sambuc while (NULL != current_thread) {
87*433d6423SLionel Sambuc ddekit_printf("0x%08X ", (int)current_thread);
88*433d6423SLionel Sambuc current_thread = current_thread->next;
89*433d6423SLionel Sambuc }
90*433d6423SLionel Sambuc
91*433d6423SLionel Sambuc ddekit_printf("\n");
92*433d6423SLionel Sambuc }
93*433d6423SLionel Sambuc
94*433d6423SLionel Sambuc ddekit_printf("Current thread: 0x%08X\n", (int)current);
95*433d6423SLionel Sambuc #endif
96*433d6423SLionel Sambuc }
97*433d6423SLionel Sambuc
98*433d6423SLionel Sambuc /*****************************************************************************
99*433d6423SLionel Sambuc * DDEKIT public thread API (ddekit/thread.h) *
100*433d6423SLionel Sambuc ****************************************************************************/
101*433d6423SLionel Sambuc
102*433d6423SLionel Sambuc /*****************************************************************************
103*433d6423SLionel Sambuc * ddekit_yield *
104*433d6423SLionel Sambuc ****************************************************************************/
ddekit_yield()105*433d6423SLionel Sambuc void ddekit_yield()
106*433d6423SLionel Sambuc {
107*433d6423SLionel Sambuc ddekit_thread_schedule();
108*433d6423SLionel Sambuc }
109*433d6423SLionel Sambuc
110*433d6423SLionel Sambuc /*****************************************************************************
111*433d6423SLionel Sambuc * ddekit_thread_schedule *
112*433d6423SLionel Sambuc ****************************************************************************/
ddekit_thread_schedule()113*433d6423SLionel Sambuc void ddekit_thread_schedule()
114*433d6423SLionel Sambuc {
115*433d6423SLionel Sambuc _ddekit_thread_enqueue(current);
116*433d6423SLionel Sambuc _ddekit_thread_schedule();
117*433d6423SLionel Sambuc }
118*433d6423SLionel Sambuc
119*433d6423SLionel Sambuc /*****************************************************************************
120*433d6423SLionel Sambuc * ddekit_thread_create *
121*433d6423SLionel Sambuc ****************************************************************************/
122*433d6423SLionel Sambuc ddekit_thread_t *
ddekit_thread_create(void (* fun)(void *),void * arg,const char * name)123*433d6423SLionel Sambuc ddekit_thread_create(void (*fun)(void *), void *arg, const char *name)
124*433d6423SLionel Sambuc {
125*433d6423SLionel Sambuc ddekit_thread_t *th =
126*433d6423SLionel Sambuc (ddekit_thread_t *) ddekit_simple_malloc(sizeof(ddekit_thread_t));
127*433d6423SLionel Sambuc memset(th,0,sizeof(ddekit_thread_t));
128*433d6423SLionel Sambuc strncpy(th->name, name, DDEKIT_THREAD_NAMELEN);
129*433d6423SLionel Sambuc th->name[DDEKIT_THREAD_NAMELEN-1] = 0;
130*433d6423SLionel Sambuc
131*433d6423SLionel Sambuc th->stack = ddekit_simple_malloc(DDEKIT_THREAD_STACKSIZE);
132*433d6423SLionel Sambuc
133*433d6423SLionel Sambuc th->arg = arg;
134*433d6423SLionel Sambuc th->fun = fun;
135*433d6423SLionel Sambuc
136*433d6423SLionel Sambuc th->id = id++;
137*433d6423SLionel Sambuc th->prio = DDEKIT_THREAD_STDPRIO;
138*433d6423SLionel Sambuc th->next = NULL;
139*433d6423SLionel Sambuc th->sleep_sem = ddekit_sem_init(0);
140*433d6423SLionel Sambuc
141*433d6423SLionel Sambuc /* Setup thread context */
142*433d6423SLionel Sambuc th->ctx.uc_flags |= _UC_IGNSIGM | _UC_IGNFPU;
143*433d6423SLionel Sambuc if (getcontext(&th->ctx) != 0) {
144*433d6423SLionel Sambuc panic("ddekit thread create thread getcontext error");
145*433d6423SLionel Sambuc }
146*433d6423SLionel Sambuc th->ctx.uc_stack.ss_sp = th->stack;/* makecontext will determine sp */
147*433d6423SLionel Sambuc th->ctx.uc_stack.ss_size = DDEKIT_THREAD_STACKSIZE;
148*433d6423SLionel Sambuc makecontext(&th->ctx,_ddekit_thread_start,1 /* argc */,th /* pass thread as argument */);
149*433d6423SLionel Sambuc DDEBUG_MSG_VERBOSE("created thread %s, stack at: %p\n", name,
150*433d6423SLionel Sambuc th->stack + DDEKIT_THREAD_STACKSIZE);
151*433d6423SLionel Sambuc _ddekit_thread_enqueue(th);
152*433d6423SLionel Sambuc
153*433d6423SLionel Sambuc return th;
154*433d6423SLionel Sambuc }
155*433d6423SLionel Sambuc
156*433d6423SLionel Sambuc /*****************************************************************************
157*433d6423SLionel Sambuc * ddekit_thread_get_data *
158*433d6423SLionel Sambuc ****************************************************************************/
ddekit_thread_get_data(ddekit_thread_t * thread)159*433d6423SLionel Sambuc void *ddekit_thread_get_data(ddekit_thread_t *thread)
160*433d6423SLionel Sambuc {
161*433d6423SLionel Sambuc return thread->data;
162*433d6423SLionel Sambuc }
163*433d6423SLionel Sambuc
164*433d6423SLionel Sambuc /*****************************************************************************
165*433d6423SLionel Sambuc * ddekit_thread_get_my_data *
166*433d6423SLionel Sambuc ****************************************************************************/
ddekit_thread_get_my_data(void)167*433d6423SLionel Sambuc void *ddekit_thread_get_my_data(void)
168*433d6423SLionel Sambuc {
169*433d6423SLionel Sambuc return current->data;
170*433d6423SLionel Sambuc }
171*433d6423SLionel Sambuc
172*433d6423SLionel Sambuc /*****************************************************************************
173*433d6423SLionel Sambuc * ddekit_thread_myself *
174*433d6423SLionel Sambuc ****************************************************************************/
175*433d6423SLionel Sambuc
ddekit_thread_myself(void)176*433d6423SLionel Sambuc ddekit_thread_t *ddekit_thread_myself(void)
177*433d6423SLionel Sambuc {
178*433d6423SLionel Sambuc return current;
179*433d6423SLionel Sambuc }
180*433d6423SLionel Sambuc
181*433d6423SLionel Sambuc /*****************************************************************************
182*433d6423SLionel Sambuc * ddekit_thread_setup_myself *
183*433d6423SLionel Sambuc ****************************************************************************/
184*433d6423SLionel Sambuc
ddekit_thread_setup_myself(const char * name)185*433d6423SLionel Sambuc ddekit_thread_t *ddekit_thread_setup_myself(const char *name) {
186*433d6423SLionel Sambuc ddekit_thread_t *th =
187*433d6423SLionel Sambuc (ddekit_thread_t *) ddekit_simple_malloc(sizeof(ddekit_thread_t));
188*433d6423SLionel Sambuc memset(th,0,sizeof(ddekit_thread_t));
189*433d6423SLionel Sambuc strncpy(th->name, name, DDEKIT_THREAD_NAMELEN);
190*433d6423SLionel Sambuc th->name[DDEKIT_THREAD_NAMELEN-1] = 0;
191*433d6423SLionel Sambuc th->stack = NULL;
192*433d6423SLionel Sambuc th->next = NULL;
193*433d6423SLionel Sambuc th->id = id++;
194*433d6423SLionel Sambuc th->prio = DDEKIT_THREAD_STDPRIO;
195*433d6423SLionel Sambuc th->sleep_sem = ddekit_sem_init(0);
196*433d6423SLionel Sambuc #if DDEBUG >= 4
197*433d6423SLionel Sambuc _ddekit_print_backtrace(th);
198*433d6423SLionel Sambuc #endif
199*433d6423SLionel Sambuc return th;
200*433d6423SLionel Sambuc }
201*433d6423SLionel Sambuc
202*433d6423SLionel Sambuc /*****************************************************************************
203*433d6423SLionel Sambuc * ddekit_thread_set_data *
204*433d6423SLionel Sambuc ****************************************************************************/
ddekit_thread_set_data(ddekit_thread_t * thread,void * data)205*433d6423SLionel Sambuc void ddekit_thread_set_data(ddekit_thread_t *thread, void *data)
206*433d6423SLionel Sambuc {
207*433d6423SLionel Sambuc thread->data=data;
208*433d6423SLionel Sambuc }
209*433d6423SLionel Sambuc
210*433d6423SLionel Sambuc /*****************************************************************************
211*433d6423SLionel Sambuc * ddekit_thread_set_my_data *
212*433d6423SLionel Sambuc ****************************************************************************/
ddekit_thread_set_my_data(void * data)213*433d6423SLionel Sambuc void ddekit_thread_set_my_data(void *data)
214*433d6423SLionel Sambuc {
215*433d6423SLionel Sambuc current->data = data;
216*433d6423SLionel Sambuc }
217*433d6423SLionel Sambuc
218*433d6423SLionel Sambuc /*****************************************************************************
219*433d6423SLionel Sambuc * ddekit_thread_usleep *
220*433d6423SLionel Sambuc ****************************************************************************/
ddekit_thread_usleep(unsigned long usecs)221*433d6423SLionel Sambuc void ddekit_thread_usleep(unsigned long usecs)
222*433d6423SLionel Sambuc {
223*433d6423SLionel Sambuc /*
224*433d6423SLionel Sambuc * Cannot use usleep here, because it's implemented in vfs.
225*433d6423SLionel Sambuc * Assuming the anyway no finder granularity than system's HZ value
226*433d6423SLionel Sambuc * can be reached. So we use dde_kit_thread_msleep for now.
227*433d6423SLionel Sambuc */
228*433d6423SLionel Sambuc
229*433d6423SLionel Sambuc /* If no timeout is 0 return immediately */
230*433d6423SLionel Sambuc if (usecs == 0)
231*433d6423SLionel Sambuc return;
232*433d6423SLionel Sambuc
233*433d6423SLionel Sambuc unsigned long to = usecs/1000;
234*433d6423SLionel Sambuc
235*433d6423SLionel Sambuc /* round up to to possible granularity */
236*433d6423SLionel Sambuc
237*433d6423SLionel Sambuc if (to == 0)
238*433d6423SLionel Sambuc to = 1;
239*433d6423SLionel Sambuc
240*433d6423SLionel Sambuc ddekit_thread_msleep(to);
241*433d6423SLionel Sambuc }
242*433d6423SLionel Sambuc
243*433d6423SLionel Sambuc /*****************************************************************************
244*433d6423SLionel Sambuc * ddekit_thread_nsleep *
245*433d6423SLionel Sambuc ****************************************************************************/
ddekit_thread_nsleep(unsigned long nsecs)246*433d6423SLionel Sambuc void ddekit_thread_nsleep(unsigned long nsecs)
247*433d6423SLionel Sambuc {
248*433d6423SLionel Sambuc /*
249*433d6423SLionel Sambuc * Cannot use usleep here, because it's implemented in vfs.
250*433d6423SLionel Sambuc * Assuming the anyway no finder granularity than system's HZ value
251*433d6423SLionel Sambuc * can be reached. So we use dde_kit_thread_msleep.
252*433d6423SLionel Sambuc */
253*433d6423SLionel Sambuc
254*433d6423SLionel Sambuc /* If no timeout is 0 return immediately */
255*433d6423SLionel Sambuc if (nsecs == 0)
256*433d6423SLionel Sambuc return;
257*433d6423SLionel Sambuc
258*433d6423SLionel Sambuc unsigned long to = nsecs/1000;
259*433d6423SLionel Sambuc
260*433d6423SLionel Sambuc /* round up to to possible granularity */
261*433d6423SLionel Sambuc
262*433d6423SLionel Sambuc if (to == 0)
263*433d6423SLionel Sambuc to = 1;
264*433d6423SLionel Sambuc
265*433d6423SLionel Sambuc ddekit_thread_usleep(to);
266*433d6423SLionel Sambuc }
267*433d6423SLionel Sambuc
268*433d6423SLionel Sambuc /*****************************************************************************
269*433d6423SLionel Sambuc * ddekit_thread_msleep *
270*433d6423SLionel Sambuc ****************************************************************************/
ddekit_thread_msleep(unsigned long msecs)271*433d6423SLionel Sambuc void ddekit_thread_msleep(unsigned long msecs)
272*433d6423SLionel Sambuc {
273*433d6423SLionel Sambuc unsigned long to;
274*433d6423SLionel Sambuc
275*433d6423SLionel Sambuc to = (msecs*HZ/1000);
276*433d6423SLionel Sambuc
277*433d6423SLionel Sambuc if (to == 0) {
278*433d6423SLionel Sambuc to = 1;
279*433d6423SLionel Sambuc }
280*433d6423SLionel Sambuc
281*433d6423SLionel Sambuc ddekit_thread_t *th = ddekit_thread_myself();
282*433d6423SLionel Sambuc
283*433d6423SLionel Sambuc if (th == NULL) {
284*433d6423SLionel Sambuc ddekit_panic("th==NULL!");
285*433d6423SLionel Sambuc }
286*433d6423SLionel Sambuc
287*433d6423SLionel Sambuc if (th->sleep_sem == NULL) {
288*433d6423SLionel Sambuc ddekit_panic("th->sleepsem==NULL! %p %s ", th, th->name);
289*433d6423SLionel Sambuc }
290*433d6423SLionel Sambuc
291*433d6423SLionel Sambuc /* generate a timer interrupt at to */
292*433d6423SLionel Sambuc ddekit_add_timer(NULL, NULL, to+jiffies);
293*433d6423SLionel Sambuc _ddekit_thread_sleep(to+jiffies);
294*433d6423SLionel Sambuc }
295*433d6423SLionel Sambuc
296*433d6423SLionel Sambuc /*****************************************************************************
297*433d6423SLionel Sambuc * ddekit_thread_sleep *
298*433d6423SLionel Sambuc ****************************************************************************/
ddekit_thread_sleep(ddekit_lock_t * lock)299*433d6423SLionel Sambuc void ddekit_thread_sleep(ddekit_lock_t *lock)
300*433d6423SLionel Sambuc {
301*433d6423SLionel Sambuc WARN_UNIMPL;
302*433d6423SLionel Sambuc }
303*433d6423SLionel Sambuc
304*433d6423SLionel Sambuc /*****************************************************************************
305*433d6423SLionel Sambuc * ddekit_thread_exit *
306*433d6423SLionel Sambuc ****************************************************************************/
ddekit_thread_exit()307*433d6423SLionel Sambuc void ddekit_thread_exit()
308*433d6423SLionel Sambuc {
309*433d6423SLionel Sambuc ddekit_sem_down(current->sleep_sem);
310*433d6423SLionel Sambuc ddekit_panic("thread running after exit!\n");
311*433d6423SLionel Sambuc /* not reached */
312*433d6423SLionel Sambuc while(1);
313*433d6423SLionel Sambuc }
314*433d6423SLionel Sambuc
315*433d6423SLionel Sambuc /*****************************************************************************
316*433d6423SLionel Sambuc * ddekit_thread_terminate *
317*433d6423SLionel Sambuc ****************************************************************************/
318*433d6423SLionel Sambuc void
ddekit_thread_terminate(ddekit_thread_t * thread)319*433d6423SLionel Sambuc ddekit_thread_terminate(ddekit_thread_t * thread)
320*433d6423SLionel Sambuc {
321*433d6423SLionel Sambuc if (thread == ddekit_thread_myself()) {
322*433d6423SLionel Sambuc /* TODO: Whether or not this is an error, is to be decided.
323*433d6423SLionel Sambuc * Memory (especially stack) freeing should be somehow
324*433d6423SLionel Sambuc * postponed when such termination is legal. */
325*433d6423SLionel Sambuc ddekit_panic("Thread attempted termination of itself!\n");
326*433d6423SLionel Sambuc }
327*433d6423SLionel Sambuc
328*433d6423SLionel Sambuc _ddekit_thread_dequeue(thread);
329*433d6423SLionel Sambuc
330*433d6423SLionel Sambuc ddekit_sem_deinit(thread->sleep_sem);
331*433d6423SLionel Sambuc
332*433d6423SLionel Sambuc ddekit_simple_free(thread->stack);
333*433d6423SLionel Sambuc
334*433d6423SLionel Sambuc ddekit_simple_free(thread);
335*433d6423SLionel Sambuc }
336*433d6423SLionel Sambuc
337*433d6423SLionel Sambuc /*****************************************************************************
338*433d6423SLionel Sambuc * ddekit_thread_get_name *
339*433d6423SLionel Sambuc ****************************************************************************/
ddekit_thread_get_name(ddekit_thread_t * thread)340*433d6423SLionel Sambuc const char *ddekit_thread_get_name(ddekit_thread_t *thread)
341*433d6423SLionel Sambuc {
342*433d6423SLionel Sambuc return thread->name;
343*433d6423SLionel Sambuc }
344*433d6423SLionel Sambuc
345*433d6423SLionel Sambuc /*****************************************************************************
346*433d6423SLionel Sambuc * ddekit_thread_get_id *
347*433d6423SLionel Sambuc ****************************************************************************/
ddekit_thread_get_id(ddekit_thread_t * thread)348*433d6423SLionel Sambuc int ddekit_thread_get_id(ddekit_thread_t *thread)
349*433d6423SLionel Sambuc {
350*433d6423SLionel Sambuc return thread->id;
351*433d6423SLionel Sambuc }
352*433d6423SLionel Sambuc
353*433d6423SLionel Sambuc /*****************************************************************************
354*433d6423SLionel Sambuc * ddekit_init_threads *
355*433d6423SLionel Sambuc ****************************************************************************/
ddekit_init_threads(void)356*433d6423SLionel Sambuc void ddekit_init_threads(void)
357*433d6423SLionel Sambuc {
358*433d6423SLionel Sambuc int i;
359*433d6423SLionel Sambuc
360*433d6423SLionel Sambuc for (i =0 ; i < DDEKIT_THREAD_PRIOS ; i++) {
361*433d6423SLionel Sambuc ready_queue[i] = NULL;
362*433d6423SLionel Sambuc }
363*433d6423SLionel Sambuc
364*433d6423SLionel Sambuc current = ddekit_thread_setup_myself("main");
365*433d6423SLionel Sambuc
366*433d6423SLionel Sambuc DDEBUG_MSG_INFO("ddekit thread subsystem initialized");
367*433d6423SLionel Sambuc }
368*433d6423SLionel Sambuc
369*433d6423SLionel Sambuc /*****************************************************************************
370*433d6423SLionel Sambuc * DDEKIT internals (src/thread.h) *
371*433d6423SLionel Sambuc *****************************************************************************/
372*433d6423SLionel Sambuc
373*433d6423SLionel Sambuc /*****************************************************************************
374*433d6423SLionel Sambuc * _ddekit_thread_schedule *
375*433d6423SLionel Sambuc ****************************************************************************/
_ddekit_thread_schedule()376*433d6423SLionel Sambuc void _ddekit_thread_schedule()
377*433d6423SLionel Sambuc {
378*433d6423SLionel Sambuc
379*433d6423SLionel Sambuc DDEBUG_MSG_VERBOSE("called schedule id: %d name %s, prio: %d",
380*433d6423SLionel Sambuc current->id, current->name, current->prio);
381*433d6423SLionel Sambuc
382*433d6423SLionel Sambuc /* get our tcb */
383*433d6423SLionel Sambuc ddekit_thread_t * th = current;
384*433d6423SLionel Sambuc volatile int is_callback;
385*433d6423SLionel Sambuc
386*433d6423SLionel Sambuc #if DDEBUG >= 4
387*433d6423SLionel Sambuc _ddekit_print_backtrace(th);
388*433d6423SLionel Sambuc #endif
389*433d6423SLionel Sambuc /* getcontext saves the current context in ctx. When setcontext is called
390*433d6423SLionel Sambuc * with that ctx it will return execution at getcontext here. To
391*433d6423SLionel Sambuc * discriminate between the initial call to getcontext that simply returns
392*433d6423SLionel Sambuc * and the situation where getcontext returns because of a setcontext call
393*433d6423SLionel Sambuc * we use the is_callback variable.
394*433d6423SLionel Sambuc *
395*433d6423SLionel Sambuc * When the program flow passes via the assignment bellow it will enter
396*433d6423SLionel Sambuc * the scheduling loop and set is_callback to 1. When the function returns
397*433d6423SLionel Sambuc * because of a setcontext call the program skip the scheduling and return
398*433d6423SLionel Sambuc * from this method to continue normal execution.
399*433d6423SLionel Sambuc */
400*433d6423SLionel Sambuc is_callback =0;
401*433d6423SLionel Sambuc /* save our context */
402*433d6423SLionel Sambuc th->ctx.uc_flags |= _UC_IGNSIGM | _UC_IGNFPU;
403*433d6423SLionel Sambuc if (getcontext(&th->ctx) != 0){
404*433d6423SLionel Sambuc panic("ddekit thread schedule getcontext error");
405*433d6423SLionel Sambuc }
406*433d6423SLionel Sambuc if (is_callback == 0) {
407*433d6423SLionel Sambuc is_callback = 1;
408*433d6423SLionel Sambuc int i;
409*433d6423SLionel Sambuc
410*433d6423SLionel Sambuc /* find a runnable thread */
411*433d6423SLionel Sambuc
412*433d6423SLionel Sambuc current = NULL;
413*433d6423SLionel Sambuc
414*433d6423SLionel Sambuc for (i = DDEKIT_THREAD_PRIOS-1; i >= 0; i--) {
415*433d6423SLionel Sambuc if (ready_queue[i]!=NULL) {
416*433d6423SLionel Sambuc current = ready_queue[i];
417*433d6423SLionel Sambuc ready_queue[i] = current->next;
418*433d6423SLionel Sambuc current->next=NULL;
419*433d6423SLionel Sambuc break;
420*433d6423SLionel Sambuc }
421*433d6423SLionel Sambuc }
422*433d6423SLionel Sambuc
423*433d6423SLionel Sambuc if (current == NULL) {
424*433d6423SLionel Sambuc ddekit_panic("No runnable threads?!");
425*433d6423SLionel Sambuc }
426*433d6423SLionel Sambuc
427*433d6423SLionel Sambuc DDEBUG_MSG_VERBOSE("switching to id: %d name %s, prio: %d",
428*433d6423SLionel Sambuc current->id, current->name, current->prio);
429*433d6423SLionel Sambuc #if DDEBUG >= 4
430*433d6423SLionel Sambuc _ddekit_print_backtrace(current);
431*433d6423SLionel Sambuc #endif
432*433d6423SLionel Sambuc //th->ctx.uc_flags |= _UC_IGNSIGM | _UC_IGNFPU;
433*433d6423SLionel Sambuc if (setcontext(¤t->ctx) == -1){
434*433d6423SLionel Sambuc panic("ddekit threading setcontext error");
435*433d6423SLionel Sambuc }
436*433d6423SLionel Sambuc panic("unreachable code");
437*433d6423SLionel Sambuc }
438*433d6423SLionel Sambuc DDEBUG_MSG_VERBOSE("continuing thread execution id: %d name %s, prio: %d",
439*433d6423SLionel Sambuc current->id, current->name, current->prio);
440*433d6423SLionel Sambuc
441*433d6423SLionel Sambuc }
442*433d6423SLionel Sambuc
443*433d6423SLionel Sambuc /*****************************************************************************
444*433d6423SLionel Sambuc * _ddekit_thread_enqueue *
445*433d6423SLionel Sambuc ****************************************************************************/
_ddekit_thread_enqueue(ddekit_thread_t * th)446*433d6423SLionel Sambuc void _ddekit_thread_enqueue(ddekit_thread_t *th)
447*433d6423SLionel Sambuc {
448*433d6423SLionel Sambuc DDEBUG_MSG_VERBOSE("Enqueuing thread 0x%08X: id %d, name %s, prio %d",
449*433d6423SLionel Sambuc (int)th, th->id, th->name, th->prio);
450*433d6423SLionel Sambuc
451*433d6423SLionel Sambuc #if DDEBUG >= 4
452*433d6423SLionel Sambuc _ddekit_print_backtrace(th);
453*433d6423SLionel Sambuc #endif
454*433d6423SLionel Sambuc
455*433d6423SLionel Sambuc ddekit_assert(th->next==NULL);
456*433d6423SLionel Sambuc
457*433d6423SLionel Sambuc if (ready_queue[th->prio] != NULL) {
458*433d6423SLionel Sambuc ddekit_thread_t *pos = ready_queue[th->prio];
459*433d6423SLionel Sambuc while (pos->next != NULL) {
460*433d6423SLionel Sambuc pos = pos->next;
461*433d6423SLionel Sambuc }
462*433d6423SLionel Sambuc pos->next = th;
463*433d6423SLionel Sambuc } else {
464*433d6423SLionel Sambuc ready_queue[th->prio] = th;
465*433d6423SLionel Sambuc }
466*433d6423SLionel Sambuc }
467*433d6423SLionel Sambuc
468*433d6423SLionel Sambuc /*****************************************************************************
469*433d6423SLionel Sambuc * _ddekit_thread_dequeue *
470*433d6423SLionel Sambuc ****************************************************************************/
471*433d6423SLionel Sambuc void
_ddekit_thread_dequeue(ddekit_thread_t * th)472*433d6423SLionel Sambuc _ddekit_thread_dequeue(ddekit_thread_t * th)
473*433d6423SLionel Sambuc {
474*433d6423SLionel Sambuc ddekit_thread_t * current_thread;
475*433d6423SLionel Sambuc ddekit_thread_t * previous_thread;
476*433d6423SLionel Sambuc
477*433d6423SLionel Sambuc DDEBUG_MSG_VERBOSE("Dequeuing thread 0x%08X: id %d, name %s, prio %d",
478*433d6423SLionel Sambuc (int)th, th->id, th->name, th->prio);
479*433d6423SLionel Sambuc
480*433d6423SLionel Sambuc ddekit_assert((th->prio < DDEKIT_THREAD_PRIOS) && (th->prio >= 0));
481*433d6423SLionel Sambuc
482*433d6423SLionel Sambuc /* Dump queues when debugging */
483*433d6423SLionel Sambuc _ddekit_dump_queues();
484*433d6423SLionel Sambuc
485*433d6423SLionel Sambuc /* Check ready queue (based on thread's priority) for thread */
486*433d6423SLionel Sambuc current_thread = ready_queue[th->prio];
487*433d6423SLionel Sambuc previous_thread = NULL;
488*433d6423SLionel Sambuc
489*433d6423SLionel Sambuc while (NULL != current_thread) {
490*433d6423SLionel Sambuc
491*433d6423SLionel Sambuc /* On match... */
492*433d6423SLionel Sambuc if (th == current_thread) {
493*433d6423SLionel Sambuc
494*433d6423SLionel Sambuc if (previous_thread) {
495*433d6423SLionel Sambuc /* ...fix previous element to remove current */
496*433d6423SLionel Sambuc previous_thread->next = current_thread->next;
497*433d6423SLionel Sambuc } else {
498*433d6423SLionel Sambuc /* ...alter queue start to reflect removal */
499*433d6423SLionel Sambuc ready_queue[th->prio] = current_thread->next;
500*433d6423SLionel Sambuc }
501*433d6423SLionel Sambuc
502*433d6423SLionel Sambuc /* Thread found and dequeued */
503*433d6423SLionel Sambuc DDEBUG_MSG_VERBOSE("Dequeued 'ready[%d]': 0x%08X",
504*433d6423SLionel Sambuc th->prio, (int)th);
505*433d6423SLionel Sambuc return;
506*433d6423SLionel Sambuc }
507*433d6423SLionel Sambuc
508*433d6423SLionel Sambuc /* Next thread */
509*433d6423SLionel Sambuc previous_thread = current_thread;
510*433d6423SLionel Sambuc current_thread = current_thread->next;
511*433d6423SLionel Sambuc }
512*433d6423SLionel Sambuc
513*433d6423SLionel Sambuc /* When previous loop fails, check if thread is sleeping */
514*433d6423SLionel Sambuc current_thread = sleep_queue;
515*433d6423SLionel Sambuc previous_thread = NULL;
516*433d6423SLionel Sambuc
517*433d6423SLionel Sambuc while (NULL != current_thread) {
518*433d6423SLionel Sambuc
519*433d6423SLionel Sambuc /* On match... */
520*433d6423SLionel Sambuc if (th == current_thread) {
521*433d6423SLionel Sambuc
522*433d6423SLionel Sambuc if (previous_thread) {
523*433d6423SLionel Sambuc /* ...fix previous element to remove current */
524*433d6423SLionel Sambuc previous_thread->next = current_thread->next;
525*433d6423SLionel Sambuc } else {
526*433d6423SLionel Sambuc /* ...alter queue start to reflect removal */
527*433d6423SLionel Sambuc sleep_queue = current_thread->next;
528*433d6423SLionel Sambuc }
529*433d6423SLionel Sambuc
530*433d6423SLionel Sambuc /* Thread found and dequeued */
531*433d6423SLionel Sambuc DDEBUG_MSG_VERBOSE("Dequeued 'sleep': 0x%08X", (int)th);
532*433d6423SLionel Sambuc return;
533*433d6423SLionel Sambuc }
534*433d6423SLionel Sambuc
535*433d6423SLionel Sambuc /* Next thread */
536*433d6423SLionel Sambuc previous_thread = current_thread;
537*433d6423SLionel Sambuc current_thread = current_thread->next;
538*433d6423SLionel Sambuc }
539*433d6423SLionel Sambuc
540*433d6423SLionel Sambuc /* Thread may exist and not be enqueued at
541*433d6423SLionel Sambuc * all (is bound to semaphore for instance) */
542*433d6423SLionel Sambuc DDEBUG_MSG_VERBOSE("Thread 0x%08X was not enqueued!", (int)th);
543*433d6423SLionel Sambuc }
544*433d6423SLionel Sambuc
545*433d6423SLionel Sambuc /*****************************************************************************
546*433d6423SLionel Sambuc * _ddekit_thread_set_myprio *
547*433d6423SLionel Sambuc ****************************************************************************/
_ddekit_thread_set_myprio(int prio)548*433d6423SLionel Sambuc void _ddekit_thread_set_myprio(int prio)
549*433d6423SLionel Sambuc {
550*433d6423SLionel Sambuc DDEBUG_MSG_VERBOSE("changing thread prio, id: %d name %s, old prio: %d, "
551*433d6423SLionel Sambuc "new prio: %d", current->id, current->name, current->prio, prio);
552*433d6423SLionel Sambuc
553*433d6423SLionel Sambuc current->prio = prio;
554*433d6423SLionel Sambuc ddekit_thread_schedule();
555*433d6423SLionel Sambuc }
556*433d6423SLionel Sambuc
557*433d6423SLionel Sambuc /*****************************************************************************
558*433d6423SLionel Sambuc * _ddekit_thread_wakeup_sleeping *
559*433d6423SLionel Sambuc ****************************************************************************/
_ddekit_thread_wakeup_sleeping()560*433d6423SLionel Sambuc void _ddekit_thread_wakeup_sleeping()
561*433d6423SLionel Sambuc {
562*433d6423SLionel Sambuc ddekit_thread_t *th = sleep_queue;
563*433d6423SLionel Sambuc
564*433d6423SLionel Sambuc sleep_queue = NULL;
565*433d6423SLionel Sambuc
566*433d6423SLionel Sambuc while (th != NULL) {
567*433d6423SLionel Sambuc ddekit_thread_t *th1 = th->next;
568*433d6423SLionel Sambuc if (th->sleep_until > jiffies) {
569*433d6423SLionel Sambuc th->next = sleep_queue;
570*433d6423SLionel Sambuc sleep_queue = th;
571*433d6423SLionel Sambuc } else {
572*433d6423SLionel Sambuc th->next = NULL;
573*433d6423SLionel Sambuc _ddekit_thread_enqueue(th);
574*433d6423SLionel Sambuc }
575*433d6423SLionel Sambuc th = th1;
576*433d6423SLionel Sambuc }
577*433d6423SLionel Sambuc
578*433d6423SLionel Sambuc ddekit_thread_schedule();
579*433d6423SLionel Sambuc }
580*433d6423SLionel Sambuc
581*433d6423SLionel Sambuc #define FUNC_STACKTRACE(statement) \
582*433d6423SLionel Sambuc { \
583*433d6423SLionel Sambuc reg_t bp, pc, hbp; \
584*433d6423SLionel Sambuc extern reg_t get_bp(void); \
585*433d6423SLionel Sambuc \
586*433d6423SLionel Sambuc bp= get_bp(); \
587*433d6423SLionel Sambuc while(bp) \
588*433d6423SLionel Sambuc { \
589*433d6423SLionel Sambuc pc= ((reg_t *)bp)[1]; \
590*433d6423SLionel Sambuc hbp= ((reg_t *)bp)[0]; \
591*433d6423SLionel Sambuc statement; \
592*433d6423SLionel Sambuc if (hbp != 0 && hbp <= bp) \
593*433d6423SLionel Sambuc { \
594*433d6423SLionel Sambuc pc = -1; \
595*433d6423SLionel Sambuc statement; \
596*433d6423SLionel Sambuc break; \
597*433d6423SLionel Sambuc } \
598*433d6423SLionel Sambuc bp= hbp; \
599*433d6423SLionel Sambuc } \
600*433d6423SLionel Sambuc }
601*433d6423SLionel Sambuc
602*433d6423SLionel Sambuc /*****************************************************************************
603*433d6423SLionel Sambuc * _ddekit_print_backtrace *
604*433d6423SLionel Sambuc ****************************************************************************/
_ddekit_print_backtrace(ddekit_thread_t * th)605*433d6423SLionel Sambuc void _ddekit_print_backtrace(ddekit_thread_t *th)
606*433d6423SLionel Sambuc {
607*433d6423SLionel Sambuc #if defined(__i386)
608*433d6423SLionel Sambuc unsigned long bp, pc, hbp;
609*433d6423SLionel Sambuc
610*433d6423SLionel Sambuc ddekit_printf("%s: ", th->name);
611*433d6423SLionel Sambuc
612*433d6423SLionel Sambuc bp = th->ctx.uc_mcontext.__gregs[_REG_EBP];
613*433d6423SLionel Sambuc while (bp) {
614*433d6423SLionel Sambuc pc = ((unsigned long *)bp)[1];
615*433d6423SLionel Sambuc hbp = ((unsigned long *)bp)[0];
616*433d6423SLionel Sambuc
617*433d6423SLionel Sambuc ddekit_printf("0x%lx ", (unsigned long) pc);
618*433d6423SLionel Sambuc
619*433d6423SLionel Sambuc if (hbp != 0 && hbp <= bp) {
620*433d6423SLionel Sambuc pc = -1;
621*433d6423SLionel Sambuc ddekit_printf("0x%lx ", (unsigned long) pc);
622*433d6423SLionel Sambuc break;
623*433d6423SLionel Sambuc }
624*433d6423SLionel Sambuc bp= hbp;
625*433d6423SLionel Sambuc }
626*433d6423SLionel Sambuc
627*433d6423SLionel Sambuc ddekit_printf("\n");
628*433d6423SLionel Sambuc #endif
629*433d6423SLionel Sambuc }
630