499 lines
14 KiB
C
499 lines
14 KiB
C
#include "common.h"
|
|
#include <ddekit/assert.h>
|
|
#include <ddekit/condvar.h>
|
|
#include <ddekit/memory.h>
|
|
#include <ddekit/panic.h>
|
|
#include <ddekit/timer.h>
|
|
|
|
#ifdef DDEBUG_LEVEL_THREAD
|
|
#undef DDEBUG
|
|
#define DDEBUG DDEBUG_LEVEL_THREAD
|
|
#endif
|
|
|
|
#include "debug.h"
|
|
#include "util.h"
|
|
#include "thread.h"
|
|
#include "timer.h"
|
|
|
|
|
|
/* Incremented to generate unique thread IDs */
|
|
static unsigned id;
|
|
|
|
static ddekit_thread_t *ready_queue[DDEKIT_THREAD_PRIOS];
|
|
|
|
static ddekit_thread_t *sleep_queue;
|
|
|
|
/* Handle to the running thread, set in _dde_kit_thread_schedule() */
|
|
static ddekit_thread_t *current = NULL;
|
|
|
|
static void _ddekit_thread_start(ddekit_thread_t *th);
|
|
static void _ddekit_thread_sleep(unsigned long until);
|
|
|
|
/*****************************************************************************
|
|
* _ddekit_thread_start *
|
|
****************************************************************************/
|
|
static void _ddekit_thread_start(ddekit_thread_t *th)
|
|
{
|
|
/* entry point of newly created threads */
|
|
th->fun(th->arg);
|
|
ddekit_thread_exit();
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* _ddekit_thread_sleep *
|
|
****************************************************************************/
|
|
static void _ddekit_thread_sleep(unsigned long until)
|
|
{
|
|
current->next = sleep_queue;
|
|
sleep_queue = current;
|
|
current->sleep_until = until;
|
|
_ddekit_thread_schedule();
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DDEKIT public thread API (ddekit/thread.h) *
|
|
****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* ddekit_yield *
|
|
****************************************************************************/
|
|
void ddekit_yield()
|
|
{
|
|
ddekit_thread_schedule();
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_thread_schedule *
|
|
****************************************************************************/
|
|
void ddekit_thread_schedule()
|
|
{
|
|
_ddekit_thread_enqueue(current);
|
|
_ddekit_thread_schedule();
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_thread_create *
|
|
****************************************************************************/
|
|
ddekit_thread_t *
|
|
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));
|
|
|
|
strncpy(th->name, name, DDEKIT_THREAD_NAMELEN);
|
|
th->name[DDEKIT_THREAD_NAMELEN-1] = 0;
|
|
|
|
th->stack = ddekit_large_malloc(DDEKIT_THREAD_STACKSIZE);
|
|
|
|
th->arg = arg;
|
|
th->fun = fun;
|
|
|
|
th->id = id++;
|
|
th->prio = DDEKIT_THREAD_STDPRIO;
|
|
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__ */
|
|
|
|
DDEBUG_MSG_VERBOSE("created thread %s, stack at: %p\n", name,
|
|
th->stack + DDEKIT_THREAD_STACKSIZE);
|
|
_ddekit_thread_enqueue(th);
|
|
|
|
return th;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_thread_get_data *
|
|
****************************************************************************/
|
|
void *ddekit_thread_get_data(ddekit_thread_t *thread)
|
|
{
|
|
return thread->data;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_thread_get_my_data *
|
|
****************************************************************************/
|
|
void *ddekit_thread_get_my_data(void)
|
|
{
|
|
return current->data;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_thread_myself *
|
|
****************************************************************************/
|
|
|
|
ddekit_thread_t *ddekit_thread_myself(void)
|
|
{
|
|
return current;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_thread_setup_myself *
|
|
****************************************************************************/
|
|
|
|
ddekit_thread_t *ddekit_thread_setup_myself(const char *name) {
|
|
ddekit_thread_t *th =
|
|
(ddekit_thread_t *) ddekit_simple_malloc(sizeof(ddekit_thread_t));
|
|
|
|
strncpy(th->name, name, DDEKIT_THREAD_NAMELEN);
|
|
th->name[DDEKIT_THREAD_NAMELEN-1] = 0;
|
|
th->stack = NULL;
|
|
th->next = NULL;
|
|
th->id = id++;
|
|
th->prio = DDEKIT_THREAD_STDPRIO;
|
|
th->sleep_sem = ddekit_sem_init(0);
|
|
#if DDEBUG >= 4
|
|
_ddekit_print_backtrace(th);
|
|
#endif
|
|
return th;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_thread_set_data *
|
|
****************************************************************************/
|
|
void ddekit_thread_set_data(ddekit_thread_t *thread, void *data)
|
|
{
|
|
thread->data=data;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_thread_set_my_data *
|
|
****************************************************************************/
|
|
void ddekit_thread_set_my_data(void *data)
|
|
{
|
|
current->data = data;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_thread_usleep *
|
|
****************************************************************************/
|
|
void ddekit_thread_usleep(unsigned long usecs)
|
|
{
|
|
/*
|
|
* Cannot use usleep here, because it's implemented in vfs.
|
|
* Assuming the anyway no finder granularity than system's HZ value
|
|
* can be reached. So we use dde_kit_thread_msleep for now.
|
|
*/
|
|
|
|
/* If no timeout is 0 return immediately */
|
|
if (usecs == 0)
|
|
return;
|
|
|
|
unsigned long to = usecs/1000;
|
|
|
|
/* round up to to possible granularity */
|
|
|
|
if (to == 0)
|
|
to = 1;
|
|
|
|
ddekit_thread_msleep(to);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_thread_nsleep *
|
|
****************************************************************************/
|
|
void ddekit_thread_nsleep(unsigned long nsecs)
|
|
{
|
|
/*
|
|
* Cannot use usleep here, because it's implemented in vfs.
|
|
* Assuming the anyway no finder granularity than system's HZ value
|
|
* can be reached. So we use dde_kit_thread_msleep.
|
|
*/
|
|
|
|
/* If no timeout is 0 return immediately */
|
|
if (nsecs == 0)
|
|
return;
|
|
|
|
unsigned long to = nsecs/1000;
|
|
|
|
/* round up to to possible granularity */
|
|
|
|
if (to == 0)
|
|
to = 1;
|
|
|
|
ddekit_thread_usleep(to);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_thread_msleep *
|
|
****************************************************************************/
|
|
void ddekit_thread_msleep(unsigned long msecs)
|
|
{
|
|
unsigned long to;
|
|
|
|
to = (msecs*HZ/1000);
|
|
|
|
if (to == 0) {
|
|
to = 1;
|
|
}
|
|
|
|
ddekit_thread_t *th = ddekit_thread_myself();
|
|
|
|
if (th == NULL) {
|
|
ddekit_panic("th==NULL!");
|
|
}
|
|
|
|
if (th->sleep_sem == NULL) {
|
|
ddekit_panic("th->sleepsem==NULL! %p %s ", th, th->name);
|
|
}
|
|
|
|
/* generate a timer interrupt at to */
|
|
ddekit_add_timer(NULL, NULL, to+jiffies);
|
|
_ddekit_thread_sleep(to+jiffies);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_thread_sleep *
|
|
****************************************************************************/
|
|
void ddekit_thread_sleep(ddekit_lock_t *lock)
|
|
{
|
|
WARN_UNIMPL;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_thread_exit *
|
|
****************************************************************************/
|
|
void ddekit_thread_exit()
|
|
{
|
|
ddekit_sem_down(current->sleep_sem);
|
|
ddekit_panic("thread running after exit!\n");
|
|
/* not reached */
|
|
while(1);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_thread_terminate *
|
|
****************************************************************************/
|
|
void ddekit_thread_terminate(ddekit_thread_t *thread)
|
|
{
|
|
/* todo */
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_thread_get_name *
|
|
****************************************************************************/
|
|
const char *ddekit_thread_get_name(ddekit_thread_t *thread)
|
|
{
|
|
return thread->name;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_thread_get_id *
|
|
****************************************************************************/
|
|
int ddekit_thread_get_id(ddekit_thread_t *thread)
|
|
{
|
|
return thread->id;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* ddekit_init_threads *
|
|
****************************************************************************/
|
|
void ddekit_init_threads(void)
|
|
{
|
|
int i;
|
|
|
|
for (i =0 ; i < DDEKIT_THREAD_PRIOS ; i++) {
|
|
ready_queue[i] = NULL;
|
|
}
|
|
|
|
current = ddekit_thread_setup_myself("main");
|
|
|
|
DDEBUG_MSG_INFO("ddekit thread subsystem initialized");
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* DDEKIT internals (src/thread.h) *
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* _ddekit_thread_schedule *
|
|
****************************************************************************/
|
|
void _ddekit_thread_schedule()
|
|
{
|
|
|
|
DDEBUG_MSG_VERBOSE("called schedule id: %d name %s, prio: %d",
|
|
current->id, current->name, current->prio);
|
|
|
|
/* get our tcb */
|
|
ddekit_thread_t * th = current;
|
|
|
|
#if DDEBUG >= 4
|
|
_ddekit_print_backtrace(th);
|
|
#endif
|
|
|
|
/* save our context */
|
|
if (_setjmp(th->jb) == 0) {
|
|
|
|
int i;
|
|
|
|
/* find a runnable thread */
|
|
|
|
current = NULL;
|
|
|
|
for (i = DDEKIT_THREAD_PRIOS-1; i >= 0; i--) {
|
|
if (ready_queue[i]!=NULL) {
|
|
current = ready_queue[i];
|
|
ready_queue[i] = current->next;
|
|
current->next=NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (current == NULL) {
|
|
ddekit_panic("No runable threads?!");
|
|
}
|
|
|
|
DDEBUG_MSG_VERBOSE("switching to id: %d name %s, prio: %d",
|
|
current->id, current->name, current->prio);
|
|
#if DDEBUG >= 4
|
|
_ddekit_print_backtrace(current);
|
|
#endif
|
|
_longjmp(current->jb, 1);
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* _ddekit_thread_enqueue *
|
|
****************************************************************************/
|
|
void _ddekit_thread_enqueue(ddekit_thread_t *th)
|
|
{
|
|
|
|
DDEBUG_MSG_VERBOSE("enqueueing thread: id: %d name %s, prio: %d",
|
|
th->id, th->name, th->prio);
|
|
|
|
#if DDEBUG >= 4
|
|
_ddekit_print_backtrace(th);
|
|
#endif
|
|
|
|
ddekit_assert(th->next==NULL);
|
|
|
|
if (ready_queue[th->prio] != NULL) {
|
|
ddekit_thread_t *pos = ready_queue[th->prio];
|
|
while (pos->next != NULL) {
|
|
pos = pos->next;
|
|
}
|
|
pos->next = th;
|
|
} else {
|
|
ready_queue[th->prio] = th;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* _ddekit_thread_set_myprio *
|
|
****************************************************************************/
|
|
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);
|
|
|
|
current->prio = prio;
|
|
ddekit_thread_schedule();
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* _ddekit_thread_wakeup_sleeping *
|
|
****************************************************************************/
|
|
void _ddekit_thread_wakeup_sleeping()
|
|
{
|
|
ddekit_thread_t *th = sleep_queue;
|
|
|
|
sleep_queue = NULL;
|
|
|
|
while (th != NULL) {
|
|
ddekit_thread_t *th1 = th->next;
|
|
if (th->sleep_until > jiffies) {
|
|
th->next = sleep_queue;
|
|
sleep_queue = th;
|
|
} else {
|
|
th->next = NULL;
|
|
_ddekit_thread_enqueue(th);
|
|
}
|
|
th = th1;
|
|
}
|
|
|
|
ddekit_thread_schedule();
|
|
}
|
|
|
|
#define FUNC_STACKTRACE(statement) \
|
|
{ \
|
|
reg_t bp, pc, hbp; \
|
|
extern reg_t get_bp(void); \
|
|
\
|
|
bp= get_bp(); \
|
|
while(bp) \
|
|
{ \
|
|
pc= ((reg_t *)bp)[1]; \
|
|
hbp= ((reg_t *)bp)[0]; \
|
|
statement; \
|
|
if (hbp != 0 && hbp <= bp) \
|
|
{ \
|
|
pc = -1; \
|
|
statement; \
|
|
break; \
|
|
} \
|
|
bp= hbp; \
|
|
} \
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* _ddekit_print_backtrace *
|
|
****************************************************************************/
|
|
void _ddekit_print_backtrace(ddekit_thread_t *th)
|
|
{
|
|
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__ */
|
|
|
|
while (bp) {
|
|
pc = ((unsigned long *)bp)[1];
|
|
hbp = ((unsigned long *)bp)[0];
|
|
|
|
ddekit_printf("0x%lx ", (unsigned long) pc);
|
|
|
|
if (hbp != 0 && hbp <= bp) {
|
|
pc = -1;
|
|
ddekit_printf("0x%lx ", (unsigned long) pc);
|
|
break;
|
|
}
|
|
bp= hbp;
|
|
}
|
|
ddekit_printf("\n");
|
|
}
|