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/timer.h>
#ifdef DDEBUG_LEVEL_THREAD
#undef DDEBUG
#define DDEBUG DDEBUG_LEVEL_THREAD
#endif
//#define DDEBUG DDEBUG_VERBOSE
#include "debug.h"
#include "util.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 *) ddekit_simple_malloc(sizeof(ddekit_thread_t));
memset(th,0,sizeof(ddekit_thread_t));
strncpy(th->name, name, DDEKIT_THREAD_NAMELEN);
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->sleep_sem = ddekit_sem_init(0);
/* setup stack */
void **ptr = (void **)(th->stack + DDEKIT_THREAD_STACKSIZE);
*(--ptr) = th;
--ptr;
--ptr;
/* 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__ */
/* Setup thread context */
th->ctx.uc_flags |= _UC_IGNSIGM | _UC_IGNFPU;
if (getcontext(&th->ctx) != 0) {
panic("ddekit thread create thread getcontext error");
}
th->ctx.uc_stack.ss_sp = th->stack;/* makecontext will determine sp */
th->ctx.uc_stack.ss_size = DDEKIT_THREAD_STACKSIZE;
makecontext(&th->ctx,_ddekit_thread_start,1 /* argc */,th /* pass thread as argument */);
DDEBUG_MSG_VERBOSE("created thread %s, stack at: %p\n", name,
th->stack + DDEKIT_THREAD_STACKSIZE);
_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 *th =
(ddekit_thread_t *) ddekit_simple_malloc(sizeof(ddekit_thread_t));
memset(th,0,sizeof(ddekit_thread_t));
strncpy(th->name, name, DDEKIT_THREAD_NAMELEN);
th->name[DDEKIT_THREAD_NAMELEN-1] = 0;
th->stack = NULL;
@ -341,14 +326,30 @@ void _ddekit_thread_schedule()
/* get our tcb */
ddekit_thread_t * th = current;
volatile int is_callback;
#if DDEBUG >= 4
_ddekit_print_backtrace(th);
#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 */
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;
/* find a runnable thread */
@ -365,7 +366,7 @@ void _ddekit_thread_schedule()
}
if (current == NULL) {
ddekit_panic("No runable threads?!");
ddekit_panic("No runnable threads?!");
}
DDEBUG_MSG_VERBOSE("switching to id: %d name %s, prio: %d",
@ -373,8 +374,14 @@ void _ddekit_thread_schedule()
#if DDEBUG >= 4
_ddekit_print_backtrace(current);
#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)
{
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;
ddekit_thread_schedule();
@ -466,22 +473,12 @@ void _ddekit_thread_wakeup_sleeping()
****************************************************************************/
void _ddekit_print_backtrace(ddekit_thread_t *th)
{
#if defined(__i386)
unsigned long bp, pc, hbp;
ddekit_printf("%s: ", th->name);
#ifdef __ACK__
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__ */
bp = th->ctx.uc_mcontext.__gregs[_REG_EBP];
while (bp) {
pc = ((unsigned long *)bp)[1];
hbp = ((unsigned long *)bp)[0];
@ -494,6 +491,8 @@ void _ddekit_print_backtrace(ddekit_thread_t *th)
break;
}
bp= hbp;
}
}
ddekit_printf("\n");
#endif
}

View file

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