xref: /inferno-os/emu/port/kproc-pthreads.c (revision 1b2614f99767317f75ba698e8fa1c3c93fa902f7)
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 	p->os = os;
126 
127 	if(flags & KPDUPPG) {
128 		pg = up->env->pgrp;
129 		incref(&pg->r);
130 		p->env->pgrp = pg;
131 	}
132 	if(flags & KPDUPFDG) {
133 		fg = up->env->fgrp;
134 		incref(&fg->r);
135 		p->env->fgrp = fg;
136 	}
137 	if(flags & KPDUPENVG) {
138 		eg = up->env->egrp;
139 		incref(&eg->r);
140 		p->env->egrp = eg;
141 	}
142 
143 	p->env->uid = up->env->uid;
144 	p->env->gid = up->env->gid;
145 	kstrdup(&p->env->user, up->env->user);
146 
147 	strcpy(p->text, name);
148 
149 	p->func = func;
150 	p->arg = arg;
151 
152 	lock(&procs.l);
153 	if(procs.tail != nil) {
154 		p->prev = procs.tail;
155 		procs.tail->next = p;
156 	} else {
157 		procs.head = p;
158 		p->prev = nil;
159 	}
160 	procs.tail = p;
161 	unlock(&procs.l);
162 
163 	memset(&attr, 0, sizeof(attr));
164 	if(pthread_attr_init(&attr) == -1)
165 		panic("pthread_attr_init failed");
166 	if(flags & KPX11)
167 		pthread_attr_setstacksize(&attr, 512*1024);	/* could be a parameter */
168 	else if(KSTACK > 0)
169 		pthread_attr_setstacksize(&attr, (KSTACK < PTHREAD_STACK_MIN? PTHREAD_STACK_MIN: KSTACK)+1024);
170 	pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
171 	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
172 	if(pthread_create(&thread, &attr, tramp, p))
173 		panic("thr_create failed\n");
174 	pthread_attr_destroy(&attr);
175 }
176 
177 /* called to wake up kproc blocked on a syscall */
178 void
179 oshostintr(Proc *p)
180 {
181 	Osdep *os;
182 
183 	os = p->os;
184 	if(os != nil && os->self != 0)
185 		pthread_kill(os->self, SIGUSR1);
186 }
187 
188 void
189 osblock(void)
190 {
191 	Osdep *os;
192 
193 	os = up->os;
194 	while(sem_wait(&os->sem))
195 		{}	/* retry on signals (which shouldn't happen) */
196 }
197 
198 void
199 osready(Proc *p)
200 {
201 	Osdep *os;
202 
203 	os = p->os;
204 	sem_post(&os->sem);
205 }
206 
207 void
208 kprocinit(Proc *p)
209 {
210 	if(pthread_key_create(&prdakey, NULL))
211 		panic("key_create failed");
212 	if(pthread_setspecific(prdakey, p))
213 		panic("set specific thread data failed");
214 }
215 
216 void
217 osyield(void)
218 {
219 //	pthread_yield_np();
220 	/* define pthread_yield to be sched_yield or pthread_yield_np if required */
221 	pthread_yield();
222 }
223 
224 void
225 ospause(void)
226 {
227 	/* main just wants this thread to go away */
228 	pthread_exit(0);
229 }
230 
231 void
232 oslopri(void)
233 {
234 	struct sched_param param;
235 	int policy;
236 	pthread_t self;
237 
238 	self = pthread_self();
239 	pthread_getschedparam(self, &policy, &param);
240 	param.sched_priority = sched_get_priority_min(policy);
241 	pthread_setschedparam(self,  policy, &param);
242 }
243