1 /* 2 * Posix generic OS implementation for drawterm. 3 */ 4 5 #define _XOPEN_SOURCE 500 6 #include <pthread.h> 7 #include <time.h> 8 #include <sys/time.h> 9 #include <signal.h> 10 #include <pwd.h> 11 #include <errno.h> 12 13 #include "u.h" 14 #include "lib.h" 15 #include "dat.h" 16 #include "fns.h" 17 18 typedef struct Oproc Oproc; 19 struct Oproc 20 { 21 int nsleep; 22 int nwakeup; 23 pthread_mutex_t mutex; 24 pthread_cond_t cond; 25 }; 26 27 static pthread_key_t prdakey; 28 29 Proc* 30 _getproc(void) 31 { 32 void *v; 33 34 if((v = pthread_getspecific(prdakey)) == nil) 35 panic("cannot getspecific"); 36 return v; 37 } 38 39 void 40 _setproc(Proc *p) 41 { 42 if(pthread_setspecific(prdakey, p) != 0) 43 panic("cannot setspecific"); 44 } 45 46 void 47 osinit(void) 48 { 49 if(pthread_key_create(&prdakey, 0)) 50 panic("cannot pthread_key_create"); 51 } 52 53 #undef pipe 54 void 55 osnewproc(Proc *p) 56 { 57 Oproc *op; 58 pthread_mutexattr_t attr; 59 60 op = (Oproc*)p->oproc; 61 pthread_mutexattr_init(&attr); 62 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); 63 pthread_mutex_init(&op->mutex, &attr); 64 pthread_mutexattr_destroy(&attr); 65 pthread_cond_init(&op->cond, 0); 66 } 67 68 void 69 osmsleep(int ms) 70 { 71 struct timeval tv; 72 73 tv.tv_sec = ms / 1000; 74 tv.tv_usec = (ms % 1000) * 1000; /* micro */ 75 if(select(0, NULL, NULL, NULL, &tv) < 0) 76 panic("select"); 77 } 78 79 void 80 osyield(void) 81 { 82 sched_yield(); 83 } 84 85 void 86 oserrstr(void) 87 { 88 char *p; 89 90 if((p = strerror(errno)) != nil) 91 strecpy(up->errstr, up->errstr+ERRMAX, p); 92 else 93 snprint(up->errstr, ERRMAX, "unix error %d", errno); 94 } 95 96 void 97 oserror(void) 98 { 99 oserrstr(); 100 nexterror(); 101 } 102 103 static void* tramp(void*); 104 105 void 106 osproc(Proc *p) 107 { 108 pthread_t pid; 109 110 if(pthread_create(&pid, nil, tramp, p)){ 111 oserrstr(); 112 panic("osproc: %r"); 113 } 114 sched_yield(); 115 } 116 117 static void* 118 tramp(void *vp) 119 { 120 Proc *p; 121 122 p = vp; 123 if(pthread_setspecific(prdakey, p)) 124 panic("cannot setspecific"); 125 (*p->fn)(p->arg); 126 /* BUG: leaks Proc */ 127 pthread_setspecific(prdakey, 0); 128 pthread_exit(0); 129 return 0; 130 } 131 132 void 133 procsleep(void) 134 { 135 Proc *p; 136 Oproc *op; 137 138 p = up; 139 op = (Oproc*)p->oproc; 140 pthread_mutex_lock(&op->mutex); 141 op->nsleep++; 142 while(op->nsleep > op->nwakeup) 143 pthread_cond_wait(&op->cond, &op->mutex); 144 pthread_mutex_unlock(&op->mutex); 145 } 146 147 void 148 procwakeup(Proc *p) 149 { 150 Oproc *op; 151 152 op = (Oproc*)p->oproc; 153 pthread_mutex_lock(&op->mutex); 154 op->nwakeup++; 155 if(op->nwakeup == op->nsleep) 156 pthread_cond_signal(&op->cond); 157 pthread_mutex_unlock(&op->mutex); 158 } 159 160 int randfd; 161 #undef open 162 void 163 randominit(void) 164 { 165 #ifdef USE_RANDOM 166 srandom(getpid()+fastticks(nil)+ticks()); 167 #else 168 if((randfd = open("/dev/urandom", OREAD)) < 0) 169 if((randfd = open("/dev/random", OREAD)) < 0) 170 panic("open /dev/random: %r"); 171 #endif 172 } 173 174 #undef read 175 ulong 176 randomread(void *v, ulong n) 177 { 178 #ifdef USE_RANDOM 179 int i; 180 181 for(i=0; i<n; i++) 182 ((uchar*)v)[i] = random(); 183 return n; 184 #else 185 int m; 186 187 if((m = read(randfd, v, n)) != n) 188 panic("short read from /dev/random: %d but %d", n, m); 189 return m; 190 #endif 191 } 192 193 #undef time 194 long 195 seconds(void) 196 { 197 return time(0); 198 } 199 200 ulong 201 ticks(void) 202 { 203 static long sec0 = 0, usec0; 204 struct timeval t; 205 206 if(gettimeofday(&t, nil) < 0) 207 return 0; 208 if(sec0 == 0){ 209 sec0 = t.tv_sec; 210 usec0 = t.tv_usec; 211 } 212 return (t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000; 213 } 214 215