xref: /inferno-os/emu/DragonFly/os.c (revision ebcf8d9b30a1bc12ed7da82c9b1bae3bf11ef0dd)
1 #include	"dat.h"
2 #include	"fns.h"
3 #include	"error.h"
4 #undef getwd
5 #include	<signal.h>
6 #include 	<sys/socket.h>
7 #include	<time.h>
8 #include	<sys/time.h>
9 #include	<termios.h>
10 #include	<sched.h>
11 #include	<pwd.h>
12 #include	<errno.h>
13 #include	<unistd.h>
14 #include	<sys/resource.h>
15 #include 	<fpuctl.h>
16 
17 enum
18 {
19 	DELETE  = 0x7F,
20 	NSTACKSPERALLOC = 16,
21 	X11STACK=	256*1024
22 };
23 char *hosttype = "DragonFly";
24 
25 extern void unlockandexit(int*);
26 extern void executeonnewstack(void*, void (*f)(void*), void*);
27 static void *stackalloc(Proc *p, void **tos);
28 static void stackfreeandexit(void *stack);
29 
30 extern int dflag;
31 
32 void
33 pexit(char *msg, int t)
34 {
35 	Osenv *e;
36 	Proc *p;
37 	void *kstack;
38 
39 	lock(&procs.l);
40 	p = up;
41 	if(p->prev)
42 		p->prev->next = p->next;
43 	else
44 		procs.head = p->next;
45 
46 	if(up->next)
47 		p->next->prev = p->prev;
48 	else
49 		procs.tail = p->prev;
50 	unlock(&procs.l);
51 
52 	if(0)
53 		print("pexit: %s: %s\n", up->text, msg);
54 
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 	kstack = p->kstack;
63 	free(p->prog);
64 	free(p);
65 	if(kstack != nil)
66 		stackfreeandexit(kstack);
67 }
68 
69 void
70 trapBUS(int signo, siginfo_t *info, void *context)
71 {
72 	if(info)
73 		print("trapBUS: signo: %d code: %d addr: %lx\n",
74 		info->si_signo, info->si_code, info->si_addr);
75 	else
76 		print("trapBUS: no info\n");
77 	disfault(nil, "Bus error");
78 }
79 
80 static void
81 trapUSR1(int signo)
82 {
83 	int intwait;
84 
85 	USED(signo);
86 
87 	intwait = up->intwait;
88 	up->intwait = 0;	/* clear it to let proc continue in osleave */
89 
90 	if(up->type != Interp)		/* Used to unblock pending I/O */
91 		return;
92 	if(intwait == 0)		/* Not posted so its a sync error */
93 		disfault(nil, Eintr);	/* Should never happen */
94 }
95 
96 static void
97 trapUSR2(int signo)
98 {
99 	USED(signo);
100 	/* we've done our work of interrupting sigsuspend */
101 }
102 
103 static void
104 trapILL(int signo)
105 {
106 	disfault(nil, "Illegal instruction");
107 }
108 
109 static void
110 trapSEGV(int signo)
111 {
112 	disfault(nil, "Segmentation violation");
113 }
114 
115 static void
116 trapFPE(int signo)
117 {
118 	char buf[64];
119 	USED(signo);
120 	snprint(buf, sizeof(buf), "sys: fp: exception status=%.4lux", getfsr());
121 	disfault(nil, buf);
122 }
123 
124 static sigset_t initmask;
125 
126 static void
127 setsigs(void)
128 {
129 	struct sigaction act;
130 	sigset_t mask;
131 
132 	memset(&act, 0 , sizeof(act));
133 	sigemptyset(&initmask);
134 
135 	signal(SIGPIPE, SIG_IGN);	/* prevent signal when devcmd child exits */
136 	if(signal(SIGTERM, SIG_IGN) != SIG_IGN)
137 		signal(SIGTERM, cleanexit);
138 
139 	act.sa_handler = trapUSR1;
140 	act.sa_mask = initmask;
141 	sigaction(SIGUSR1, &act, nil);
142 
143 	act.sa_handler = trapUSR2;
144 	sigaction(SIGUSR2, &act, nil);
145 	sigemptyset(&mask);
146 	sigaddset(&mask, SIGUSR2);
147 	sigaddset(&initmask, SIGUSR2);
148 	sigprocmask(SIG_BLOCK, &mask, NULL);
149 
150 	/*
151  	 * prevent Zombies forming when any process terminates
152 	 */
153 	act.sa_sigaction = 0;
154 	act.sa_flags |= SA_NOCLDWAIT;
155 	if(sigaction(SIGCHLD, &act, nil))
156 		panic("sigaction SIGCHLD");
157 
158 	if(sflag == 0) {
159 		act.sa_sigaction = trapBUS;
160 		act.sa_flags |= SA_SIGINFO;
161 		if(sigaction(SIGBUS, &act, nil))
162 			panic("sigaction SIGBUS");
163 		act.sa_handler = trapILL;
164 		if(sigaction(SIGILL, &act, nil))
165 			panic("sigaction SIGBUS");
166 		act.sa_handler = trapSEGV;
167 		if(sigaction(SIGSEGV, &act, nil))
168 			panic("sigaction SIGSEGV");
169 		act.sa_handler = trapFPE;
170 		if(sigaction(SIGFPE, &act, nil))
171 			panic("sigaction SIGFPE");
172 		if(sigaddset(&initmask, SIGINT) == -1)
173 			panic("sigaddset");
174 	}
175 	if(sigprocmask(SIG_BLOCK, &initmask, nil)!= 0)
176 		panic("sigprocmask");
177 }
178 
179 static int
180 tramp(void *arg)
181 {
182 	Proc *p;
183 
184 	p = arg;
185 	p->pid = p->sigid = getpid();
186 	sigprocmask(SIG_BLOCK, &initmask, nil);	/* in 5.3, rfork_thread doesn't copy from parent, contrary to docs? */
187 	(*p->func)(p->arg);
188 	pexit("{Tramp}", 0);
189 	_exit(0);
190 }
191 
192 int
193 kproc(char *name, void (*func)(void*), void *arg, int flags)
194 {
195 	Proc *p;
196 	Pgrp *pg;
197 	Fgrp *fg;
198 	Egrp *eg;
199 	int pid;
200 	void *tos;
201 
202 	p = newproc();
203 
204 	if(flags & KPDUPPG) {
205 		pg = up->env->pgrp;
206 		incref(&pg->r);
207 		p->env->pgrp = pg;
208 	}
209 	if(flags & KPDUPFDG) {
210 		fg = up->env->fgrp;
211 		incref(&fg->r);
212 		p->env->fgrp = fg;
213 	}
214 	if(flags & KPDUPENVG) {
215 		eg = up->env->egrp;
216 		incref(&eg->r);
217 		p->env->egrp = eg;
218 	}
219 
220 	p->env->uid = up->env->uid;
221 	p->env->gid = up->env->gid;
222 	kstrdup(&p->env->user, up->env->user);
223 
224 	strcpy(p->text, name);
225 
226 	p->func = func;
227 	p->arg = arg;
228 
229 	lock(&procs.l);
230 	if(procs.tail != nil) {
231 		p->prev = procs.tail;
232 		procs.tail->next = p;
233 	}
234 	else {
235 		procs.head = p;
236 		p->prev = nil;
237 	}
238 	procs.tail = p;
239 	unlock(&procs.l);
240 
241 	if(flags & KPX11){
242 		p->kstack = nil;	/* never freed; also up not defined */
243 		tos = (char*)mallocz(X11STACK, 0) + X11STACK - sizeof(void*);
244 	}else
245 		p->kstack = stackalloc(p, &tos);
246 	pid = rfork_thread(RFPROC|RFMEM|RFNOWAIT, tos, tramp, p);
247 	if(pid < 0)
248 		panic("ourfork");
249 
250 	return pid;
251 
252 }
253 
254 void
255 oshostintr(Proc *p)
256 {
257 	kill(p->sigid, SIGUSR1);
258 }
259 
260 void
261 osblock(void)
262 {
263 	sigset_t mask;
264 
265 	sigprocmask(SIG_SETMASK, NULL, &mask);
266 	sigdelset(&mask, SIGUSR2);
267 	sigsuspend(&mask);
268 }
269 
270 void
271 osready(Proc *p)
272 {
273 	if(kill(p->sigid, SIGUSR2) < 0)
274 		fprint(2, "emu: osready failed: pid %d: %s\n", p->sigid, strerror(errno));
275 }
276 
277 void
278 oslongjmp(void *regs, osjmpbuf env, int val)
279 {
280 	USED(regs);
281 	siglongjmp(env, val);
282 }
283 
284 struct termios tinit;
285 
286 static void
287 termset(void)
288 {
289 	struct termios t;
290 
291 	tcgetattr(0, &t);
292 	tinit = t;
293 	t.c_lflag &= ~(ICANON|ECHO|ISIG);
294 	t.c_cc[VMIN] = 1;
295 	t.c_cc[VTIME] = 0;
296 	tcsetattr(0, TCSANOW, &t);
297 }
298 
299 static void
300 termrestore(void)
301 {
302 	tcsetattr(0, TCSANOW, &tinit);
303 }
304 
305 void
306 cleanexit(int x)
307 {
308 	USED(x);
309 
310 	if(up->intwait) {
311 		up->intwait = 0;
312 		return;
313 	}
314 
315 	if(dflag == 0)
316 		termrestore();
317 
318 	kill(0, SIGKILL);
319 	exit(0);
320 }
321 
322 void
323 osreboot(char *file, char **argv)
324 {
325 	if(dflag == 0)
326 		termrestore();
327 	execvp(file, argv);
328 	panic("reboot failure");
329 }
330 
331 int gidnobody= -1, uidnobody= -1;
332 
333 void
334 getnobody()
335 {
336 	struct passwd *pwd;
337 
338 	if(pwd = getpwnam("nobody")) {
339 		uidnobody = pwd->pw_uid;
340 		gidnobody = pwd->pw_gid;
341 	}
342 }
343 
344 void
345 libinit(char *imod)
346 {
347 	struct passwd *pw;
348 	Proc *p;
349 	void *tos;
350 	char sys[64];
351 
352 	setsid();
353 
354 	gethostname(sys, sizeof(sys));
355 	kstrdup(&ossysname, sys);
356 	getnobody();
357 
358 	if(dflag == 0)
359 		termset();
360 
361 	setsigs();
362 
363 	p = newproc();
364 	p->kstack = stackalloc(p, &tos);
365 
366 	pw = getpwuid(getuid());
367 	if(pw != nil)
368 		kstrdup(&eve, pw->pw_name);
369 	else
370 		print("cannot getpwuid\n");
371 
372 	p->env->uid = getuid();
373 	p->env->gid = getgid();
374 
375 	executeonnewstack(tos, emuinit, imod);
376 }
377 
378 int
379 readkbd(void)
380 {
381 	int n;
382 	char buf[1];
383 
384 	n = read(0, buf, sizeof(buf));
385 	if(n < 0)
386 		print("keyboard close (n=%d, %s)\n", n, strerror(errno));
387 	if(n <= 0)
388 		pexit("keyboard thread", 0);
389 
390 	switch(buf[0]) {
391 	case '\r':
392 		buf[0] = '\n';
393 		break;
394 	case DELETE:
395 		cleanexit(0);
396 		break;
397 	}
398 	return buf[0];
399 }
400 
401 /*
402  * Return an abitrary millisecond clock time
403  */
404 long
405 osmillisec(void)
406 {
407 	static long sec0 = 0, usec0;
408 	struct timeval t;
409 
410 	if(gettimeofday(&t,(struct timezone*)0)<0)
411 		return 0;
412 	if(sec0==0) {
413 		sec0 = t.tv_sec;
414 		usec0 = t.tv_usec;
415 	}
416 	return (t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000;
417 }
418 
419 int
420 limbosleep(ulong milsec)
421 {
422 	return osmillisleep(milsec);
423 }
424 
425 /*
426  * Return the time since the epoch in nanoseconds and microseconds
427  * The epoch is defined at 1 Jan 1970
428  */
429 vlong
430 osnsec(void)
431 {
432 	struct timeval t;
433 
434 	gettimeofday(&t, nil);
435 	return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000;
436 }
437 
438 vlong
439 osusectime(void)
440 {
441 	struct timeval t;
442 
443 	gettimeofday(&t, nil);
444 	return (vlong)t.tv_sec * 1000000 + t.tv_usec;
445 }
446 
447 int
448 osmillisleep(ulong milsec)
449 {
450 	struct timespec time;
451 
452 	time.tv_sec = milsec / 1000;
453 	time.tv_nsec = (milsec % 1000) * 1000000;
454 	nanosleep(&time, 0);
455 	return 0;
456 }
457 
458 void
459 osyield(void)
460 {
461 	sched_yield();
462 }
463 
464 void
465 ospause(void)
466 {
467 	for(;;)
468 		pause();
469 }
470 
471 void
472 oslopri(void)
473 {
474 	setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS,0)+4);
475 }
476 
477 static struct {
478 	Lock l;
479 	void *free;
480 } stacklist;
481 
482 static void
483 _stackfree(void *stack)
484 {
485 	*((void **)stack) = stacklist.free;
486 	stacklist.free = stack;
487 }
488 
489 static void
490 stackfreeandexit(void *stack)
491 {
492 	lock(&stacklist.l);
493 	_stackfree(stack);
494 	unlockandexit(&stacklist.l.val);
495 }
496 
497 static void *
498 stackalloc(Proc *p, void **tos)
499 {
500 	void *rv;
501 	lock(&stacklist.l);
502 	if (stacklist.free == 0) {
503 		int x;
504 		/*
505 		 * obtain some more by using sbrk()
506 		 */
507 		void *more = sbrk(KSTACK * (NSTACKSPERALLOC + 1));
508 		if (more == 0)
509 			panic("stackalloc: no more stacks");
510 		/*
511 		 * align to KSTACK
512 		 */
513 		more = (void *)((((unsigned long)more) + (KSTACK - 1)) & ~(KSTACK - 1));
514 		/*
515 		 * free all the new stacks onto the freelist
516 		 */
517 		for (x = 0; x < NSTACKSPERALLOC; x++)
518 			_stackfree((char *)more + KSTACK * x);
519 	}
520 	rv = stacklist.free;
521 	stacklist.free = *(void **)rv;
522 	unlock(&stacklist.l);
523 	*tos = rv + KSTACK - sizeof(void*);
524 	*(Proc **)rv = p;
525 	return rv;
526 }
527 
528 int
529 segflush(void *a, ulong n)
530 {
531 	USED(a);
532 	USED(n);
533 	return 0;
534 }
535