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