summaryrefslogtreecommitdiff
path: root/emu/Hp/os.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /emu/Hp/os.c
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'emu/Hp/os.c')
-rw-r--r--emu/Hp/os.c591
1 files changed, 591 insertions, 0 deletions
diff --git a/emu/Hp/os.c b/emu/Hp/os.c
new file mode 100644
index 00000000..a371ac50
--- /dev/null
+++ b/emu/Hp/os.c
@@ -0,0 +1,591 @@
+#include <pthread.h>
+#include <signal.h>
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+#include <sys/socket.h>
+#include <time.h>
+#include <sys/time.h>
+#include <termios.h>
+#include <pwd.h>
+#include <errno.h>
+
+enum
+{
+ BUNCHES = 5000,
+ DELETE = 0x7F
+};
+char *hosttype = "Hp";
+
+
+static pthread_key_t prdakey;
+
+extern int dflag;
+
+Lock mulock = {1, 0};
+
+ulong
+_tas(ulong *l)
+{
+ ulong v;
+
+ while(!(mutexlock(&mulock)))
+ pthread_yield();
+
+ v = *l;
+ if(v == 0)
+ *l = 1;
+ mulock.key = 1;
+ return v;
+}
+
+static ulong erendezvous(void*, ulong);
+
+
+void
+osblock(void)
+{
+ erendezvous(up, 0);
+}
+
+void
+osready(Proc *p)
+{
+ erendezvous(p, 0);
+}
+
+
+void
+pexit(char *msg, int t)
+{
+ Osenv *e;
+
+ lock(&procs.l);
+ if(up->prev)
+ up->prev->next = up->next;
+ else
+ procs.head = up->next;
+
+ if(up->next)
+ up->next->prev = up->prev;
+ else
+ procs.tail = up->prev;
+ unlock(&procs.l);
+
+ e = up->env;
+ if(e != nil) {
+ closefgrp(e->fgrp);
+ closepgrp(e->pgrp);
+ closeegrp(e->egrp);
+ closesigs(e->sigs);
+ }
+ free(up->prog);
+ free(up);
+ pthread_exit(0);
+}
+
+void
+trapBUS(int signo, siginfo_t *info, void *context)
+{
+ if(info)
+ print("trapBUS: signo: %d code: %d addr: %lx\n",
+ info->si_signo, info->si_code, info->si_addr);
+ else
+ print("trapBUS: no info\n");
+ disfault(nil, "Bus error");
+}
+
+void
+trapUSR1(void)
+{
+ int intwait;
+
+ intwait = up->intwait;
+ up->intwait = 0; /* clear it to let proc continue in osleave */
+
+ if(up->type != Interp) /* Used to unblock pending I/O */
+ return;
+
+ if(intwait == 0) /* Not posted so it's a sync error */
+ disfault(nil, Eintr); /* Should never happen */
+}
+
+void
+trapILL(void)
+{
+ disfault(nil, "Illegal instruction");
+}
+
+void
+trapSEGV(void)
+{
+ disfault(nil, "Segmentation violation");
+}
+
+sigset_t set;
+setsigs()
+{
+ struct sigaction act;
+
+ memset(&act, 0 , sizeof(act));
+ sigemptyset(&set);
+
+ act.sa_handler=SIG_IGN;
+ if(sigaction(SIGPIPE, &act, nil))
+ panic("can't ignore sig pipe");
+
+ if(sigaddset(&set,SIGUSR1)== -1)
+ panic("sigaddset SIGUSR1");
+
+ if(sigaddset(&set,SIGUSR2)== -1)
+ panic("sigaddset SIGUSR2");
+
+ /* For the correct functioning of devcmd in the
+ * face of exiting slaves
+ */
+ if(sflag == 0) {
+ act.sa_handler=trapBUS;
+ act.sa_flags|=SA_SIGINFO;
+ if(sigaction(SIGBUS, &act, nil))
+ panic("sigaction SIGBUS");
+ act.sa_handler=trapILL;
+ if(sigaction(SIGILL, &act, nil))
+ panic("sigaction SIGILL");
+ act.sa_handler=trapSEGV;
+ if(sigaction(SIGSEGV, &act, nil))
+ panic("sigaction SIGSEGV");
+ if(sigaddset(&set,SIGINT)== -1)
+ panic("sigaddset");
+ }
+ if(sigprocmask(SIG_BLOCK,&set,nil)!= 0)
+ panic("sigprocmask");
+}
+
+static void *
+tramp(void *v)
+{
+ struct Proc *Up;
+ pthread_t thread;
+ struct sigaction oldact;
+
+ setsigs();
+ if(sigaction(SIGBUS, nil, &oldact))
+ panic("sigaction failed");
+ if(oldact.sa_handler!=trapBUS && sflag==0)
+ panic("3rd old act sa_handler");
+
+ if(pthread_setspecific(prdakey,v)) {
+ print("set specific data failed in tramp\n");
+ pthread_exit(0);
+ }
+ Up = v;
+ thread = pthread_self();
+ Up->sigid = cma_thread_get_unique(&thread);
+ /* attempt to catch signals again */
+ setsigs();
+ Up->func(Up->arg);
+ pexit("", 0);
+}
+
+pthread_t active_threads[BUNCHES]; /* this should be more than enuf */
+
+int
+kproc(char *name, void (*func)(void*), void *arg, int flags)
+{
+ pthread_t thread;
+ pthread_attr_t attr;
+ int id;
+ Proc *p;
+ Pgrp *pg;
+ Fgrp *fg;
+ Egrp *eg;
+ struct sigaction oldact;
+
+ p = newproc();
+
+ 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);
+ if((pthread_attr_create(&attr))== -1)
+ panic("pthread_attr_create failed");
+
+ errno=0;
+ pthread_attr_setsched(&attr,SCHED_OTHER);
+ if(errno)
+ panic("pthread_attr_setsched failed");
+
+ if(pthread_create(&thread, attr, tramp, p))
+ panic("thr_create failed\n");
+ if(sigaction(SIGBUS, nil, &oldact))
+ panic("sigaction failed");
+ if(oldact.sa_handler!=trapBUS && sflag == 0)
+ panic("2nd old act sa_handler");
+
+ if((id=cma_thread_get_unique(&thread))>=BUNCHES)
+ panic("id too big");
+ active_threads[id]=thread;
+ return id;
+}
+
+void
+oshostintr(Proc *p)
+{
+ pthread_cancel(active_threads[p->sigid]);
+}
+
+void
+oslongjmp(void *regs, osjmpbuf env, int val)
+{
+ USED(regs);
+ siglongjmp(env, val);
+}
+
+struct termios tinit;
+
+static void
+termset(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 void
+termrestore(void)
+{
+ tcsetattr(0, TCSANOW, &tinit);
+}
+
+void
+cleanexit(int x)
+{
+ USED(x);
+
+ if(up->intwait) {
+ up->intwait = 0;
+ return;
+ }
+
+ if(dflag == 0)
+ termrestore();
+
+ kill(0, SIGKILL);
+ exit(0);
+}
+
+void
+osreboot(char *file, char **argv)
+{
+ if(dflag == 0)
+ termrestore();
+ execvp(file, argv);
+ panic("reboot failure");
+}
+
+int gidnobody= -1, uidnobody= -1;
+
+void
+getnobody()
+{
+ struct passwd *pwd;
+
+ if(pwd = getpwnam("nobody")) {
+ uidnobody = pwd->pw_uid;
+ gidnobody = pwd->pw_gid;
+ }
+}
+
+static pthread_mutex_t rendezvouslock;
+
+void
+libinit(char *imod)
+{
+ struct passwd *pw;
+ struct Proc *Up;
+ struct sigaction oldact;
+ int ii;
+ int retval;
+ int *pidptr;
+ char sys[64];
+
+ cma_init();
+ setsid();
+ /* mulock.key = 1; */ /* initialize to unlock */
+ if(pthread_mutex_init(&rendezvouslock,pthread_mutexattr_default))
+ panic("pthread_mutex_init");
+
+ gethostname(sys, sizeof(sys));
+ kstrdup(&ossysname, sys);
+ getnobody();
+
+ if(dflag == 0)
+ termset();
+
+ setsigs();
+ if(sigaction(SIGBUS, nil, &oldact)) {
+ panic("sigaction failed");
+ }
+ if(oldact.sa_handler!=trapBUS && sflag == 0)
+ panic("1st old act sa_handler");
+
+ if(pthread_keycreate(&prdakey,NULL))
+ print("keycreate failed\n");
+
+ Up = newproc();
+ if(pthread_setspecific(prdakey,Up))
+ 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);
+}
+
+int
+readkbd(void)
+{
+ int n;
+ char buf[1];
+
+ n = read(0, buf, sizeof(buf));
+ if(n != 1) {
+ print("keyboard close (n=%d, %s)\n", n, strerror(errno));
+ 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;
+ int pid;
+ Tag* hash;
+ Tag* free;
+ pthread_cond_t cv;
+};
+
+static Tag* ht[NHASH];
+static Tag* ft;
+
+static ulong
+erendezvous(void *tag, ulong value)
+{
+ int h;
+ ulong rval;
+ Tag *t, *f, **l;
+ int ii=0;
+
+ h = (ulong)tag & (NHASH-1);
+
+ if(pthread_mutex_lock(&rendezvouslock))
+ panic("pthread_mutex_lock");
+
+ l = &ht[h];
+ for(t = *l; t; t = t->hash) {
+ if(t->tag == tag) {
+ rval = t->val;
+ t->val = value;
+ t->tag = 0;
+ if(pthread_mutex_unlock(&rendezvouslock))
+ panic("pthread_mutex_unlock");
+ if(pthread_cond_signal(&(t->cv)))
+ panic("pthread_cond_signal");
+ return rval;
+ }
+ }
+
+ t = ft;
+ if(t == 0) {
+ t = malloc(sizeof(Tag));
+ if(t == 0)
+ panic("rendezvous: no memory");
+ if(pthread_cond_init(&(t->cv),pthread_condattr_default)) {
+ print("pthread_cond_init (errno: %s) \n", strerror(errno));
+ panic("pthread_cond_init");
+ }
+ } else
+ ft = t->free;
+
+ t->tag = tag;
+ t->val = value;
+ t->hash = *l;
+ *l = t;
+
+ while(t->tag)
+ pthread_cond_wait(&(t->cv),&rendezvouslock);
+
+ rval = t->val;
+ for(f = *l; f; f = f->hash){
+ if(f == t) {
+ *l = f->hash;
+ break;
+ }
+ l = &f->hash;
+ }
+ t->free = ft;
+ ft = t;
+ if(pthread_mutex_unlock(&rendezvouslock))
+ panic("pthread_mutex_unlock");
+
+ return rval;
+}
+
+
+/*
+ * Return an abitrary millisecond clock time
+ */
+long
+osmillisec(void)
+{
+ static long sec0 = 0, usec0;
+ struct timeval t;
+
+ if(gettimeofday(&t,(struct timezone*)0)<0)
+ return(0);
+ if(sec0==0) {
+ sec0 = t.tv_sec;
+ usec0 = t.tv_usec;
+ }
+ return((t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000);
+}
+
+/*
+ * Return the time since the epoch in nanoseconds and microseconds
+ * The epoch is defined at 1 Jan 1970
+ */
+vlong
+osnsec(void)
+{
+ struct timeval t;
+
+ gettimeofday(&t, nil);
+ return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000;
+}
+
+vlong
+osusectime(void)
+{
+ struct timeval t;
+
+ gettimeofday(&t, nil);
+ return (vlong)t.tv_sec * 1000000 + t.tv_usec;
+}
+
+
+int
+osmillisleep(ulong milsec)
+{
+ struct timespec time;
+ time.tv_sec = milsec/1000;
+ time.tv_nsec= (milsec%1000)*1000000;
+ if(pthread_delay_np(&time)== -1)
+ ; /* might be interrupted */
+ return 0;
+}
+
+Proc *
+getup(void)
+{
+ void *vp;
+
+ vp=nil;
+ pthread_getspecific(prdakey,&vp);
+ return(vp);
+}
+
+ulong
+getcallerpc(void *arg)
+{
+ return 0 ;
+}
+
+void
+osyield(void)
+{
+ pthread_yield();
+}
+
+void
+ospause(void)
+{
+ int s;
+
+ for(;;) {
+ switch(s=sigwait(&set)) {
+ case SIGUSR1:
+ trapUSR1();
+ case SIGINT:
+ cleanexit(0);
+ default:
+ print("signal: %d %s\n",s, strerror(errno));
+ panic("sigwait");
+ }
+ }
+}
+
+void
+oslopri(void)
+{
+ /* TO DO */
+}