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