Charles.Forsyth20061220965a0ca19 years agoHistory
647 lines · 12.0 KB · C
RawDownload
/* * Loosely based on FreeBSD/os.c and Solaris/os.c * Copyright © 1998, 1999 Lucent Technologies Inc.  All rights reserved. * Revisions Copyright © 1999, 2000 Vita Nuova Limited.  All rights reserved. * Revisions Copyright © 2002, 2003 Corpus Callosum Corporation.  All rights reserved. */ #include	"dat.h"#include	"fns.h"#include	"error.h" #undef _POSIX_C_SOURCE #undef getwd #include	<unistd.h>#include        <pthread.h>#include	<time.h>#include	<termios.h>#include	<signal.h>#include	<pwd.h>#include	<sys/resource.h>#include	<sys/time.h> #include 	<sys/socket.h>#include	<sched.h>#include	<errno.h>#include        <sys/ucontext.h> #include <sys/types.h>#include <sys/stat.h> #include <mach/mach_init.h>#include <mach/task.h>#include <mach/vm_map.h> #if defined(__ppc__)#include <architecture/ppc/cframe.h>#endif enum{    DELETE = 0x7F};char *hosttype = "MacOSX";char *cputype = OBJTYPE; static pthread_key_t  prdakey; extern int dflag; Proc *getup(void) {    return (Proc *)pthread_getspecific(prdakey);} /*  Pthread version */voidpexit(char *msg, int t){    Osenv *e;    Proc *p;     USED(t);    USED(msg);     lock(&procs.l);    p = up;    if(p->prev)        p->prev->next = p->next;    else        procs.head = p->next;     if(p->next)        p->next->prev = p->prev;    else        procs.tail = p->prev;    unlock(&procs.l);     if(0)        print("pexit: %s: %s\n", p->text, msg);     e = p->env;    if(e != nil) {        closefgrp(e->fgrp);        closepgrp(e->pgrp);        closeegrp(e->egrp);        closesigs(e->sigs);    }    free(e->user);    free(p->prog);    free(p);    pthread_exit(0);} voidtrapBUS(int signo){    USED(signo);        disfault(nil, "Bus error");} voidtrapUSR1(int signo){    USED(signo);        if(up->type != Interp)      /* Used to unblock pending I/O */        return;    if(up->intwait == 0)        /* Not posted so its a sync error */        disfault(nil, Eintr);	/* Should never happen */        up->intwait = 0;		/* Clear it so the proc can continue */} voidtrapILL(int signo){    USED(signo);    disfault(nil, "Illegal instruction");} /* from geoff collyer's port */voidprintILL(int sig, siginfo_t *siginfo, void *v){    USED(sig);    USED(v);    panic("Illegal instruction with code=%d at address=%x, opcode=%x.\n"        ,siginfo->si_code, siginfo->si_addr,*(char*)siginfo->si_addr);} voidtrapSEGV(int signo){    USED(signo);    disfault(nil, "Segmentation violation");} voidtrapFPE(int signo){    USED(signo);    disfault(nil, "Floating point exception");} static voidsetsigs(void){    struct sigaction act;     memset(&act, 0 , sizeof(act));        /*     * For the correct functioning of devcmd in the     * face of exiting slaves     */    signal(SIGPIPE, SIG_IGN);    if(signal(SIGTERM, SIG_IGN) != SIG_IGN)        signal(SIGTERM, cleanexit);        act.sa_handler=trapUSR1;    sigaction(SIGUSR1, &act, nil);        if(sflag == 0) {        act.sa_handler = trapBUS;        sigaction(SIGBUS, &act, nil);        act.sa_handler = trapILL;        sigaction(SIGILL, &act, nil);        act.sa_handler = trapSEGV;        sigaction(SIGSEGV, &act, nil);        act.sa_handler = trapFPE;        sigaction(SIGFPE, &act, nil);        if(signal(SIGINT, SIG_IGN) != SIG_IGN)            signal(SIGINT, cleanexit);    } else {        act.sa_sigaction = printILL;        act.sa_flags=SA_SIGINFO;        sigaction(SIGILL, &act, nil);    }    }  void *tramp(void *arg){    Proc *p = arg;    p->sigid = (int)pthread_self();    if(pthread_setspecific(prdakey, arg)) {        print("set specific data failed in tramp\n");        pthread_exit(0);    }    p->func(p->arg);    pexit("{Tramp}", 0);    return NULL;} intkproc(char *name, void (*func)(void*), void *arg, int flags){    pthread_t thread;    Proc *p;    Pgrp *pg;    Fgrp *fg;    Egrp *eg;        pthread_attr_t attr;     p = newproc();    if(p == nil)        panic("kproc: no memory");        if(flags & KPDUPPG) {        pg = up->env->pgrp;        incref(&pg->r);        p->env->pgrp = pg;    }    if(flags & KPDUPFDG) {        fg = up->env->fgrp;        incref(&fg->r);        p->env->fgrp = fg;    }    if(flags & KPDUPENVG) {        eg = up->env->egrp;        incref(&eg->r);        p->env->egrp = eg;    }     p->env->uid = up->env->uid;    p->env->gid = up->env->gid;    kstrdup(&p->env->user, up->env->user);     strcpy(p->text, name);     p->func = func;    p->arg = arg;     lock(&procs.l);    if(procs.tail != nil) {        p->prev = procs.tail;        procs.tail->next = p;    } else {        procs.head = p;        p->prev = nil;    }    procs.tail = p;    unlock(&procs.l);        up->kid = p;        if((pthread_attr_init(&attr))== -1)        panic("pthread_attr_init failed");     errno=0;    pthread_attr_setschedpolicy(&attr,SCHED_OTHER);    if(errno)        panic("pthread_attr_setschedpolicy failed");     pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);     if(pthread_create(&thread, &attr, tramp, p))        panic("thr_create failed\n");    pthread_attr_destroy(&attr);            return (int)thread;} intsegflush(void *va, ulong len){    kern_return_t   err;    vm_machine_attribute_val_t value = MATTR_VAL_ICACHE_FLUSH;        err = vm_machine_attribute( (vm_map_t)mach_task_self(),                                (vm_address_t)va,                                (vm_size_t)len,                                MATTR_CACHE,                                &value);    if (err != KERN_SUCCESS) {        print("segflush: failure (%d) address %lud\n", err, va);            }    return (int)err;} /* from geoff collyer's portinvalidate instruction cache and write back data cache from a to a+n-1,at least. voidsegflush(void *a, ulong n){    ulong *p;        // paranoia, flush the world    __asm__("isync\n\t"            "eieio\n\t"            : // no output            :            );    // cache blocks are often eight words (32 bytes) long, sometimes 16 bytes.    // need to determine it dynamically?    for (p = (ulong *)((ulong)a & ~3UL); (char *)p < (char *)a + n; p++)        __asm__("dcbst	0,%0\n\t"	// not dcbf, which writes back, then invalidates            "icbi	0,%0\n\t"            : // no output            : "ar" (p)            );    __asm__("isync\n\t"            "eieio\n\t"            : // no output            :            );}*/ voidoshostintr(Proc *p){    pthread_kill((pthread_t)p->sigid, SIGUSR1);} static ulong erendezvous(void*, ulong); voidosblock(void){    erendezvous(up, 0);} voidosready(Proc *p){    erendezvous(p, 0);} voidoslongjmp(void *regs, osjmpbuf env, int val){    USED(regs);    siglongjmp(env, val);} struct termios tinit; static voidtermset(void){    struct termios t;     tcgetattr(0, &t);    tinit = t;    t.c_lflag &= ~(ICANON|ECHO|ISIG);    t.c_cc[VMIN] = 1;    t.c_cc[VTIME] = 0;    tcsetattr(0, TCSANOW, &t);}     static voidtermrestore(void){    tcsetattr(0, TCSANOW, &tinit);}  voidcleanexit(int x){    USED(x);        if(up->intwait) {        up->intwait = 0;        return;    }        if(dflag == 0)        termrestore();        exit(0);    } voidosreboot(char *file, char **argv){    if(dflag == 0)        termrestore();    execvp(file, argv);    panic("reboot failure");} int gidnobody= -1, uidnobody= -1; voidgetnobody(){    struct passwd *pwd;        if((pwd = getpwnam("nobody"))) {        uidnobody = pwd->pw_uid;        gidnobody = pwd->pw_gid;    }} /* Pthread version */static	pthread_mutex_t rendezvouslock;static	pthread_mutexattr_t	*pthread_mutexattr_default = NULL; voidlibinit(char *imod){    struct passwd *pw;    Proc *p;    char sys[64];     setsid();            // setup personality    gethostname(sys, sizeof(sys));    kstrdup(&ossysname, sys);    getnobody();        if(dflag == 0)        termset();     setsigs();     if(pthread_mutex_init(&rendezvouslock, pthread_mutexattr_default))         panic("pthread_mutex_init");     if(pthread_key_create(&prdakey,NULL))        print("key_create failed\n");        p = newproc();    if(pthread_setspecific(prdakey, p))        panic("set specific thread data failed\n");        pw = getpwuid(getuid());    if(pw != nil)        kstrdup(&eve, pw->pw_name);    else        print("cannot getpwuid\n");        up->env->uid = getuid();    up->env->gid = getgid();     emuinit(imod);} intreadkbd(void){    int n;    char buf[1];        n = read(0, buf, sizeof(buf));    if(n < 0)        print("keyboard close (n=%d, %s)\n", n, strerror(errno));    if(n <= 0)        pexit("keyboard thread", 0);        switch(buf[0]) {        case '\r':            buf[0] = '\n';            break;        case DELETE:            cleanexit(0);            break;    }    return buf[0];} enum{    NHLOG	= 7,    NHASH	= (1<<NHLOG)}; typedef struct Tag Tag;struct Tag{    void*	tag;    ulong	val;    pthread_cond_t cv;    Tag*	next;}; static	Tag*	ht[NHASH];static	Tag*	ft;//static	Lock	hlock; static ulongerendezvous(void *tag, ulong value){    int h;    ulong rval;    Tag *t, **l, *f;        h = (ulong)tag & (NHASH-1); //    lock(&hlock);    pthread_mutex_lock(&rendezvouslock);

Lines 1–500 of 647.