xref: /inferno-os/emu/port/kproc-pthreads.c (revision d60c26c675792fa5bc6ca1ea859edae93c7be5ce)
1 #include	"dat.h"
2 #include	"fns.h"
3 #include	"error.h"
4 
5 #undef _POSIX_C_SOURCE
6 #undef getwd
7 
8 #include	<unistd.h>
9 #include	<signal.h>
10 #include 	<pthread.h>
11 #include	<limits.h>
12 #include	<errno.h>
13 #include	<semaphore.h>
14 
15 #ifdef __NetBSD__
16 #include	<sched.h>
17 #define pthread_yield() (sched_yield())
18 #define PTHREAD_STACK_MIN ((size_t)sysconf(_SC_THREAD_STACK_MIN))
19 #endif
20 
21 
22 typedef struct Osdep Osdep;
23 struct Osdep {
24 	sem_t	sem;
25 	pthread_t	self;
26 };
27 
28 static pthread_key_t  prdakey;
29 
30 extern int dflag;
31 
32 Proc*
33 getup(void)
34 {
35 	return pthread_getspecific(prdakey);
36 }
37 
38 void
39 pexit(char *msg, int t)
40 {
41 	Osenv *e;
42 	Proc *p;
43 	Osdep *os;
44 
45 	USED(t);
46 
47 	lock(&procs.l);
48 	p = up;
49 	if(p->prev)
50 		p->prev->next = p->next;
51 	else
52 		procs.head = p->next;
53 
54 	if(p->next)
55 		p->next->prev = p->prev;
56 	else
57 		procs.tail = p->prev;
58 	unlock(&procs.l);
59 
60 	if(0)
61 		print("pexit: %s: %s\n", p->text, msg);
62 
63 	e = p->env;
64 	if(e != nil) {
65 		closefgrp(e->fgrp);
66 		closepgrp(e->pgrp);
67 		closeegrp(e->egrp);
68 		closesigs(e->sigs);
69 		free(e->user);
70 	}
71 	free(p->prog);
72 	os = p->os;
73 	if(os != nil){
74 		sem_destroy(&os->sem);
75 		free(os);
76 	}
77 	free(p);
78 	pthread_exit(0);
79 }
80 
81 static void*
82 tramp(void *arg)
83 {
84 	Proc *p;
85 	Osdep *os;
86 
87 	p = arg;
88 	os = p->os;
89 	os->self = pthread_self();
90 	if(pthread_setspecific(prdakey, arg))
91 		panic("set specific data failed in tramp\n");
92 	if(0){
93 		pthread_attr_t attr;
94 		memset(&attr, 0, sizeof(attr));
95 		pthread_getattr_np(pthread_self(), &attr);
96 		size_t s;
97 		pthread_attr_getstacksize(&attr, &s);
98 		print("stack size = %d\n", s);
99 	}
100 	p->func(p->arg);
101 	pexit("{Tramp}", 0);
102 	return nil;
103 }
104 
105 void
106 kproc(char *name, void (*func)(void*), void *arg, int flags)
107 {
108 	pthread_t thread;
109 	Proc *p;
110 	Pgrp *pg;
111 	Fgrp *fg;
112 	Egrp *eg;
113 	pthread_attr_t attr;
114 	Osdep *os;
115 
116 	p = newproc();
117 	if(p == nil)
118 		panic("kproc: no memory");
119 
120 	os = malloc(sizeof(*os));
121 	if(os == nil)
122 		panic("kproc: no memory");
123 	os->self = 0;	/* set by tramp */
124 	sem_init(&os->sem, 0, 0);
125 #if defined(__NetBSD__) && defined(__powerpc__)
126 	{ /* XXX: Work around a problem on macppc with kernel semaphores. */
127 		int val;
128 		sem_getvalue(&os->sem, &val);
129 	}
130 #endif
131 	p->os = os;
132 
133 	if(flags & KPDUPPG) {
134 		pg = up->env->pgrp;
135 		incref(&pg->r);
136 		p->env->pgrp = pg;
137 	}
138 	if(flags & KPDUPFDG) {
139 		fg = up->env->fgrp;
140 		incref(&fg->r);
141 		p->env->fgrp = fg;
142 	}
143 	if(flags & KPDUPENVG) {
144 		eg = up->env->egrp;
145 		incref(&eg->r);
146 		p->env->egrp = eg;
147 	}
148 
149 	p->env->uid = up->env->uid;
150 	p->env->gid = up->env->gid;
151 	kstrdup(&p->env->user, up->env->user);
152 
153 	strcpy(p->text, name);
154 
155 	p->func = func;
156 	p->arg = arg;
157 
158 	lock(&procs.l);
159 	if(procs.tail != nil) {
160 		p->prev = procs.tail;
161 		procs.tail->next = p;
162 	} else {
163 		procs.head = p;
164 		p->prev = nil;
165 	}
166 	procs.tail = p;
167 	unlock(&procs.l);
168 
169 	memset(&attr, 0, sizeof(attr));
170 	if(pthread_attr_init(&attr) == -1)
171 		panic("pthread_attr_init failed");
172 	if(flags & KPX11)
173 		pthread_attr_setstacksize(&attr, 512*1024);	/* could be a parameter */
174 	else if(KSTACK > 0)
175 		pthread_attr_setstacksize(&attr, (KSTACK < PTHREAD_STACK_MIN? PTHREAD_STACK_MIN: KSTACK)+1024);
176 	pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
177 	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
178 	if(pthread_create(&thread, &attr, tramp, p))
179 		panic("thr_create failed\n");
180 	pthread_attr_destroy(&attr);
181 }
182 
183 /* called to wake up kproc blocked on a syscall */
184 void
185 oshostintr(Proc *p)
186 {
187 	Osdep *os;
188 
189 	os = p->os;
190 	if(os != nil && os->self != 0)
191 		pthread_kill(os->self, SIGUSR1);
192 }
193 
194 void
195 osblock(void)
196 {
197 	Osdep *os;
198 
199 	os = up->os;
200 	while(sem_wait(&os->sem))
201 		{}	/* retry on signals (which shouldn't happen) */
202 }
203 
204 void
205 osready(Proc *p)
206 {
207 	Osdep *os;
208 
209 	os = p->os;
210 	sem_post(&os->sem);
211 }
212 
213 void
214 kprocinit(Proc *p)
215 {
216 	if(pthread_key_create(&prdakey, NULL))
217 		panic("key_create failed");
218 	if(pthread_setspecific(prdakey, p))
219 		panic("set specific thread data failed");
220 }
221 
222 void
223 osyield(void)
224 {
225 //	pthread_yield_np();
226 	/* define pthread_yield to be sched_yield or pthread_yield_np if required */
227 	pthread_yield();
228 }
229 
230 void
231 ospause(void)
232 {
233 	/* main just wants this thread to go away */
234 	pthread_exit(0);
235 }
236 
237 void
238 oslopri(void)
239 {
240 	struct sched_param param;
241 	int policy;
242 	pthread_t self;
243 
244 	self = pthread_self();
245 	pthread_getschedparam(self, &policy, &param);
246 	param.sched_priority = sched_get_priority_min(policy);
247 	pthread_setschedparam(self,  policy, &param);
248 }
249