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