thread.c
上传用户:shmaik
上传日期:2014-06-01
资源大小:45093k
文件大小:7k
- static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/thread.doc,v 1.11 1997/02/21 19:50:51 drh Exp $";
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include </usr/include/signal.h>
- #include <sys/time.h>
- #include "assert.h"
- #include "mem.h"
- #include "thread.h"
- #include "sem.h"
- void _MONITOR(void) {}
- extern void _ENDMONITOR(void);
- #define T Thread_T
- #define isempty(q) ((q) == NULL)
- struct T {
- unsigned long *sp; /* must be first */
- T link;
- T *inqueue;
- T handle;
- Except_Frame *estack;
- int code;
- T join;
- T next;
- int alerted;
- };
- static T ready = NULL;
- static T current;
- static int nthreads;
- static struct Thread_T root;
- static T join0;
- static T freelist;
- const Except_T Thread_Alerted = { "Thread alerted" };
- const Except_T Thread_Failed =
- { "Thread creation failed" };
- static int critical;
- extern void _swtch(T from, T to);
- static void put(T t, T *q) {
- assert(t);
- assert(t->inqueue == NULL && t->link == NULL);
- if (*q) {
- t->link = (*q)->link;
- (*q)->link = t;
- } else
- t->link = t;
- *q = t;
- t->inqueue = q;
- }
- static T get(T *q) {
- T t;
- assert(!isempty(*q));
- t = (*q)->link;
- if (t == *q)
- *q = NULL;
- else
- (*q)->link = t->link;
- assert(t->inqueue == q);
- t->link = NULL;
- t->inqueue = NULL;
- return t;
- }
- static void delete(T t, T *q) {
- T p;
- assert(t->link && t->inqueue == q);
- assert(!isempty(*q));
- for (p = *q; p->link != t; p = p->link)
- ;
- if (p == t)
- *q = NULL;
- else {
- p->link = t->link;
- if (*q == t)
- *q = p;
- }
- t->link = NULL;
- t->inqueue = NULL;
- }
- static void run(void) {
- T t = current;
- current = get(&ready);
- t->estack = Except_stack;
- Except_stack = current->estack;
- _swtch(t, current);
- }
- static void testalert(void) {
- if (current->alerted) {
- current->alerted = 0;
- RAISE(Thread_Alerted);
- }
- }
- static void release(void) {
- T t;
- do { critical++;
- while ((t = freelist) != NULL) {
- freelist = t->next;
- FREE(t);
- }
- critical--; } while (0);
- }
- #if linux
- #include <asm/sigcontext.h>
- static int interrupt(int sig, struct sigcontext_struct sc) {
- if (critical ||
- sc.eip >= (unsigned long)_MONITOR
- && sc.eip <= (unsigned long)_ENDMONITOR)
- return 0;
- put(current, &ready);
- do { critical++;
- sigsetmask(sc.oldmask);
- critical--; } while (0);
- run();
- return 0;
- }
- #else
- static int interrupt(int sig, int code,
- struct sigcontext *scp) {
- if (critical ||
- scp->sc_pc >= (unsigned long)_MONITOR
- && scp->sc_pc <= (unsigned long)_ENDMONITOR)
- return 0;
- put(current, &ready);
- sigsetmask(scp->sc_mask);
- run();
- return 0;
- }
- #endif
- int Thread_init(int preempt, ...) {
- assert(preempt == 0 || preempt == 1);
- assert(current == NULL);
- root.handle = &root;
- current = &root;
- nthreads = 1;
- if (preempt) {
- {
- struct sigaction sa;
- memset(&sa, ' ', sizeof sa);
- sa.sa_handler = (void (*)())interrupt;
- if (sigaction(SIGVTALRM, &sa, NULL) < 0)
- return 0;
- }
- {
- struct itimerval it;
- it.it_value.tv_sec = 0;
- it.it_value.tv_usec = 50;
- it.it_interval.tv_sec = 0;
- it.it_interval.tv_usec = 50;
- if (setitimer(ITIMER_VIRTUAL, &it, NULL) < 0)
- return 0;
- }
- }
- return 1;
- }
- T Thread_self(void) {
- assert(current);
- return current;
- }
- void Thread_pause(void) {
- assert(current);
- put(current, &ready);
- run();
- }
- int Thread_join(T t) {
- assert(current && t != current);
- testalert();
- if (t) {
- if (t->handle == t) {
- put(current, &t->join);
- run();
- testalert();
- return current->code;
- } else
- return -1;
- } else {
- assert(isempty(join0));
- if (nthreads > 1) {
- put(current, &join0);
- run();
- testalert();
- }
- return 0;
- }
- }
- void Thread_exit(int code) {
- assert(current);
- release();
- if (current != &root) {
- current->next = freelist;
- freelist = current;
- }
- current->handle = NULL;
- while (!isempty(current->join)) {
- T t = get(¤t->join);
- t->code = code;
- put(t, &ready);
- }
- if (!isempty(join0) && nthreads == 2) {
- assert(isempty(ready));
- put(get(&join0), &ready);
- }
- if (--nthreads == 0)
- exit(code);
- else
- run();
- }
- void Thread_alert(T t) {
- assert(current);
- assert(t && t->handle == t);
- t->alerted = 1;
- if (t->inqueue) {
- delete(t, t->inqueue);
- put(t, &ready);
- }
- }
- T Thread_new(int apply(void *), void *args,
- int nbytes, ...) {
- T t;
- assert(current);
- assert(apply);
- assert(args && nbytes >= 0 || args == NULL);
- if (args == NULL)
- nbytes = 0;
- {
- int stacksize = (16*1024+sizeof (*t)+nbytes+15)&~15;
- release();
- do { critical++;
- TRY
- t = ALLOC(stacksize);
- memset(t, ' ', sizeof *t);
- EXCEPT(Mem_Failed)
- t = NULL;
- END_TRY;
- critical--; } while (0);
- if (t == NULL)
- RAISE(Thread_Failed);
- t->sp = (void *)((char *)t + stacksize);
- while (((unsigned long)t->sp)&15)
- t->sp--;
- }
- t->handle = t;
- if (nbytes > 0) {
- t->sp -= ((nbytes + 15U)&~15)/sizeof (*t->sp);
- do { critical++;
- memcpy(t->sp, args, nbytes);
- critical--; } while (0);
- args = t->sp;
- }
- #if alpha
- { extern void _start(void);
- t->sp -= 112/8;
- t->sp[(48+24)/8] = (unsigned long)Thread_exit;
- t->sp[(48+16)/8] = (unsigned long)args;
- t->sp[(48+ 8)/8] = (unsigned long)apply;
- t->sp[(48+ 0)/8] = (unsigned long)_start; }
- #elif mips
- { extern void _start(void);
- t->sp -= 16/4;
- t->sp -= 88/4;
- t->sp[(48+20)/4] = (unsigned long)Thread_exit;
- t->sp[(48+28)/4] = (unsigned long)args;
- t->sp[(48+32)/4] = (unsigned long)apply;
- t->sp[(48+36)/4] = (unsigned long)_start; }
- #elif sparc
- { int i; void *fp; extern void _start(void);
- for (i = 0; i < 8; i++)
- *--t->sp = 0;
- *--t->sp = (unsigned long)args;
- *--t->sp = (unsigned long)apply;
- t->sp -= 64/4;
- fp = t->sp;
- *--t->sp = (unsigned long)_start - 8;
- *--t->sp = (unsigned long)fp;
- t->sp -= 64/4; }
- #elif linux && i386
- { extern void _thrstart(void);
- t->sp -= 4/4;
- *t->sp = (unsigned long)_thrstart;
- t->sp -= 16/4;
- t->sp[4/4] = (unsigned long)apply;
- t->sp[8/4] = (unsigned long)args;
- t->sp[12/4] = (unsigned long)t->sp + (4+16)/4; }
- #else
- Unsupported platform
- #endif
- nthreads++;
- put(t, &ready);
- return t;
- }
- #undef T
- #define T Sem_T
- T *Sem_new(int count) {
- T *s;
- NEW(s);
- Sem_init(s, count);
- return s;
- }
- void Sem_init(T *s, int count) {
- assert(current);
- assert(s);
- s->count = count;
- s->queue = NULL;
- }
- void Sem_wait(T *s) {
- assert(current);
- assert(s);
- testalert();
- if (s->count <= 0) {
- put(current, (Thread_T *)&s->queue);
- run();
- testalert();
- } else
- --s->count;
- }
- void Sem_signal(T *s) {
- assert(current);
- assert(s);
- if (s->count == 0 && !isempty(s->queue)) {
- Thread_T t = get((Thread_T *)&s->queue);
- assert(!t->alerted);
- put(t, &ready);
- } else
- ++s->count;
- }
- #undef T