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
30enum
31{
32 DELETE = 0x7f,
33 CTRLC = 'C'-'@',
34 NSTACKSPERALLOC = 16,
35 X11STACK= 256*1024
36};
37char *hosttype = "Linux";
38
39extern void unlockandexit(int*);
40extern void executeonnewstack(void*, void (*f)(void*), void*);
41
42static void *stackalloc(Proc *p, void **tos);
43static void stackfreeandexit(void *stack);
44
45typedef sem_t Sem;
46
47extern int dflag;
48
49int gidnobody = -1;
50int uidnobody = -1;
51static struct termios tinit;
52
53void
54pexit(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
96int
97tramp(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
107void
108kproc(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
176static void
177sysfault(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
185static void
186trapILL(int signo, siginfo_t *si, void *a)
187{
188 USED(signo);
189 USED(a);
190 sysfault("illegal instruction pc=", si->si_addr);
191}
192
193static int
194isnilref(siginfo_t *si)
195{
196 return si != 0 && (si->si_addr == (void*)~(uintptr_t)0 || (uintptr_t)si->si_addr < 512);
197}
198
199static void
200trapmemref(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
211static void
212trapFPE(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
222static void
223trapUSR1(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 */
240void
241oshostintr(Proc *p)
242{
243 kill(p->sigid, SIGUSR1);
244}
245
246void
247osblock(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
256void
257osready(Proc *p)
258{
259 sem_post(p->os);
260}
261
262void
263oslongjmp(void *regs, osjmpbuf env, int val)
264{
265 USED(regs);
266 siglongjmp(env, val);
267}
268
269static void
270termset(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
282static void
283termrestore(void)
284{
285 tcsetattr(0, TCSANOW, &tinit);
286}
287
288void
289cleanexit(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
305void
306osreboot(char *file, char **argv)
307{
308 if(dflag == 0)
309 termrestore();
310 execvp(file, argv);
311 error("reboot failure");
312}
313
314void
315libinit(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
380int
381readkbd(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 */
409long
410osmillisec(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 */
429vlong
430osnsec(void)
431{
432 struct timeval t;
433
434 gettimeofday(&t, nil);
435 return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000;
436}
437
438vlong
439osusectime(void)
440{
441 struct timeval t;
442
443 gettimeofday(&t, nil);
444 return (vlong)t.tv_sec * 1000000 + t.tv_usec;
445}
446
447int
448osmillisleep(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
458int
459limbosleep(ulong milsec)
460{
461 return osmillisleep(milsec);
462}
463
464void
465osyield(void)
466{
467 sched_yield();
468}
469
470void
471ospause(void)
472{
473 for(;;)
474 pause();
475}
476
477void
478oslopri(void)
479{
480 setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS,0)+4);
481}
482
483static struct {
484 Lock l;
485 void *free;
486} stacklist;
487
488static void
489_stackfree(void *stack)
490{
491 *((void **)stack) = stacklist.free;
492 stacklist.free = stack;
493}
494
495static void
496stackfreeandexit(void *stack)
497{
498 lock(&stacklist.l);
499 _stackfree(stack);
500 unlockandexit(&stacklist.l.val);
501}
502
503static void *
504stackalloc(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
14typedef struct Osdep Osdep;
15struct Osdep {
16 sem_t sem;
17 pthread_t self;
18};
19
20static pthread_key_t prdakey;
21
22extern int dflag;
23
24Proc*
25getup(void)
26{
27 return pthread_getspecific(prdakey);
28}
29
30void
31pexit(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
73static void*
74tramp(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
89void
90kproc(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 */
162void
163oshostintr(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
172void
173osblock(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
182void
183osready(Proc *p)
184{
185 Osdep *os;
186
187 os = p->os;
188 sem_post(&os->sem);
189}
190
191void
192kprocinit(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
200void
201osyield(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
208void
209ospause(void)
210{
211 /* main just wants this thread to go away */
212 pthread_exit(0);
213}
214
215void
216oslopri(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)"