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