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