xref: /plan9-contrib/sys/src/cmd/unix/drawterm/kern/posix.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
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