sched.c 3.3 KB

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