📄 thread.c
字号:
static char rcsid[] = "$Id: thread.c 183 2007-06-14 13:39:57Z drhanson $";#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 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#if __APPLE__#define sc_pc sc_eip#endifstatic 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); do { critical++; sigsetmask(scp->sc_mask); critical--; } while (0); run(); return 0;}#endifint 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, '\0', 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 = 10; it.it_interval.tv_sec = 0; it.it_interval.tv_usec = 10; 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, '\0', sizeof *t); EXCEPT(Mem_Failed) t = NULL; END_TRY; critical--; } while (0); if (t == NULL) RAISE(Thread_Failed); t->sp = (void *)(((unsigned long)t + stacksize)&~15U); } 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 || __APPLE__) && i386 { extern void _thrstart(void); t->sp -= 16/4; /* keep stack aligned to 16-byte boundaries */ *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_TT *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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -