sched.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <thread.h>
  12. #include "threadimpl.h"
  13. #include <tos.h>
  14. static Thread *runthread(Proc*);
  15. static char *_psstate[] = {
  16. "Moribund",
  17. "Dead",
  18. "Exec",
  19. "Fork",
  20. "Running",
  21. "Ready",
  22. "Rendezvous",
  23. };
  24. static char*
  25. psstate(int s)
  26. {
  27. if(s < 0 || s >= nelem(_psstate))
  28. return "unknown";
  29. return _psstate[s];
  30. }
  31. void
  32. _schedinit(void *arg)
  33. {
  34. Proc *p;
  35. Thread *t, **l;
  36. p = arg;
  37. _threadsetproc(p);
  38. p->pid = _tos->pid; //getpid();
  39. while(setjmp(p->sched))
  40. ;
  41. _threaddebug(DBGSCHED, "top of schedinit, _threadexitsallstatus=%p", _threadexitsallstatus);
  42. if(_threadexitsallstatus)
  43. exits(_threadexitsallstatus);
  44. lock(&p->lock);
  45. if((t=p->thread) != nil){
  46. p->thread = nil;
  47. if(t->moribund){
  48. t->state = Dead;
  49. for(l=&p->threads.head; *l; l=&(*l)->nextt)
  50. if(*l == t){
  51. *l = t->nextt;
  52. if(*l==nil)
  53. p->threads.tail = l;
  54. p->nthreads--;
  55. break;
  56. }
  57. unlock(&p->lock);
  58. if(t->inrendez){
  59. _threadflagrendez(t);
  60. _threadbreakrendez();
  61. }
  62. free(t->stk);
  63. free(t->cmdname);
  64. free(t); /* XXX how do we know there are no references? */
  65. t = nil;
  66. _sched();
  67. }
  68. if(p->needexec){
  69. t->ret = _schedexec(&p->exec);
  70. p->needexec = 0;
  71. }
  72. if(p->newproc){
  73. t->ret = _schedfork(p->newproc);
  74. p->newproc = nil;
  75. }
  76. t->state = t->nextstate;
  77. if(t->state == Ready)
  78. _threadready(t);
  79. }
  80. unlock(&p->lock);
  81. _sched();
  82. }
  83. void
  84. needstack(int n)
  85. {
  86. int x;
  87. Proc *p;
  88. Thread *t;
  89. p = _threadgetproc();
  90. t = p->thread;
  91. if((uint8_t*)&x - n < (uint8_t*)t->stk){
  92. fprint(2, "%s %lu: &x=%p n=%d t->stk=%p\n",
  93. argv0, _tos->pid, &x, n, t->stk);
  94. fprint(2, "%s %lu: stack overflow\n", argv0, _tos->pid);
  95. abort();
  96. }
  97. }
  98. void
  99. _sched(void)
  100. {
  101. Proc *p;
  102. Thread *t;
  103. Resched:
  104. p = _threadgetproc();
  105. if((t = p->thread) != nil){
  106. needstack(128);
  107. _threaddebug(DBGSCHED, "pausing, state=%s", psstate(t->state));
  108. if(setjmp(t->sched)==0)
  109. longjmp(p->sched, 1);
  110. return;
  111. }else{
  112. t = runthread(p);
  113. if(t == nil){
  114. _threaddebug(DBGSCHED, "all threads gone; exiting");
  115. _schedexit(p);
  116. }
  117. _threaddebug(DBGSCHED, "running %d.%d", t->proc->pid, t->id);
  118. p->thread = t;
  119. if(t->moribund){
  120. _threaddebug(DBGSCHED, "%d.%d marked to die");
  121. goto Resched;
  122. }
  123. t->state = Running;
  124. t->nextstate = Ready;
  125. longjmp(t->sched, 1);
  126. }
  127. }
  128. static Thread*
  129. runthread(Proc *p)
  130. {
  131. Thread *t;
  132. Tqueue *q;
  133. if(p->nthreads==0)
  134. return nil;
  135. q = &p->ready;
  136. lock(&p->readylock);
  137. if(q->head == nil){
  138. q->asleep = 1;
  139. _threaddebug(DBGSCHED, "sleeping for more work");
  140. unlock(&p->readylock);
  141. while(rendezvous(q, 0) == (void*)~0){
  142. if(_threadexitsallstatus)
  143. exits(_threadexitsallstatus);
  144. }
  145. /* lock picked up from _threadready */
  146. }
  147. t = q->head;
  148. q->head = t->next;
  149. unlock(&p->readylock);
  150. return t;
  151. }
  152. void
  153. _threadready(Thread *t)
  154. {
  155. Tqueue *q;
  156. assert(t->state == Ready);
  157. _threaddebug(DBGSCHED, "readying %d.%d", t->proc->pid, t->id);
  158. q = &t->proc->ready;
  159. lock(&t->proc->readylock);
  160. t->next = nil;
  161. if(q->head==nil)
  162. q->head = t;
  163. else
  164. *q->tail = t;
  165. q->tail = &t->next;
  166. if(q->asleep){
  167. q->asleep = 0;
  168. /* lock passes to runthread */
  169. _threaddebug(DBGSCHED, "waking process %d", t->proc->pid);
  170. while(rendezvous(q, 0) == (void*)~0){
  171. if(_threadexitsallstatus)
  172. exits(_threadexitsallstatus);
  173. }
  174. }else
  175. unlock(&t->proc->readylock);
  176. }
  177. void
  178. yield(void)
  179. {
  180. _sched();
  181. }