xref: /plan9-contrib/sys/src/libthread/main.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
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