1 #include <u.h> 2 #include <libc.h> 3 #include <thread.h> 4 #include "threadimpl.h" 5 6 typedef struct Mainarg Mainarg; 7 struct Mainarg 8 { 9 int argc; 10 char **argv; 11 }; 12 13 int mainstacksize; 14 int _threadnotefd; 15 int _threadpasserpid; 16 static jmp_buf _mainjmp; 17 static void mainlauncher(void*); 18 extern void (*_sysfatal)(char*, va_list); 19 extern void (*__assert)(char*); 20 static Proc **mainp; 21 22 void 23 main(int argc, char **argv) 24 { 25 Mainarg *a; 26 Proc *p; 27 28 rfork(RFREND); 29 mainp = &p; 30 if(setjmp(_mainjmp)) 31 _schedinit(p); 32 33 //_threaddebuglevel = (DBGSCHED|DBGCHAN|DBGREND)^~0; 34 _systhreadinit(); 35 _qlockinit(_threadrendezvous); 36 _sysfatal = _threadsysfatal; 37 __assert = _threadassert; 38 notify(_threadnote); 39 if(mainstacksize == 0) 40 mainstacksize = 8*1024; 41 42 a = _threadmalloc(sizeof *a, 1); 43 a->argc = argc; 44 a->argv = argv; 45 46 p = _newproc(mainlauncher, a, mainstacksize, "threadmain", 0, 0); 47 _schedinit(p); 48 abort(); /* not reached */ 49 } 50 51 static void 52 mainlauncher(void *arg) 53 { 54 Mainarg *a; 55 56 a = arg; 57 threadmain(a->argc, a->argv); 58 threadexits("threadmain"); 59 } 60 61 static char* 62 skip(char *p) 63 { 64 while(*p == ' ') 65 p++; 66 while(*p != ' ' && *p != 0) 67 p++; 68 return p; 69 } 70 71 static long 72 _times(long *t) 73 { 74 char b[200], *p; 75 int f; 76 ulong r; 77 78 memset(b, 0, sizeof(b)); 79 f = open("/dev/cputime", OREAD|OCEXEC); 80 if(f < 0) 81 return 0; 82 if(read(f, b, sizeof(b)) <= 0){ 83 close(f); 84 return 0; 85 } 86 p = b; 87 if(t) 88 t[0] = atol(p); 89 p = skip(p); 90 if(t) 91 t[1] = atol(p); 92 p = skip(p); 93 r = atol(p); 94 if(t){ 95 p = skip(p); 96 t[2] = atol(p); 97 p = skip(p); 98 t[3] = atol(p); 99 } 100 return r; 101 } 102 103 static void 104 efork(Execargs *e) 105 { 106 char buf[ERRMAX]; 107 108 _threaddebug(DBGEXEC, "_schedexec %s", e->prog); 109 close(e->fd[0]); 110 exec(e->prog, e->args); 111 _threaddebug(DBGEXEC, "_schedexec failed: %r"); 112 rerrstr(buf, sizeof buf); 113 if(buf[0]=='\0') 114 strcpy(buf, "exec failed"); 115 write(e->fd[1], buf, strlen(buf)); 116 close(e->fd[1]); 117 _exits(buf); 118 } 119 120 int 121 _schedexec(Execargs *e) 122 { 123 int pid; 124 125 switch(pid = rfork(RFREND|RFNOTEG|RFFDG|RFMEM|RFPROC)){ 126 case 0: 127 efork(e); 128 default: 129 return pid; 130 } 131 } 132 133 int 134 _schedfork(Proc *p) 135 { 136 int pid; 137 138 switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT|p->rforkflag)){ 139 case 0: 140 *mainp = p; /* write to stack, so local to proc */ 141 longjmp(_mainjmp, 1); 142 default: 143 return pid; 144 } 145 } 146 147 void 148 _schedexit(Proc *p) 149 { 150 char ex[ERRMAX]; 151 Proc **l; 152 153 lock(&_threadpq.lock); 154 for(l=&_threadpq.head; *l; l=&(*l)->next){ 155 if(*l == p){ 156 *l = p->next; 157 if(*l == nil) 158 _threadpq.tail = l; 159 break; 160 } 161 } 162 unlock(&_threadpq.lock); 163 164 utfecpy(ex, ex+sizeof ex, p->exitstr); 165 free(p); 166 _exits(ex); 167 } 168 169 void 170 _schedexecwait(void) 171 { 172 int pid; 173 Channel *c; 174 Proc *p; 175 Thread *t; 176 Waitmsg *w; 177 178 p = _threadgetproc(); 179 t = p->thread; 180 pid = t->ret; 181 _threaddebug(DBGEXEC, "_schedexecwait %d", t->ret); 182 183 rfork(RFCFDG); 184 for(;;){ 185 w = wait(); 186 if(w == nil) 187 break; 188 if(w->pid == pid) 189 break; 190 free(w); 191 } 192 if(w != nil){ 193 if((c = _threadwaitchan) != nil) 194 sendp(c, w); 195 else 196 free(w); 197 } 198 threadexits("procexec"); 199 } 200 201 static Proc **procp; 202 203 void 204 _systhreadinit(void) 205 { 206 procp = privalloc(); 207 } 208 209 Proc* 210 _threadgetproc(void) 211 { 212 return *procp; 213 } 214 215 void 216 _threadsetproc(Proc *p) 217 { 218 *procp = p; 219 } 220