History

20110301-1941

forsyth committed 15 years ago

Commit 37650521 parent 364cbe53 files · +759 −1Browse files

Unified · Split

3 files
  1. emu/Linux/osp.c +532 −0
  2. emu/port/kproc-pthreads.c +226 −0
  3. include/version.h +1 −1
emu/Linux/osp.c+532−0
@@ -0,0 +1,532 @@
1+#include <sys/types.h>
2+#include <time.h>
3+#include <termios.h>
4+#include <signal.h>
5+#include <pwd.h>
6+#include <sched.h>
7+#include <sys/resource.h>
8+#include <sys/wait.h>
9+#include <sys/time.h>
10+
11+#include <stdint.h>
12+
13+#include "dat.h"
14+#include "fns.h"
15+#include "error.h"
16+#include <fpuctl.h>
17+
18+#include <semaphore.h>
19+
20+#include <raise.h>
21+
22+/* glibc 2.3.3-NTPL messes up getpid() by trying to cache the result, so we'll do it ourselves */
23+#include <sys/syscall.h>
24+#define getpid() syscall(SYS_getpid)
25+
26+/* temporarily suppress CLONE_PTRACE so it works on broken Linux kernels */
27+#undef CLONE_PTRACE
28+#define CLONE_PTRACE 0
29+
30+enum
31+{
32+ DELETE = 0x7f,
33+ CTRLC = 'C'-'@',
34+ NSTACKSPERALLOC = 16,
35+ X11STACK= 256*1024
36+};
37+char *hosttype = "Linux";
38+
39+extern void unlockandexit(int*);
40+extern void executeonnewstack(void*, void (*f)(void*), void*);
41+
42+static void *stackalloc(Proc *p, void **tos);
43+static void stackfreeandexit(void *stack);
44+
45+typedef sem_t Sem;
46+
47+extern int dflag;
48+
49+int gidnobody = -1;
50+int uidnobody = -1;
51+static struct termios tinit;
52+
53+void
54+pexit(char *msg, int t)
55+{
56+ Osenv *e;
57+ Proc *p;
58+ Sem *sem;
59+ void *kstack;
60+
61+ lock(&procs.l);
62+ p = up;
63+ if(p->prev)
64+ p->prev->next = p->next;
65+ else
66+ procs.head = p->next;
67+
68+ if(p->next)
69+ p->next->prev = p->prev;
70+ else
71+ procs.tail = p->prev;
72+ unlock(&procs.l);
73+
74+ if(0)
75+ print("pexit: %s: %s\n", p->text, msg);
76+
77+ e = p->env;
78+ if(e != nil) {
79+ closefgrp(e->fgrp);
80+ closepgrp(e->pgrp);
81+ closeegrp(e->egrp);
82+ closesigs(e->sigs);
83+ free(e->user);
84+ }
85+ kstack = p->kstack;
86+ free(p->prog);
87+ sem = p->os;
88+ if(sem != nil)
89+ sem_destroy(sem);
90+ free(p->os);
91+ free(p);
92+ if(kstack != nil)
93+ stackfreeandexit(kstack);
94+}
95+
96+int
97+tramp(void *arg)
98+{
99+ Proc *p;
100+ p = arg;
101+ p->pid = p->sigid = getpid();
102+ (*p->func)(p->arg);
103+ pexit("{Tramp}", 0);
104+ return 0; /* not reached */
105+}
106+
107+void
108+kproc(char *name, void (*func)(void*), void *arg, int flags)
109+{
110+ Proc *p;
111+ Pgrp *pg;
112+ Fgrp *fg;
113+ Egrp *eg;
114+ void *tos;
115+ Sem *sem;
116+
117+ p = newproc();
118+ if(0)
119+ print("start %s:%#p\n", name, p);
120+ if(p == nil)
121+ panic("kproc(%s): no memory", name);
122+
123+ sem = malloc(sizeof(*sem));
124+ if(sem == nil)
125+ panic("can't allocate semaphore");
126+ sem_init(sem, 0, 0);
127+ p->os = sem;
128+
129+ if(flags & KPDUPPG) {
130+ pg = up->env->pgrp;
131+ incref(&pg->r);
132+ p->env->pgrp = pg;
133+ }
134+ if(flags & KPDUPFDG) {
135+ fg = up->env->fgrp;
136+ incref(&fg->r);
137+ p->env->fgrp = fg;
138+ }
139+ if(flags & KPDUPENVG) {
140+ eg = up->env->egrp;
141+ incref(&eg->r);
142+ p->env->egrp = eg;
143+ }
144+
145+ p->env->uid = up->env->uid;
146+ p->env->gid = up->env->gid;
147+ kstrdup(&p->env->user, up->env->user);
148+
149+ strcpy(p->text, name);
150+
151+ p->func = func;
152+ p->arg = arg;
153+
154+ if(flags & KPX11){
155+ p->kstack = nil; /* never freed; also up not defined */
156+ tos = (char*)mallocz(X11STACK, 0) + X11STACK - sizeof(vlong);
157+ }else
158+ p->kstack = stackalloc(p, &tos);
159+
160+ lock(&procs.l);
161+ if(procs.tail != nil) {
162+ p->prev = procs.tail;
163+ procs.tail->next = p;
164+ }
165+ else {
166+ procs.head = p;
167+ p->prev = nil;
168+ }
169+ procs.tail = p;
170+ unlock(&procs.l);
171+
172+ if(clone(tramp, tos, CLONE_PTRACE|CLONE_VM|CLONE_FS|CLONE_FILES|SIGCHLD, p, nil, nil, nil) <= 0)
173+ panic("kproc: clone failed");
174+}
175+
176+static void
177+sysfault(char *what, void *addr)
178+{
179+ char buf[64];
180+
181+ snprint(buf, sizeof(buf), "sys: %s%#p", what, addr);
182+ disfault(nil, buf);
183+}
184+
185+static void
186+trapILL(int signo, siginfo_t *si, void *a)
187+{
188+ USED(signo);
189+ USED(a);
190+ sysfault("illegal instruction pc=", si->si_addr);
191+}
192+
193+static int
194+isnilref(siginfo_t *si)
195+{
196+ return si != 0 && (si->si_addr == (void*)~(uintptr_t)0 || (uintptr_t)si->si_addr < 512);
197+}
198+
199+static void
200+trapmemref(int signo, siginfo_t *si, void *a)
201+{
202+ USED(a); /* ucontext_t*, could fetch pc in machine-dependent way */
203+ if(isnilref(si))
204+ disfault(nil, exNilref);
205+ else if(signo == SIGBUS)
206+ sysfault("bad address addr=", si->si_addr); /* eg, misaligned */
207+ else
208+ sysfault("segmentation violation addr=", si->si_addr);
209+}
210+
211+static void
212+trapFPE(int signo, siginfo_t *si, void *a)
213+{
214+ char buf[64];
215+
216+ USED(signo);
217+ USED(a);
218+ snprint(buf, sizeof(buf), "sys: fp: exception status=%.4lux pc=%#p", getfsr(), si->si_addr);
219+ disfault(nil, buf);
220+}
221+
222+static void
223+trapUSR1(int signo)
224+{
225+ int intwait;
226+
227+ USED(signo);
228+
229+ intwait = up->intwait;
230+ up->intwait = 0; /* clear it to let proc continue in osleave */
231+
232+ if(up->type != Interp) /* Used to unblock pending I/O */
233+ return;
234+
235+ if(intwait == 0) /* Not posted so it's a sync error */
236+ disfault(nil, Eintr); /* Should never happen */
237+}
238+
239+/* called to wake up kproc blocked on a syscall */
240+void
241+oshostintr(Proc *p)
242+{
243+ kill(p->sigid, SIGUSR1);
244+}
245+
246+void
247+osblock(void)
248+{
249+ Sem *sem;
250+
251+ sem = up->os;
252+ while(sem_wait(sem))
253+ {} /* retry on signals (which shouldn't happen) */
254+}
255+
256+void
257+osready(Proc *p)
258+{
259+ sem_post(p->os);
260+}
261+
262+void
263+oslongjmp(void *regs, osjmpbuf env, int val)
264+{
265+ USED(regs);
266+ siglongjmp(env, val);
267+}
268+
269+static void
270+termset(void)
271+{
272+ struct termios t;
273+
274+ tcgetattr(0, &t);
275+ tinit = t;
276+ t.c_lflag &= ~(ICANON|ECHO|ISIG);
277+ t.c_cc[VMIN] = 1;
278+ t.c_cc[VTIME] = 0;
279+ tcsetattr(0, TCSANOW, &t);
280+}
281+
282+static void
283+termrestore(void)
284+{
285+ tcsetattr(0, TCSANOW, &tinit);
286+}
287+
288+void
289+cleanexit(int x)
290+{
291+ USED(x);
292+
293+ if(up->intwait) {
294+ up->intwait = 0;
295+ return;
296+ }
297+
298+ if(dflag == 0)
299+ termrestore();
300+
301+ kill(0, SIGKILL);
302+ exit(0);
303+}
304+
305+void
306+osreboot(char *file, char **argv)
307+{
308+ if(dflag == 0)
309+ termrestore();
310+ execvp(file, argv);
311+ error("reboot failure");
312+}
313+
314+void
315+libinit(char *imod)
316+{
317+ struct sigaction act;
318+ struct passwd *pw;
319+ Proc *p;
320+ void *tos;
321+ char sys[64];
322+
323+ setsid();
324+
325+ gethostname(sys, sizeof(sys));
326+ kstrdup(&ossysname, sys);
327+ pw = getpwnam("nobody");
328+ if(pw != nil) {
329+ uidnobody = pw->pw_uid;
330+ gidnobody = pw->pw_gid;
331+ }
332+
333+ if(dflag == 0)
334+ termset();
335+
336+ memset(&act, 0, sizeof(act));
337+ act.sa_handler = trapUSR1;
338+ sigaction(SIGUSR1, &act, nil);
339+
340+ act.sa_handler = SIG_IGN;
341+ sigaction(SIGCHLD, &act, nil);
342+
343+ /*
344+ * For the correct functioning of devcmd in the
345+ * face of exiting slaves
346+ */
347+ signal(SIGPIPE, SIG_IGN);
348+ if(signal(SIGTERM, SIG_IGN) != SIG_IGN)
349+ signal(SIGTERM, cleanexit);
350+ if(signal(SIGINT, SIG_IGN) != SIG_IGN)
351+ signal(SIGINT, cleanexit);
352+
353+ if(sflag == 0) {
354+ act.sa_flags = SA_SIGINFO;
355+ act.sa_sigaction = trapILL;
356+ sigaction(SIGILL, &act, nil);
357+ act.sa_sigaction = trapFPE;
358+ sigaction(SIGFPE, &act, nil);
359+ act.sa_sigaction = trapmemref;
360+ sigaction(SIGBUS, &act, nil);
361+ sigaction(SIGSEGV, &act, nil);
362+ act.sa_flags &= ~SA_SIGINFO;
363+ }
364+
365+ p = newproc();
366+ p->kstack = stackalloc(p, &tos);
367+
368+ pw = getpwuid(getuid());
369+ if(pw != nil)
370+ kstrdup(&eve, pw->pw_name);
371+ else
372+ print("cannot getpwuid\n");
373+
374+ p->env->uid = getuid();
375+ p->env->gid = getgid();
376+
377+ executeonnewstack(tos, emuinit, imod);
378+}
379+
380+int
381+readkbd(void)
382+{
383+ int n;
384+ char buf[1];
385+
386+ n = read(0, buf, sizeof(buf));
387+ if(n < 0)
388+ print("keyboard close (n=%d, %s)\n", n, strerror(errno));
389+ if(n <= 0)
390+ pexit("keyboard thread", 0);
391+
392+ switch(buf[0]) {
393+ case '\r':
394+ buf[0] = '\n';
395+ break;
396+ case DELETE:
397+ buf[0] = 'H' - '@';
398+ break;
399+ case CTRLC:
400+ cleanexit(0);
401+ break;
402+ }
403+ return buf[0];
404+}
405+
406+/*
407+ * Return an abitrary millisecond clock time
408+ */
409+long
410+osmillisec(void)
411+{
412+ static long sec0 = 0, usec0;
413+ struct timeval t;
414+
415+ if(gettimeofday(&t,(struct timezone*)0)<0)
416+ return 0;
417+
418+ if(sec0 == 0) {
419+ sec0 = t.tv_sec;
420+ usec0 = t.tv_usec;
421+ }
422+ return (t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000;
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, NULL);
455+ return 0;
456+}
457+
458+int
459+limbosleep(ulong milsec)
460+{
461+ return osmillisleep(milsec);
462+}
463+
464+void
465+osyield(void)
466+{
467+ sched_yield();
468+}
469+
470+void
471+ospause(void)
472+{
473+ for(;;)
474+ pause();
475+}
476+
477+void
478+oslopri(void)
479+{
480+ setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS,0)+4);
481+}
482+
483+static struct {
484+ Lock l;
485+ void *free;
486+} stacklist;
487+
488+static void
489+_stackfree(void *stack)
490+{
491+ *((void **)stack) = stacklist.free;
492+ stacklist.free = stack;
493+}
494+
495+static void
496+stackfreeandexit(void *stack)
497+{
498+ lock(&stacklist.l);
499+ _stackfree(stack);
500+ unlockandexit(&stacklist.l.val);
501+}
502+
503+static void *
504+stackalloc(Proc *p, void **tos)
505+{
506+ void *rv;
507+ lock(&stacklist.l);
508+ if (stacklist.free == 0) {
509+ int x;
510+ /*
511+ * obtain some more by using sbrk()
512+ */
513+ void *more = sbrk(KSTACK * (NSTACKSPERALLOC + 1));
514+ if (more == 0)
515+ panic("stackalloc: no more stacks");
516+ /*
517+ * align to KSTACK
518+ */
519+ more = (void *)((((unsigned long)more) + (KSTACK - 1)) & ~(KSTACK - 1));
520+ /*
521+ * free all the new stacks onto the freelist
522+ */
523+ for (x = 0; x < NSTACKSPERALLOC; x++)
524+ _stackfree((char *)more + KSTACK * x);
525+ }
526+ rv = stacklist.free;
527+ stacklist.free = *(void **)rv;
528+ unlock(&stacklist.l);
529+ *tos = rv + KSTACK - sizeof(vlong);
530+ *(Proc **)rv = p;
531+ return rv;
532+}
emu/port/kproc-pthreads.c+226−0
@@ -0,0 +1,226 @@
1+#include "dat.h"
2+#include "fns.h"
3+#include "error.h"
4+
5+#undef _POSIX_C_SOURCE
6+#undef getwd
7+
8+#include <unistd.h>
9+#include <signal.h>
10+#include <pthread.h>
11+#include <errno.h>
12+#include <semaphore.h>
13+
14+typedef struct Osdep Osdep;
15+struct Osdep {
16+ sem_t sem;
17+ pthread_t self;
18+};
19+
20+static pthread_key_t prdakey;
21+
22+extern int dflag;
23+
24+Proc*
25+getup(void)
26+{
27+ return pthread_getspecific(prdakey);
28+}
29+
30+void
31+pexit(char *msg, int t)
32+{
33+ Osenv *e;
34+ Proc *p;
35+ Osdep *os;
36+
37+ USED(t);
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(p->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", p->text, msg);
54+
55+ e = p->env;
56+ if(e != nil) {
57+ closefgrp(e->fgrp);
58+ closepgrp(e->pgrp);
59+ closeegrp(e->egrp);
60+ closesigs(e->sigs);
61+ free(e->user);
62+ }
63+ free(p->prog);
64+ os = p->os;
65+ if(os != nil){
66+ sem_destroy(&os->sem);
67+ free(os);
68+ }
69+ free(p);
70+ pthread_exit(0);
71+}
72+
73+static void*
74+tramp(void *arg)
75+{
76+ Proc *p;
77+ Osdep *os;
78+
79+ p = arg;
80+ os = p->os;
81+ os->self = pthread_self();
82+ if(pthread_setspecific(prdakey, arg))
83+ panic("set specific data failed in tramp\n");
84+ p->func(p->arg);
85+ pexit("{Tramp}", 0);
86+ return nil;
87+}
88+
89+void
90+kproc(char *name, void (*func)(void*), void *arg, int flags)
91+{
92+ pthread_t thread;
93+ Proc *p;
94+ Pgrp *pg;
95+ Fgrp *fg;
96+ Egrp *eg;
97+ pthread_attr_t attr;
98+ Osdep *os;
99+
100+ p = newproc();
101+ if(p == nil)
102+ panic("kproc: no memory");
103+
104+ os = malloc(sizeof(*os));
105+ if(os == nil)
106+ panic("kproc: no memory");
107+ os->self = 0; /* set by tramp */
108+ sem_init(&os->sem, 0, 0);
109+ p->os = os;
110+
111+ if(flags & KPDUPPG) {
112+ pg = up->env->pgrp;
113+ incref(&pg->r);
114+ p->env->pgrp = pg;
115+ }
116+ if(flags & KPDUPFDG) {
117+ fg = up->env->fgrp;
118+ incref(&fg->r);
119+ p->env->fgrp = fg;
120+ }
121+ if(flags & KPDUPENVG) {
122+ eg = up->env->egrp;
123+ incref(&eg->r);
124+ p->env->egrp = eg;
125+ }
126+
127+ p->env->uid = up->env->uid;
128+ p->env->gid = up->env->gid;
129+ kstrdup(&p->env->user, up->env->user);
130+
131+ strcpy(p->text, name);
132+
133+ p->func = func;
134+ p->arg = arg;
135+
136+ lock(&procs.l);
137+ if(procs.tail != nil) {
138+ p->prev = procs.tail;
139+ procs.tail->next = p;
140+ } else {
141+ procs.head = p;
142+ p->prev = nil;
143+ }
144+ procs.tail = p;
145+ unlock(&procs.l);
146+
147+ memset(&attr, 0, sizeof(attr));
148+ if(pthread_attr_init(&attr) == -1)
149+ panic("pthread_attr_init failed");
150+ if(flags & KPX11)
151+ pthread_attr_setstacksize(&attr, 512*1024); /* could be a parameter */
152+ else if(KSTACK > 0)
153+ pthread_attr_setstacksize(&attr, KSTACK);
154+ pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
155+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
156+ if(pthread_create(&thread, &attr, tramp, p))
157+ panic("thr_create failed\n");
158+ pthread_attr_destroy(&attr);
159+}
160+
161+/* called to wake up kproc blocked on a syscall */
162+void
163+oshostintr(Proc *p)
164+{
165+ Osdep *os;
166+
167+ os = p->os;
168+ if(os != nil && os->self != 0)
169+ pthread_kill(os->self, SIGUSR1);
170+}
171+
172+void
173+osblock(void)
174+{
175+ Osdep *os;
176+
177+ os = up->os;
178+ while(sem_wait(&os->sem))
179+ {} /* retry on signals (which shouldn't happen) */
180+}
181+
182+void
183+osready(Proc *p)
184+{
185+ Osdep *os;
186+
187+ os = p->os;
188+ sem_post(&os->sem);
189+}
190+
191+void
192+kprocinit(Proc *p)
193+{
194+ if(pthread_key_create(&prdakey, NULL))
195+ panic("key_create failed");
196+ if(pthread_setspecific(prdakey, p))
197+ panic("set specific thread data failed");
198+}
199+
200+void
201+osyield(void)
202+{
203+// pthread_yield_np();
204+ /* define pthread_yield to be sched_yield or pthread_yield_np if required */
205+ pthread_yield();
206+}
207+
208+void
209+ospause(void)
210+{
211+ /* main just wants this thread to go away */
212+ pthread_exit(0);
213+}
214+
215+void
216+oslopri(void)
217+{
218+ struct sched_param param;
219+ int policy;
220+ pthread_t self;
221+
222+ self = pthread_self();
223+ pthread_getschedparam(self, &policy, &param);
224+ param.sched_priority = sched_get_priority_min(policy);
225+ pthread_setschedparam(self, policy, &param);
226+}
include/version.h+1−1
@@ -1 +1 @@
1−#define VERSION "Fourth Edition (20110225)"
1+#define VERSION "Fourth Edition (20110301)"