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