diff options
Diffstat (limited to 'qt/stp.c')
-rw-r--r-- | qt/stp.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/qt/stp.c b/qt/stp.c new file mode 100644 index 000000000..bfacc893b --- /dev/null +++ b/qt/stp.c @@ -0,0 +1,199 @@ +#include "copyright.h" +#include "qt.h" +#include "stp.h" + +#ifndef NULL +#define NULL 0 +#endif + +#define STP_STKSIZE (0x1000) + +/* `alignment' must be a power of 2. */ +#define STP_STKALIGN(sp, alignment) \ + ((void *)((((qt_word_t)(sp)) + (alignment) - 1) & ~((alignment)-1))) + + +/* The notion of a thread is merged with the notion of a queue. + Thread stuff: thread status (sp) and stuff to use during + (re)initialization. Queue stuff: next thread in the queue + (next). */ + +struct stp_t { + qt_t *sp; /* QuickThreads handle. */ + void *sto; /* `malloc'-allocated stack. */ + struct stp_t *next; /* Next thread in the queue. */ +}; + + +/* A queue is a circular list of threads. The queue head is a + designated list element. If this is a uniprocessor-only + implementation we can store the `main' thread in this, but in a + multiprocessor there are several `heavy' threads but only one run + queue. A fancier implementation might have private run queues, + which would lead to a simpler (trivial) implementation */ + +typedef struct stp_q_t { + stp_t t; + stp_t *tail; +} stp_q_t; + + +/* Helper functions. */ + +extern void *malloc (unsigned size); +extern void perror (char const *msg); +extern void free (void *sto); + + void * +xmalloc (unsigned size) +{ + void *sto; + + sto = malloc (size); + if (!sto) { + perror ("malloc"); + exit (1); + } + return (sto); +} + +/* Queue access functions. */ + + static void +stp_qinit (stp_q_t *q) +{ + q->t.next = q->tail = &q->t; +} + + + static stp_t * +stp_qget (stp_q_t *q) +{ + stp_t *t; + + t = q->t.next; + q->t.next = t->next; + if (t->next == &q->t) { + if (t == &q->t) { /* If it was already empty .. */ + return (NULL); /* .. say so. */ + } + q->tail = &q->t; /* Else now it is empty. */ + } + return (t); +} + + + static void +stp_qput (stp_q_t *q, stp_t *t) +{ + q->tail->next = t; + t->next = &q->t; + q->tail = t; +} + + +/* Thread routines. */ + +static stp_q_t stp_global_runq; /* A queue of runable threads. */ +static stp_t stp_global_main; /* Thread for the process. */ +static stp_t *stp_global_curr; /* Currently-executing thread. */ + +static void *stp_starthelp (qt_t *old, void *ignore0, void *ignore1); +static void stp_only (void *pu, void *pt, qt_userf_t *f); +static void *stp_aborthelp (qt_t *sp, void *old, void *null); +static void *stp_yieldhelp (qt_t *sp, void *old, void *blockq); + + + void +stp_init() +{ + stp_qinit (&stp_global_runq); +} + + + void +stp_start() +{ + stp_t *next; + + while ((next = stp_qget (&stp_global_runq)) != NULL) { + stp_global_curr = next; + QT_BLOCK (stp_starthelp, 0, 0, next->sp); + } +} + + + static void * +stp_starthelp (qt_t *old, void *ignore0, void *ignore1) +{ + stp_global_main.sp = old; + stp_qput (&stp_global_runq, &stp_global_main); + /* return (garbage); */ +} + + + void +stp_create (stp_userf_t *f, void *pu) +{ + stp_t *t; + void *sto; + + t = xmalloc (sizeof(stp_t)); + t->sto = xmalloc (STP_STKSIZE); + sto = STP_STKALIGN (t->sto, QT_STKALIGN); + t->sp = QT_SP (sto, STP_STKSIZE - QT_STKALIGN); + t->sp = QT_ARGS (t->sp, pu, t, (qt_userf_t *)f, stp_only); + stp_qput (&stp_global_runq, t); +} + + + static void +stp_only (void *pu, void *pt, qt_userf_t *f) +{ + stp_global_curr = (stp_t *)pt; + (*(stp_userf_t *)f)(pu); + stp_abort(); + /* NOTREACHED */ +} + + + void +stp_abort (void) +{ + stp_t *old, *newthread; + + newthread = stp_qget (&stp_global_runq); + old = stp_global_curr; + stp_global_curr = newthread; + QT_ABORT (stp_aborthelp, old, (void *)NULL, newthread->sp); +} + + + static void * +stp_aborthelp (qt_t *sp, void *old, void *null) +{ + free (((stp_t *)old)->sto); + free (old); + /* return (garbage); */ +} + + + void +stp_yield() +{ + stp_t *old, *newthread; + + newthread = stp_qget (&stp_global_runq); + old = stp_global_curr; + stp_global_curr = newthread; + QT_BLOCK (stp_yieldhelp, old, &stp_global_runq, newthread->sp); +} + + + static void * +stp_yieldhelp (qt_t *sp, void *old, void *blockq) +{ + ((stp_t *)old)->sp = sp; + stp_qput ((stp_q_t *)blockq, (stp_t *)old); + /* return (garbage); */ +} |