/* * Posix generic OS implementation for drawterm. */ #include "u.h" #ifndef _XOPEN_SOURCE /* for Apple and OpenBSD; not sure if needed */#define _XOPEN_SOURCE 500#endif #include <pthread.h>#include <time.h>#include <sys/time.h>#include <sys/select.h>#include <signal.h>#include <pwd.h>#include <errno.h> #include "lib.h"#include "dat.h"#include "fns.h" typedef struct Oproc Oproc;struct Oproc{ int nsleep; int nwakeup; pthread_mutex_t mutex; pthread_cond_t cond;}; static pthread_key_t prdakey; Proc*_getproc(void){ void *v; if((v = pthread_getspecific(prdakey)) == nil) panic("cannot getspecific"); return v;} void_setproc(Proc *p){ if(pthread_setspecific(prdakey, p) != 0) panic("cannot setspecific");} voidosinit(void){ if(pthread_key_create(&prdakey, 0)) panic("cannot pthread_key_create");} #undef pipevoidosnewproc(Proc *p){ Oproc *op; pthread_mutexattr_t attr; op = (Oproc*)p->oproc; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); pthread_mutex_init(&op->mutex, &attr); pthread_mutexattr_destroy(&attr); pthread_cond_init(&op->cond, 0);} voidosmsleep(int ms){ struct timeval tv; tv.tv_sec = ms / 1000; tv.tv_usec = (ms % 1000) * 1000; /* micro */ if(select(0, NULL, NULL, NULL, &tv) < 0) panic("select");} voidosyield(void){ sched_yield();} voidoserrstr(void){ char *p; if((p = strerror(errno)) != nil) strecpy(up->errstr, up->errstr+ERRMAX, p); else snprint(up->errstr, ERRMAX, "unix error %d", errno);} voidoserror(void){ oserrstr(); nexterror();} static void* tramp(void*); voidosproc(Proc *p){ pthread_t pid; if(pthread_create(&pid, nil, tramp, p)){ oserrstr(); panic("osproc: %r"); } sched_yield();} static void*tramp(void *vp){ Proc *p; p = vp; if(pthread_setspecific(prdakey, p)) panic("cannot setspecific"); (*p->fn)(p->arg); /* BUG: leaks Proc */ pthread_setspecific(prdakey, 0); panic("exit"); return 0;} voidprocsleep(void){ Proc *p; Oproc *op; p = up; op = (Oproc*)p->oproc; pthread_mutex_lock(&op->mutex); op->nsleep++; while(op->nsleep > op->nwakeup) pthread_cond_wait(&op->cond, &op->mutex); pthread_mutex_unlock(&op->mutex);} voidprocwakeup(Proc *p){ Oproc *op; op = (Oproc*)p->oproc; pthread_mutex_lock(&op->mutex); op->nwakeup++; if(op->nwakeup == op->nsleep) pthread_cond_signal(&op->cond); pthread_mutex_unlock(&op->mutex);} int randfd;#undef openvoidrandominit(void){#ifdef USE_RANDOM srandom(getpid()+fastticks(nil)+ticks());#else if((randfd = open("/dev/urandom", OREAD)) < 0) if((randfd = open("/dev/random", OREAD)) < 0) panic("open /dev/random: %r");#endif} #undef readulongrandomread(void *v, ulong n){#ifdef USE_RANDOM int i; for(i=0; i<n; i++) ((uchar*)v)[i] = random(); return n;#else int m; if((m = read(randfd, v, n)) != n) panic("short read from /dev/random: %d but %d", n, m); return m;#endif} #undef timelongseconds(void){ return time(0);} ulongticks(void){ static long sec0 = 0, usec0; struct timeval t; if(gettimeofday(&t, nil) < 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;} longshowfilewrite(char *a, int n){ error("not implemented"); return -1;}
/*
* Posix generic OS implementation for drawterm.
*/
#include "u.h"
#ifndef _XOPEN_SOURCE /* for Apple and OpenBSD; not sure if needed */
#define _XOPEN_SOURCE 500
#endif
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#include <sys/select.h>
#include <signal.h>
#include <pwd.h>
#include <errno.h>
#include "lib.h"
#include "dat.h"
#include "fns.h"
typedef struct Oproc Oproc;
struct Oproc
{
int nsleep;
int nwakeup;
pthread_mutex_t mutex;
pthread_cond_t cond;
};
static pthread_key_t prdakey;
Proc*
_getproc(void)
{
void *v;
if((v = pthread_getspecific(prdakey)) == nil)
panic("cannot getspecific");
return v;
}
void
_setproc(Proc *p)
{
if(pthread_setspecific(prdakey, p) != 0)
panic("cannot setspecific");
}
void
osinit(void)
{
if(pthread_key_create(&prdakey, 0))
panic("cannot pthread_key_create");
}
#undef pipe
void
osnewproc(Proc *p)
{
Oproc *op;
pthread_mutexattr_t attr;
op = (Oproc*)p->oproc;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
pthread_mutex_init(&op->mutex, &attr);
pthread_mutexattr_destroy(&attr);
pthread_cond_init(&op->cond, 0);
}
void
osmsleep(int ms)
{
struct timeval tv;
tv.tv_sec = ms / 1000;
tv.tv_usec = (ms % 1000) * 1000; /* micro */
if(select(0, NULL, NULL, NULL, &tv) < 0)
panic("select");
}
void
osyield(void)
{
sched_yield();
}
void
oserrstr(void)
{
char *p;
if((p = strerror(errno)) != nil)
strecpy(up->errstr, up->errstr+ERRMAX, p);
else
snprint(up->errstr, ERRMAX, "unix error %d", errno);
}
void
oserror(void)
{
oserrstr();
nexterror();
}
static void* tramp(void*);
void
osproc(Proc *p)
{
pthread_t pid;
if(pthread_create(&pid, nil, tramp, p)){
oserrstr();
panic("osproc: %r");
}
sched_yield();
}
static void*
tramp(void *vp)
{
Proc *p;
p = vp;
if(pthread_setspecific(prdakey, p))
panic("cannot setspecific");
(*p->fn)(p->arg);
/* BUG: leaks Proc */
pthread_setspecific(prdakey, 0);
panic("exit");
return 0;
}
void
procsleep(void)
{
Proc *p;
Oproc *op;
p = up;
op = (Oproc*)p->oproc;
pthread_mutex_lock(&op->mutex);
op->nsleep++;
while(op->nsleep > op->nwakeup)
pthread_cond_wait(&op->cond, &op->mutex);
pthread_mutex_unlock(&op->mutex);
}
void
procwakeup(Proc *p)
{
Oproc *op;
op = (Oproc*)p->oproc;
pthread_mutex_lock(&op->mutex);
op->nwakeup++;
if(op->nwakeup == op->nsleep)
pthread_cond_signal(&op->cond);
pthread_mutex_unlock(&op->mutex);
}
int randfd;
#undef open
void
randominit(void)
{
#ifdef USE_RANDOM
srandom(getpid()+fastticks(nil)+ticks());
#else
if((randfd = open("/dev/urandom", OREAD)) < 0)
if((randfd = open("/dev/random", OREAD)) < 0)
panic("open /dev/random: %r");
#endif
}
#undef read
ulong
randomread(void *v, ulong n)
{
#ifdef USE_RANDOM
int i;
for(i=0; i<n; i++)
((uchar*)v)[i] = random();
return n;
#else
int m;
if((m = read(randfd, v, n)) != n)
panic("short read from /dev/random: %d but %d", n, m);
return m;
#endif
}
#undef time
long
seconds(void)
{
return time(0);
}
ulong
ticks(void)
{
static long sec0 = 0, usec0;
struct timeval t;
if(gettimeofday(&t, nil) < 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;
}
long
showfilewrite(char *a, int n)
{
error("not implemented");
return -1;
}