xref: /inferno-os/emu/Plan9/os.c (revision d0e1d143ef6f03c75c008c7ec648859dd260cbab)
1 #include	"dat.h"
2 #include	"fns.h"
3 #include	"error.h"
4 
5 enum
6 {
7 	KSTACK	= 16*1024,
8 	DELETE	= 0x7F,
9 };
10 
11 Proc	**Xup;
12 
13 extern	void	killrefresh(void);
14 extern	void	tramp(char*, void (*)(void*), void*);
15 
16 extern	int	usenewwin;
17 
18 int	*ustack;	/* address on unshared stack: see vstack in asm*.s */
19 extern	int	dflag;
20 char *hosttype = "Plan9";
21 char *cputype;
22 
23 void
24 osblock(void)
25 {
26 	rendezvous(up, nil);
27 }
28 
29 void
30 osready(Proc *p)
31 {
32 	rendezvous(p, nil);
33 }
34 
35 void
36 pexit(char *msg, int)
37 {
38 	Osenv *e;
39 
40 	USED(msg);
41 
42 	lock(&procs.l);
43 	if(up->prev)
44 		up->prev->next = up->next;
45 	else
46 		procs.head = up->next;
47 
48 	if(up->next)
49 		up->next->prev = up->prev;
50 	else
51 		procs.tail = up->prev;
52 	unlock(&procs.l);
53 
54 /*	print("pexit: %s: %s\n", up->text, msg);	/**/
55 	e = up->env;
56 	if(e != nil) {
57 		closefgrp(e->fgrp);
58 		closepgrp(e->pgrp);
59 		closeegrp(e->egrp);
60 		closesigs(e->sigs);
61 	}
62 	free(e->user);
63 	free(up->prog);
64 	up->prog = nil;
65 	up->type = Moribund;
66 	longjmp(up->privstack, 1);
67 }
68 
69 int
70 kproc(char *name, void (*func)(void*), void *arg, int flags)
71 {
72 	int pid;
73 	Proc *p;
74 	Pgrp *pg;
75 	Fgrp *fg;
76 	Egrp *eg;
77 
78 	p = newproc();
79 	if(p == nil)
80 		panic("kproc: no memory");
81 	p->kstack = mallocz(KSTACK, 0);
82 	if(p->kstack == nil)
83 		panic("kproc: no memory");
84 
85 	if(flags & KPDUPPG) {
86 		pg = up->env->pgrp;
87 		incref(&pg->r);
88 		p->env->pgrp = pg;
89 	}
90 	if(flags & KPDUPFDG) {
91 		fg = up->env->fgrp;
92 		incref(&fg->r);
93 		p->env->fgrp = fg;
94 	}
95 	if(flags & KPDUPENVG) {
96 		eg = up->env->egrp;
97 		incref(&eg->r);
98 		p->env->egrp = eg;
99 	}
100 
101 	p->env->uid = up->env->uid;
102 	p->env->gid = up->env->gid;
103 	kstrdup(&p->env->user, up->env->user);
104 
105 	strcpy(p->text, name);
106 
107 	p->func = func;
108 	p->arg = arg;
109 
110 	lock(&procs.l);
111 	if(procs.tail != nil) {
112 		p->prev = procs.tail;
113 		procs.tail->next = p;
114 	}
115 	else {
116 		procs.head = p;
117 		p->prev = nil;
118 	}
119 	procs.tail = p;
120 	unlock(&procs.l);
121 
122 	/*
123 	 * switch back to the unshared stack to do the fork
124 	 * only the parent returns from kproc
125 	 */
126 	up->kid = p;
127 	up->kidsp = p->kstack;
128 	pid = setjmp(up->sharestack);
129 	if(pid == 0)
130 		longjmp(up->privstack, 1);
131 	return pid;
132 }
133 
134 void
135 traphandler(void *reg, char *msg)
136 {
137 	int intwait;
138 
139 	intwait = up->intwait;
140 	up->intwait = 0;
141 	/* Ignore pipe writes from devcmd */
142 	if(strstr(msg, "write on closed pipe") != nil)
143 		noted(NCONT);
144 
145 	if(sflag) {
146 		if(intwait && strcmp(msg, Eintr) == 0)
147 			noted(NCONT);
148 		else
149 			noted(NDFLT);
150 	}
151 	if(intwait == 0)
152 		disfault(reg, msg);
153 	noted(NCONT);
154 }
155 
156 int
157 readfile(char *path, char *buf, int n)
158 {
159 	int fd;
160 
161 	fd = open(path, OREAD);
162 	if(fd >= 0) {
163 		n = read(fd, buf, n-1);
164 		if(n > 0)			/* both calls to readfile() have a ``default'' */
165 			buf[n] = '\0';
166 		close(fd);
167 		return n;
168 	}
169 	return 0;
170 }
171 
172 static void
173 dobinds(void)
174 {
175 	char dir[MAXROOT+9];
176 
177 	snprint(dir, sizeof(dir), "%s/net", rootdir);
178 	bind("/net", dir, MREPL);
179 
180 	snprint(dir, sizeof(dir), "%s/net.alt", rootdir);
181 	bind("/net.alt", dir, MREPL);
182 
183 	snprint(dir, sizeof(dir), "%s/dev", rootdir);
184 	bind("#t", dir, MAFTER);
185 	bind("#A", dir, MAFTER);
186 }
187 
188 void
189 libinit(char *imod)
190 {
191 	char *sp;
192 	Proc *xup, *p;
193 	int fd, n, pid;
194 	char nbuf[64];
195 
196 	xup = nil;
197 	Xup = &xup;
198 
199 	/*
200 	 * setup personality
201 	 */
202 	if(readfile("/dev/user", nbuf, sizeof nbuf))
203 		kstrdup(&eve, nbuf);
204 	if(readfile("/dev/sysname", nbuf, sizeof nbuf))
205 		kstrdup(&ossysname, nbuf);
206 	if(readfile("/env/cputype", nbuf, sizeof nbuf))
207 		kstrdup(&cputype, nbuf);
208 
209 	/*
210 	 * guess at a safe stack for vstack
211 	 */
212 	ustack = &fd;
213 
214 	rfork(RFNAMEG|RFREND);
215 
216 	if(!dflag){
217 		fd = open("/dev/consctl", OWRITE);
218 		if(fd < 0)
219 			fprint(2, "libinit: open /dev/consctl: %r\n");
220 		n = write(fd, "rawon", 5);
221 		if(n != 5)
222 			fprint(2, "keyboard rawon (n=%d, %r)\n", n);
223 	}
224 
225 	osmillisec();	/* set the epoch */
226 	dobinds();
227 
228 	notify(traphandler);
229 
230 	/*
231 	 * dummy up a up and stack so the first proc
232 	 * calls emuinit after setting up his private jmp_buf
233 	 */
234 	p = newproc();
235 	p->kstack = mallocz(KSTACK, 0);
236 	if(p == nil || p->kstack == nil)
237 		panic("libinit: no memory");
238 	sp = p->kstack;
239 	p->func = emuinit;
240 	p->arg = imod;
241 
242 	/*
243 	 * set up a stack for forking kids on separate stacks.
244 	 * longjmp back here from kproc.
245 	 */
246 	while(setjmp(p->privstack)){
247 		if(up->type == Moribund){
248 			free(up->kstack);
249 			free(up);
250 			_exits("");
251 		}
252 		p = up->kid;
253 		sp = up->kidsp;
254 		up->kid = nil;
255 		switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){
256 		case 0:
257 			/*
258 			 * send the kid around the loop to set up his private jmp_buf
259 			 */
260 			break;
261 		default:
262 			/*
263 			 * parent just returns to his shared stack in kproc
264 			 */
265 			longjmp(up->sharestack, pid);
266 			panic("longjmp failed");
267 		}
268 	}
269 
270 	/*
271 	 * you get here only once per Proc
272 	 * go to the shared memory stack
273 	 */
274 	up = p;
275 	up->pid = up->sigid = getpid();
276 	tramp(sp+KSTACK, up->func, up->arg);
277 	panic("tramp returned");
278 }
279 
280 void
281 oshostintr(Proc *p)
282 {
283 	postnote(PNPROC, p->sigid, Eintr);
284 }
285 
286 void
287 oslongjmp(void *regs, osjmpbuf env, int val)
288 {
289 	if(regs != nil)
290 		notejmp(regs, env, val);
291 	else
292 		longjmp(env, val);
293 }
294 
295 void
296 osreboot(char*, char**)
297 {
298 }
299 
300 void
301 cleanexit(int x)
302 {
303 	USED(x);
304 	killrefresh();
305 	postnote(PNGROUP, getpid(), "interrupt");
306 	exits("interrupt");
307 }
308 
309 int
310 readkbd(void)
311 {
312 	int n;
313 	char buf[1];
314 
315 	n = read(0, buf, sizeof(buf));
316 	if(n < 0)
317 		fprint(2, "emu: keyboard read error: %r\n");
318 	if(n <= 0)
319 		pexit("keyboard", 0);
320 	switch(buf[0]) {
321 	case DELETE:
322 		cleanexit(0);
323 	case '\r':
324 		buf[0] = '\n';
325 	}
326 	return buf[0];
327 }
328 
329 static vlong
330 b2v(uchar *p)
331 {
332 	int i;
333 	vlong v;
334 
335 	v = 0;
336 	for(i=0; i<sizeof(uvlong); i++)
337 		v = (v<<8)|p[i];
338 	return v;
339 }
340 
341 vlong
342 nsec(void)
343 {
344 	int n;
345 	static int nsecfd = -1;
346 	uchar buf[sizeof(uvlong)];
347 
348 	if(nsecfd < 0){
349 		nsecfd = open("/dev/bintime", OREAD|OCEXEC);  /* never closed */
350 		if(nsecfd<0){
351 			fprint(2,"can't open /dev/bintime: %r\n");
352 			return 0;
353 		}
354 	}
355 	n = read(nsecfd, buf, sizeof(buf));
356 	if(n!=sizeof(buf)) {
357 		fprint(2,"read err on /dev/bintime: %r\n");
358 		return 0;
359 	}
360 	return b2v(buf);
361 }
362 
363 long
364 osmillisec(void)
365 {
366 	static vlong nsec0 = 0;
367 
368 	if(nsec0 == 0){
369 		nsec0 = nsec();
370 		return 0;
371 	}
372 	return (nsec()-nsec0)/1000000;
373 }
374 
375 /*
376  * Return the time since the epoch in microseconds
377  * The epoch is defined at 1 Jan 1970
378  */
379 vlong
380 osusectime(void)
381 {
382 	return nsec()/1000;
383 }
384 
385 int
386 osmillisleep(ulong milsec)
387 {
388 	sleep(milsec);
389 	return 0;
390 }
391 
392 int
393 limbosleep(ulong milsec)
394 {
395 	return osmillisleep(milsec);
396 }
397 
398 void
399 osyield(void)
400 {
401 	sleep(0);
402 }
403 
404 void
405 ospause(void)
406 {
407 	for(;;)
408 		sleep(1000000);
409 }
410 
411 void
412 oslopri(void)
413 {
414 	int fd;
415 	char buf[32];
416 
417 	snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid());
418 	if((fd = open(buf, OWRITE)) >= 0){
419 		fprint(fd, "pri 8");
420 		close(fd);
421 	}
422 }
423