xref: /inferno-os/emu/FreeBSD/os.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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 = "FreeBSD";
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 sigset_t initmask;
115 
116 static void
117 setsigs(void)
118 {
119 	struct sigaction act;
120 	sigset_t mask;
121 
122 	memset(&act, 0 , sizeof(act));
123 	sigemptyset(&initmask);
124 
125 	signal(SIGPIPE, SIG_IGN);	/* prevent signal when devcmd child exits */
126 	if(signal(SIGTERM, SIG_IGN) != SIG_IGN)
127 		signal(SIGTERM, cleanexit);
128 
129 	act.sa_handler = trapUSR1;
130 	act.sa_mask = initmask;
131 	sigaction(SIGUSR1, &act, nil);
132 
133 	act.sa_handler = trapUSR2;
134 	sigaction(SIGUSR2, &act, nil);
135 	sigemptyset(&mask);
136 	sigaddset(&mask, SIGUSR2);
137 	sigaddset(&initmask, SIGUSR2);
138 	sigprocmask(SIG_BLOCK, &mask, NULL);
139 
140 	/*
141  	 * prevent Zombies forming when any process terminates
142 	 */
143 	act.sa_sigaction = 0;
144 	act.sa_flags |= SA_NOCLDWAIT;
145 	if(sigaction(SIGCHLD, &act, nil))
146 		panic("sigaction SIGCHLD");
147 
148 	if(sflag == 0) {
149 		act.sa_sigaction = trapBUS;
150 		act.sa_flags |= SA_SIGINFO;
151 		if(sigaction(SIGBUS, &act, nil))
152 			panic("sigaction SIGBUS");
153 		act.sa_handler = trapILL;
154 		if(sigaction(SIGILL, &act, nil))
155 			panic("sigaction SIGBUS");
156 		act.sa_handler = trapSEGV;
157 		if(sigaction(SIGSEGV, &act, nil))
158 			panic("sigaction SIGSEGV");
159 		if(sigaddset(&initmask, SIGINT) == -1)
160 			panic("sigaddset");
161 	}
162 	if(sigprocmask(SIG_BLOCK, &initmask, nil)!= 0)
163 		panic("sigprocmask");
164 }
165 
166 static int
167 tramp(void *arg)
168 {
169 	Proc *p;
170 
171 	p = arg;
172 	p->pid = p->sigid = getpid();
173 	sigprocmask(SIG_BLOCK, &initmask, nil);	/* in 5.3, rfork_thread doesn't copy from parent, contrary to docs? */
174 	(*p->func)(p->arg);
175 	pexit("{Tramp}", 0);
176 	_exit(0);
177 }
178 
179 int
180 kproc(char *name, void (*func)(void*), void *arg, int flags)
181 {
182 	Proc *p;
183 	Pgrp *pg;
184 	Fgrp *fg;
185 	Egrp *eg;
186 	int pid;
187 	void *tos;
188 
189 	p = newproc();
190 
191 	if(flags & KPDUPPG) {
192 		pg = up->env->pgrp;
193 		incref(&pg->r);
194 		p->env->pgrp = pg;
195 	}
196 	if(flags & KPDUPFDG) {
197 		fg = up->env->fgrp;
198 		incref(&fg->r);
199 		p->env->fgrp = fg;
200 	}
201 	if(flags & KPDUPENVG) {
202 		eg = up->env->egrp;
203 		incref(&eg->r);
204 		p->env->egrp = eg;
205 	}
206 
207 	p->env->uid = up->env->uid;
208 	p->env->gid = up->env->gid;
209 	kstrdup(&p->env->user, up->env->user);
210 
211 	strcpy(p->text, name);
212 
213 	p->func = func;
214 	p->arg = arg;
215 
216 	lock(&procs.l);
217 	if(procs.tail != nil) {
218 		p->prev = procs.tail;
219 		procs.tail->next = p;
220 	}
221 	else {
222 		procs.head = p;
223 		p->prev = nil;
224 	}
225 	procs.tail = p;
226 	unlock(&procs.l);
227 
228 	if(flags & KPX11){
229 		p->kstack = nil;	/* never freed; also up not defined */
230 		tos = (char*)mallocz(X11STACK, 0) + X11STACK - sizeof(void*);
231 	}else
232 		p->kstack = stackalloc(p, &tos);
233 	pid = rfork_thread(RFPROC|RFMEM|RFNOWAIT, tos, tramp, p);
234 	if(pid < 0)
235 		panic("ourfork");
236 
237 	return pid;
238 
239 }
240 
241 void
242 oshostintr(Proc *p)
243 {
244 	kill(p->sigid, SIGUSR1);
245 }
246 
247 void
248 osblock(void)
249 {
250 	sigset_t mask;
251 
252 	sigprocmask(SIG_SETMASK, NULL, &mask);
253 	sigdelset(&mask, SIGUSR2);
254 	sigsuspend(&mask);
255 }
256 
257 void
258 osready(Proc *p)
259 {
260 	if(kill(p->sigid, SIGUSR2) < 0)
261 		fprint(2, "emu: osready failed: pid %d: %s\n", p->sigid, strerror(errno));
262 }
263 
264 void
265 oslongjmp(void *regs, osjmpbuf env, int val)
266 {
267 	USED(regs);
268 	siglongjmp(env, val);
269 }
270 
271 struct termios tinit;
272 
273 static void
274 termset(void)
275 {
276 	struct termios t;
277 
278 	tcgetattr(0, &t);
279 	tinit = t;
280 	t.c_lflag &= ~(ICANON|ECHO|ISIG);
281 	t.c_cc[VMIN] = 1;
282 	t.c_cc[VTIME] = 0;
283 	tcsetattr(0, TCSANOW, &t);
284 }
285 
286 static void
287 termrestore(void)
288 {
289 	tcsetattr(0, TCSANOW, &tinit);
290 }
291 
292 void
293 cleanexit(int x)
294 {
295 	USED(x);
296 
297 	if(up->intwait) {
298 		up->intwait = 0;
299 		return;
300 	}
301 
302 	if(dflag == 0)
303 		termrestore();
304 
305 	kill(0, SIGKILL);
306 	exit(0);
307 }
308 
309 void
310 osreboot(char *file, char **argv)
311 {
312 	if(dflag == 0)
313 		termrestore();
314 	execvp(file, argv);
315 	panic("reboot failure");
316 }
317 
318 int gidnobody= -1, uidnobody= -1;
319 
320 void
321 getnobody()
322 {
323 	struct passwd *pwd;
324 
325 	if(pwd = getpwnam("nobody")) {
326 		uidnobody = pwd->pw_uid;
327 		gidnobody = pwd->pw_gid;
328 	}
329 }
330 
331 void
332 libinit(char *imod)
333 {
334 	struct passwd *pw;
335 	Proc *p;
336 	void *tos;
337 	char sys[64];
338 
339 	setsid();
340 
341 	gethostname(sys, sizeof(sys));
342 	kstrdup(&ossysname, sys);
343 	getnobody();
344 
345 	if(dflag == 0)
346 		termset();
347 
348 	setsigs();
349 
350 	p = newproc();
351 	p->kstack = stackalloc(p, &tos);
352 
353 	pw = getpwuid(getuid());
354 	if(pw != nil)
355 		kstrdup(&eve, pw->pw_name);
356 	else
357 		print("cannot getpwuid\n");
358 
359 	p->env->uid = getuid();
360 	p->env->gid = getgid();
361 
362 	executeonnewstack(tos, emuinit, imod);
363 }
364 
365 int
366 readkbd(void)
367 {
368 	int n;
369 	char buf[1];
370 
371 	n = read(0, buf, sizeof(buf));
372 	if(n < 0)
373 		print("keyboard close (n=%d, %s)\n", n, strerror(errno));
374 	if(n <= 0)
375 		pexit("keyboard thread", 0);
376 
377 	switch(buf[0]) {
378 	case '\r':
379 		buf[0] = '\n';
380 		break;
381 	case DELETE:
382 		cleanexit(0);
383 		break;
384 	}
385 	return buf[0];
386 }
387 
388 /*
389  * Return an abitrary millisecond clock time
390  */
391 long
392 osmillisec(void)
393 {
394 	static long sec0 = 0, usec0;
395 	struct timeval t;
396 
397 	if(gettimeofday(&t,(struct timezone*)0)<0)
398 		return 0;
399 	if(sec0==0) {
400 		sec0 = t.tv_sec;
401 		usec0 = t.tv_usec;
402 	}
403 	return (t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000;
404 }
405 
406 int
407 limbosleep(ulong milsec)
408 {
409 	return osmillisleep(milsec);
410 }
411 
412 /*
413  * Return the time since the epoch in nanoseconds and microseconds
414  * The epoch is defined at 1 Jan 1970
415  */
416 vlong
417 osnsec(void)
418 {
419 	struct timeval t;
420 
421 	gettimeofday(&t, nil);
422 	return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000;
423 }
424 
425 vlong
426 osusectime(void)
427 {
428 	struct timeval t;
429 
430 	gettimeofday(&t, nil);
431 	return (vlong)t.tv_sec * 1000000 + t.tv_usec;
432 }
433 
434 int
435 osmillisleep(ulong milsec)
436 {
437 	struct timespec time;
438 
439 	time.tv_sec = milsec / 1000;
440 	time.tv_nsec = (milsec % 1000) * 1000000;
441 	nanosleep(&time, 0);
442 	return 0;
443 }
444 
445 void
446 osyield(void)
447 {
448 	sched_yield();
449 }
450 
451 void
452 ospause(void)
453 {
454 	for(;;)
455 		pause();
456 }
457 
458 void
459 oslopri(void)
460 {
461 	setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS,0)+4);
462 }
463 
464 static struct {
465 	Lock l;
466 	void *free;
467 } stacklist;
468 
469 static void
470 _stackfree(void *stack)
471 {
472 	*((void **)stack) = stacklist.free;
473 	stacklist.free = stack;
474 }
475 
476 static void
477 stackfreeandexit(void *stack)
478 {
479 	lock(&stacklist.l);
480 	_stackfree(stack);
481 	unlockandexit(&stacklist.l.val);
482 }
483 
484 static void *
485 stackalloc(Proc *p, void **tos)
486 {
487 	void *rv;
488 	lock(&stacklist.l);
489 	if (stacklist.free == 0) {
490 		int x;
491 		/*
492 		 * obtain some more by using sbrk()
493 		 */
494 		void *more = sbrk(KSTACK * (NSTACKSPERALLOC + 1));
495 		if (more == 0)
496 			panic("stackalloc: no more stacks");
497 		/*
498 		 * align to KSTACK
499 		 */
500 		more = (void *)((((unsigned long)more) + (KSTACK - 1)) & ~(KSTACK - 1));
501 		/*
502 		 * free all the new stacks onto the freelist
503 		 */
504 		for (x = 0; x < NSTACKSPERALLOC; x++)
505 			_stackfree((char *)more + KSTACK * x);
506 	}
507 	rv = stacklist.free;
508 	stacklist.free = *(void **)rv;
509 	unlock(&stacklist.l);
510 	*tos = rv + KSTACK - sizeof(void*);
511 	*(Proc **)rv = p;
512 	return rv;
513 }
514