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