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