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