thread.c
资源名称:c.rar [点击查看]
上传用户:shmaik
上传日期:2014-06-01
资源大小:45093k
文件大小:7k
源码类别:

VC书籍

开发平台:

C/C++

  1. static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/thread.doc,v 1.11 1997/02/21 19:50:51 drh Exp $";
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include </usr/include/signal.h>
  6. #include <sys/time.h>
  7. #include "assert.h"
  8. #include "mem.h"
  9. #include "thread.h"
  10. #include "sem.h"
  11. void _MONITOR(void) {}
  12. extern void _ENDMONITOR(void);
  13. #define T Thread_T
  14. #define isempty(q) ((q) == NULL)
  15. struct T {
  16. unsigned long *sp; /* must be first */
  17. T link;
  18. T *inqueue;
  19. T handle;
  20. Except_Frame *estack;
  21. int code;
  22. T join;
  23. T next;
  24. int alerted;
  25. };
  26. static T ready = NULL;
  27. static T current;
  28. static int nthreads;
  29. static struct Thread_T root;
  30. static T join0;
  31. static T freelist;
  32. const Except_T Thread_Alerted = { "Thread alerted" };
  33. const Except_T Thread_Failed =
  34. { "Thread creation failed" };
  35. static int critical;
  36. extern void _swtch(T from, T to);
  37. static void put(T t, T *q) {
  38. assert(t);
  39. assert(t->inqueue == NULL && t->link == NULL);
  40. if (*q) {
  41. t->link = (*q)->link;
  42. (*q)->link = t;
  43. } else
  44. t->link = t;
  45. *q = t;
  46. t->inqueue = q;
  47. }
  48. static T get(T *q) {
  49. T t;
  50. assert(!isempty(*q));
  51. t = (*q)->link;
  52. if (t == *q)
  53. *q = NULL;
  54. else
  55. (*q)->link = t->link;
  56. assert(t->inqueue == q);
  57. t->link = NULL;
  58. t->inqueue = NULL;
  59. return t;
  60. }
  61. static void delete(T t, T *q) {
  62. T p;
  63. assert(t->link && t->inqueue == q);
  64. assert(!isempty(*q));
  65. for (p = *q; p->link != t; p = p->link)
  66. ;
  67. if (p == t)
  68. *q = NULL;
  69. else {
  70. p->link = t->link;
  71. if (*q == t)
  72. *q = p;
  73. }
  74. t->link = NULL;
  75. t->inqueue = NULL;
  76. }
  77. static void run(void) {
  78. T t = current;
  79. current = get(&ready);
  80. t->estack = Except_stack;
  81. Except_stack = current->estack;
  82. _swtch(t, current);
  83. }
  84. static void testalert(void) {
  85. if (current->alerted) {
  86. current->alerted = 0;
  87. RAISE(Thread_Alerted);
  88. }
  89. }
  90. static void release(void) {
  91. T t;
  92. do { critical++;
  93. while ((t = freelist) != NULL) {
  94. freelist = t->next;
  95. FREE(t);
  96. }
  97. critical--; } while (0);
  98. }
  99. #if linux
  100. #include <asm/sigcontext.h>
  101. static int interrupt(int sig, struct sigcontext_struct sc) {
  102. if (critical ||
  103.    sc.eip >= (unsigned long)_MONITOR
  104. && sc.eip <= (unsigned long)_ENDMONITOR)
  105. return 0;
  106. put(current, &ready);
  107. do { critical++;
  108. sigsetmask(sc.oldmask);
  109. critical--; } while (0);
  110. run();
  111. return 0;
  112. }
  113. #else
  114. static int interrupt(int sig, int code,
  115. struct sigcontext *scp) {
  116. if (critical ||
  117.    scp->sc_pc >= (unsigned long)_MONITOR
  118. && scp->sc_pc <= (unsigned long)_ENDMONITOR)
  119. return 0;
  120. put(current, &ready);
  121. sigsetmask(scp->sc_mask);
  122. run();
  123. return 0;
  124. }
  125. #endif
  126. int Thread_init(int preempt, ...) {
  127. assert(preempt == 0 || preempt == 1);
  128. assert(current == NULL);
  129. root.handle = &root;
  130. current = &root;
  131. nthreads = 1;
  132. if (preempt) {
  133. {
  134. struct sigaction sa;
  135. memset(&sa, '', sizeof sa);
  136. sa.sa_handler = (void (*)())interrupt;
  137. if (sigaction(SIGVTALRM, &sa, NULL) < 0)
  138. return 0;
  139. }
  140. {
  141. struct itimerval it;
  142. it.it_value.tv_sec     =  0;
  143. it.it_value.tv_usec    = 50;
  144. it.it_interval.tv_sec  =  0;
  145. it.it_interval.tv_usec = 50;
  146. if (setitimer(ITIMER_VIRTUAL, &it, NULL) < 0)
  147. return 0;
  148. }
  149. }
  150. return 1;
  151. }
  152. T Thread_self(void) {
  153. assert(current);
  154. return current;
  155. }
  156. void Thread_pause(void) {
  157. assert(current);
  158. put(current, &ready);
  159. run();
  160. }
  161. int Thread_join(T t) {
  162. assert(current && t != current);
  163. testalert();
  164. if (t) {
  165. if (t->handle == t) {
  166. put(current, &t->join);
  167. run();
  168. testalert();
  169. return current->code;
  170. } else
  171. return -1;
  172. } else {
  173. assert(isempty(join0));
  174. if (nthreads > 1) {
  175. put(current, &join0);
  176. run();
  177. testalert();
  178. }
  179. return 0;
  180. }
  181. }
  182. void Thread_exit(int code) {
  183. assert(current);
  184. release();
  185. if (current != &root) {
  186. current->next = freelist;
  187. freelist = current;
  188. }
  189. current->handle = NULL;
  190. while (!isempty(current->join)) {
  191. T t = get(&current->join);
  192. t->code = code;
  193. put(t, &ready);
  194. }
  195. if (!isempty(join0) && nthreads == 2) {
  196. assert(isempty(ready));
  197. put(get(&join0), &ready);
  198. }
  199. if (--nthreads == 0)
  200. exit(code);
  201. else
  202. run();
  203. }
  204. void Thread_alert(T t) {
  205. assert(current);
  206. assert(t && t->handle == t);
  207. t->alerted = 1;
  208. if (t->inqueue) {
  209. delete(t, t->inqueue);
  210. put(t, &ready);
  211. }
  212. }
  213. T Thread_new(int apply(void *), void *args,
  214. int nbytes, ...) {
  215.   T t;
  216. assert(current);
  217. assert(apply);
  218. assert(args && nbytes >= 0 || args == NULL);
  219. if (args == NULL)
  220. nbytes = 0;
  221. {
  222. int stacksize = (16*1024+sizeof (*t)+nbytes+15)&~15;
  223. release();
  224. do { critical++;
  225. TRY
  226. t = ALLOC(stacksize);
  227. memset(t, '', sizeof *t);
  228. EXCEPT(Mem_Failed)
  229. t = NULL;
  230. END_TRY;
  231. critical--; } while (0);
  232. if (t == NULL)
  233. RAISE(Thread_Failed);
  234. t->sp = (void *)((char *)t + stacksize);
  235. while (((unsigned long)t->sp)&15)
  236. t->sp--;
  237. }
  238. t->handle = t;
  239. if (nbytes > 0) {
  240. t->sp -= ((nbytes + 15U)&~15)/sizeof (*t->sp);
  241. do { critical++;
  242. memcpy(t->sp, args, nbytes);
  243. critical--; } while (0);
  244. args = t->sp;
  245. }
  246. #if alpha
  247. { extern void _start(void);
  248.   t->sp -= 112/8;
  249.   t->sp[(48+24)/8] = (unsigned long)Thread_exit;
  250.   t->sp[(48+16)/8] = (unsigned long)args;
  251.   t->sp[(48+ 8)/8] = (unsigned long)apply;
  252.   t->sp[(48+ 0)/8] = (unsigned long)_start; }
  253. #elif mips
  254. { extern void _start(void);
  255.   t->sp -= 16/4;
  256.   t->sp -= 88/4;
  257.   t->sp[(48+20)/4] = (unsigned long)Thread_exit;
  258.   t->sp[(48+28)/4] = (unsigned long)args;
  259.   t->sp[(48+32)/4] = (unsigned long)apply;
  260.   t->sp[(48+36)/4] = (unsigned long)_start; }
  261. #elif sparc
  262. {  int i; void *fp; extern void _start(void);
  263.    for (i = 0; i < 8; i++)
  264.    *--t->sp = 0;
  265.    *--t->sp = (unsigned long)args;
  266.    *--t->sp = (unsigned long)apply;
  267.    t->sp -= 64/4;
  268.    fp = t->sp;
  269.    *--t->sp = (unsigned long)_start - 8;
  270.    *--t->sp = (unsigned long)fp;
  271.    t->sp -= 64/4; }
  272. #elif linux && i386
  273. { extern void _thrstart(void);
  274.   t->sp -= 4/4;
  275.   *t->sp = (unsigned long)_thrstart;
  276.   t->sp -= 16/4;
  277.   t->sp[4/4]  = (unsigned long)apply;
  278.   t->sp[8/4]  = (unsigned long)args;
  279.   t->sp[12/4] = (unsigned long)t->sp + (4+16)/4; }
  280. #else
  281. Unsupported platform
  282. #endif
  283. nthreads++;
  284. put(t, &ready);
  285. return t;
  286. }
  287. #undef T
  288. #define T Sem_T
  289. T *Sem_new(int count) {
  290. T *s;
  291. NEW(s);
  292. Sem_init(s, count);
  293. return s;
  294. }
  295. void Sem_init(T *s, int count) {
  296. assert(current);
  297. assert(s);
  298. s->count = count;
  299. s->queue = NULL;
  300. }
  301. void Sem_wait(T *s) {
  302. assert(current);
  303. assert(s);
  304. testalert();
  305. if (s->count <= 0) {
  306. put(current, (Thread_T *)&s->queue);
  307. run();
  308. testalert();
  309. } else
  310. --s->count;
  311. }
  312. void Sem_signal(T *s) {
  313. assert(current);
  314. assert(s);
  315. if (s->count == 0 && !isempty(s->queue)) {
  316. Thread_T t = get((Thread_T *)&s->queue);
  317. assert(!t->alerted);
  318. put(t, &ready);
  319. } else
  320. ++s->count;
  321. }
  322. #undef T