ddekit:use ucontext to switch threads

Use getcontext/makecontext and setcontext to create/modify and
switch thread when using ddekit.

Change-Id: I485ad61cb2eb5b8e7b486775f282ff6501912dfd
This commit is contained in:
Kees Jongenburger 2014-03-24 16:55:57 +01:00 committed by Lionel Sambuc
parent 4dafcd9245
commit 1035348df8
2 changed files with 48 additions and 49 deletions

View file

@ -5,11 +5,14 @@
#include <ddekit/panic.h> #include <ddekit/panic.h>
#include <ddekit/timer.h> #include <ddekit/timer.h>
#ifdef DDEBUG_LEVEL_THREAD #ifdef DDEBUG_LEVEL_THREAD
#undef DDEBUG #undef DDEBUG
#define DDEBUG DDEBUG_LEVEL_THREAD #define DDEBUG DDEBUG_LEVEL_THREAD
#endif #endif
//#define DDEBUG DDEBUG_VERBOSE
#include "debug.h" #include "debug.h"
#include "util.h" #include "util.h"
#include "thread.h" #include "thread.h"
@ -80,7 +83,7 @@ ddekit_thread_create(void (*fun)(void *), void *arg, const char *name)
{ {
ddekit_thread_t *th = ddekit_thread_t *th =
(ddekit_thread_t *) ddekit_simple_malloc(sizeof(ddekit_thread_t)); (ddekit_thread_t *) ddekit_simple_malloc(sizeof(ddekit_thread_t));
memset(th,0,sizeof(ddekit_thread_t));
strncpy(th->name, name, DDEKIT_THREAD_NAMELEN); strncpy(th->name, name, DDEKIT_THREAD_NAMELEN);
th->name[DDEKIT_THREAD_NAMELEN-1] = 0; th->name[DDEKIT_THREAD_NAMELEN-1] = 0;
@ -94,32 +97,14 @@ ddekit_thread_create(void (*fun)(void *), void *arg, const char *name)
th->next = NULL; th->next = NULL;
th->sleep_sem = ddekit_sem_init(0); th->sleep_sem = ddekit_sem_init(0);
/* Setup thread context */
/* setup stack */ th->ctx.uc_flags |= _UC_IGNSIGM | _UC_IGNFPU;
if (getcontext(&th->ctx) != 0) {
void **ptr = (void **)(th->stack + DDEKIT_THREAD_STACKSIZE); panic("ddekit thread create thread getcontext error");
*(--ptr) = th; }
--ptr; th->ctx.uc_stack.ss_sp = th->stack;/* makecontext will determine sp */
--ptr; th->ctx.uc_stack.ss_size = DDEKIT_THREAD_STACKSIZE;
makecontext(&th->ctx,_ddekit_thread_start,1 /* argc */,th /* pass thread as argument */);
/* TAKEN FROM P_THREAD (written by david?)*/
#ifdef __ACK__
th->jb[0].__pc = _ddekit_thread_start;
th->jb[0].__sp = ptr;
#else /* !__ACK__ */
#include <sys/jmp_buf.h>
#if defined(JB_PC) && defined(JB_SP)
/* um, yikes. */
*((void (**)(void))(&((char *)th->jb)[JB_PC])) =
(void *)_ddekit_thread_start;
*((void **)(&((char *)th->jb)[JB_SP])) = ptr;
#else
#error "Unsupported Minix architecture"
#endif
#endif /* !__ACK__ */
DDEBUG_MSG_VERBOSE("created thread %s, stack at: %p\n", name, DDEBUG_MSG_VERBOSE("created thread %s, stack at: %p\n", name,
th->stack + DDEKIT_THREAD_STACKSIZE); th->stack + DDEKIT_THREAD_STACKSIZE);
_ddekit_thread_enqueue(th); _ddekit_thread_enqueue(th);
@ -159,7 +144,7 @@ ddekit_thread_t *ddekit_thread_myself(void)
ddekit_thread_t *ddekit_thread_setup_myself(const char *name) { ddekit_thread_t *ddekit_thread_setup_myself(const char *name) {
ddekit_thread_t *th = ddekit_thread_t *th =
(ddekit_thread_t *) ddekit_simple_malloc(sizeof(ddekit_thread_t)); (ddekit_thread_t *) ddekit_simple_malloc(sizeof(ddekit_thread_t));
memset(th,0,sizeof(ddekit_thread_t));
strncpy(th->name, name, DDEKIT_THREAD_NAMELEN); strncpy(th->name, name, DDEKIT_THREAD_NAMELEN);
th->name[DDEKIT_THREAD_NAMELEN-1] = 0; th->name[DDEKIT_THREAD_NAMELEN-1] = 0;
th->stack = NULL; th->stack = NULL;
@ -341,14 +326,30 @@ void _ddekit_thread_schedule()
/* get our tcb */ /* get our tcb */
ddekit_thread_t * th = current; ddekit_thread_t * th = current;
volatile int is_callback;
#if DDEBUG >= 4 #if DDEBUG >= 4
_ddekit_print_backtrace(th); _ddekit_print_backtrace(th);
#endif #endif
/* getcontext saves the current context in ctx. When setcontext is called
* with that ctx it will return execution at getcontext here. To
* discriminate between the initial call to getcontext that simply returns
* and the situation where getcontext returns because of a setcontext call
* we use the is_callback variable.
*
* When the program flow passes via the assignment bellow it will enter
* the scheduling loop and set is_callback to 1. When the function returns
* because of a setcontext call the program skip the scheduling and return
* from this method to continue normal execution.
*/
is_callback =0;
/* save our context */ /* save our context */
if (_setjmp(th->jb) == 0) { th->ctx.uc_flags |= _UC_IGNSIGM | _UC_IGNFPU;
if (getcontext(&th->ctx) != 0){
panic("ddekit thread schedule getcontext error");
}
if (is_callback == 0) {
is_callback = 1;
int i; int i;
/* find a runnable thread */ /* find a runnable thread */
@ -365,7 +366,7 @@ void _ddekit_thread_schedule()
} }
if (current == NULL) { if (current == NULL) {
ddekit_panic("No runable threads?!"); ddekit_panic("No runnable threads?!");
} }
DDEBUG_MSG_VERBOSE("switching to id: %d name %s, prio: %d", DDEBUG_MSG_VERBOSE("switching to id: %d name %s, prio: %d",
@ -373,8 +374,14 @@ void _ddekit_thread_schedule()
#if DDEBUG >= 4 #if DDEBUG >= 4
_ddekit_print_backtrace(current); _ddekit_print_backtrace(current);
#endif #endif
_longjmp(current->jb, 1); //th->ctx.uc_flags |= _UC_IGNSIGM | _UC_IGNFPU;
if (setcontext(&current->ctx) == -1){
panic("ddekit threading setcontext error");
}
panic("unreachable code");
} }
DDEBUG_MSG_VERBOSE("continuing thread execution id: %d name %s, prio: %d",
current->id, current->name, current->prio);
} }
@ -410,7 +417,7 @@ void _ddekit_thread_enqueue(ddekit_thread_t *th)
void _ddekit_thread_set_myprio(int prio) void _ddekit_thread_set_myprio(int prio)
{ {
DDEBUG_MSG_VERBOSE("changing thread prio, id: %d name %s, old prio: %d, " DDEBUG_MSG_VERBOSE("changing thread prio, id: %d name %s, old prio: %d, "
"new prio: %d", current->id, current->name, current->prio); "new prio: %d", current->id, current->name, current->prio, prio);
current->prio = prio; current->prio = prio;
ddekit_thread_schedule(); ddekit_thread_schedule();
@ -466,22 +473,12 @@ void _ddekit_thread_wakeup_sleeping()
****************************************************************************/ ****************************************************************************/
void _ddekit_print_backtrace(ddekit_thread_t *th) void _ddekit_print_backtrace(ddekit_thread_t *th)
{ {
#if defined(__i386)
unsigned long bp, pc, hbp; unsigned long bp, pc, hbp;
ddekit_printf("%s: ", th->name); ddekit_printf("%s: ", th->name);
#ifdef __ACK__ bp = th->ctx.uc_mcontext.__gregs[_REG_EBP];
bp =th->jb[0].__bp;
#else /* !__ACK__ */
#include <sys/jmp_buf.h>
#if defined(JB_BP)
/* um, yikes. */
bp = (unsigned long) *((void **)(&((char *)th->jb)[JB_BP]));
#else
#error "Unsupported Minix architecture"
#endif
#endif /* !__ACK__ */
while (bp) { while (bp) {
pc = ((unsigned long *)bp)[1]; pc = ((unsigned long *)bp)[1];
hbp = ((unsigned long *)bp)[0]; hbp = ((unsigned long *)bp)[0];
@ -494,6 +491,8 @@ void _ddekit_print_backtrace(ddekit_thread_t *th)
break; break;
} }
bp= hbp; bp= hbp;
} }
ddekit_printf("\n"); ddekit_printf("\n");
#endif
} }

View file

@ -2,7 +2,7 @@
#define DDEKIT_SRC_THREAD_H 1 #define DDEKIT_SRC_THREAD_H 1
#include <ddekit/thread.h> #include <ddekit/thread.h>
#include <ddekit/semaphore.h> #include <ddekit/semaphore.h>
#include <setjmp.h> #include <ucontext.h>
#define DDEKIT_THREAD_NAMELEN 32 #define DDEKIT_THREAD_NAMELEN 32
#define DDEKIT_THREAD_PRIOS 3 #define DDEKIT_THREAD_PRIOS 3
@ -26,7 +26,7 @@ struct ddekit_thread {
void *data; void *data;
unsigned sleep_until; unsigned sleep_until;
char name[DDEKIT_THREAD_NAMELEN]; char name[DDEKIT_THREAD_NAMELEN];
jmp_buf jb; ucontext_t ctx;
ddekit_sem_t *sleep_sem; ddekit_sem_t *sleep_sem;
struct ddekit_thread * next; struct ddekit_thread * next;
}; };