Blob


1 #include <u.h>
2 #include <errno.h>
3 #include "threadimpl.h"
5 /*
6 * Basic kernel thread management.
7 */
8 static pthread_key_t key;
10 void
11 _kthreadinit(void)
12 {
13 pthread_key_create(&key, 0);
14 }
16 void
17 _kthreadsetproc(Proc *p)
18 {
19 sigset_t all;
21 p->pthreadid = pthread_self();
22 sigfillset(&all);
23 pthread_sigmask(SIG_SETMASK, &all, nil);
24 pthread_setspecific(key, p);
25 }
27 Proc*
28 _kthreadgetproc(void)
29 {
30 return pthread_getspecific(key);
31 }
33 void
34 _kthreadstartproc(Proc *p)
35 {
36 Proc *np;
37 pthread_t tid;
38 sigset_t all;
40 np = p->newproc;
41 sigfillset(&all);
42 pthread_sigmask(SIG_SETMASK, &all, nil);
43 if(pthread_create(&tid, nil, (void*(*)(void*))_threadscheduler,
44 np) < 0)
45 sysfatal("pthread_create: %r");
46 np->pthreadid = tid;
47 }
49 void
50 _kthreadexitproc(char *exitstr)
51 {
52 _threaddebug(DBGSCHED, "_pthreadexit");
53 pthread_exit(nil);
54 }
56 void
57 _kthreadexitallproc(char *exitstr)
58 {
59 _threaddebug(DBGSCHED, "_threadexitallproc");
60 exits(exitstr);
61 }
63 /*
64 * Exec. Pthreads does the hard work of making it possible
65 * for any thread to do the waiting, so this is pretty easy.
66 * We create a separate proc whose job is to wait for children
67 * and deliver wait messages.
68 */
69 static Channel *_threadexecwaitchan;
71 static void
72 _threadwaitproc(void *v)
73 {
74 Channel *c;
75 Waitmsg *w;
77 _threadinternalproc();
79 USED(v);
81 for(;;){
82 w = wait();
83 if(w == nil){
84 if(errno == ECHILD) /* wait for more */
85 recvul(_threadexecwaitchan);
86 continue;
87 }
88 if((c = _threadwaitchan) != nil)
89 sendp(c, w);
90 else
91 free(w);
92 }
93 fprint(2, "_threadwaitproc exits\n"); /* not reached */
94 }
97 /*
98 * Call _threadexec in the right conditions.
99 */
100 int
101 _kthreadexec(Channel *c, int fd[3], char *prog, char *args[], int freeargs)
103 static Lock lk;
104 int rv;
106 if(!_threadexecwaitchan){
107 lock(&lk);
108 if(!_threadexecwaitchan){
109 _threadexecwaitchan = chancreate(sizeof(ulong), 1);
110 proccreate(_threadwaitproc, nil, 32*1024);
112 unlock(&lk);
114 rv = _threadexec(c, fd, prog, args, freeargs);
115 nbsendul(_threadexecwaitchan, 1);
116 return rv;
119 /*
120 * Some threaded applications want to run in the background.
121 * Calling fork() and exiting in the parent will result in a child
122 * with a single pthread (if we are using pthreads), and will screw
123 * up our internal process info if we are using clone/rfork.
124 * Instead, apps should call threadbackground(), which takes
125 * care of this.
127 * _threadbackgroundinit is called from main.
128 */
130 static int mainpid, passerpid;
132 static void
133 passer(void *x, char *msg)
135 Waitmsg *w;
137 USED(x);
138 if(strcmp(msg, "sys: usr2") == 0)
139 _exit(0); /* daemonize */
140 else if(strcmp(msg, "sys: child") == 0){
141 /* child exited => so should we */
142 w = wait();
143 if(w == nil)
144 _exit(1);
145 _exit(atoi(w->msg));
146 }else
147 postnote(PNGROUP, mainpid, msg);
150 void
151 _threadbackgroundinit(void)
153 int pid;
154 sigset_t mask;
156 sigfillset(&mask);
157 pthread_sigmask(SIG_BLOCK, &mask, 0);
159 return;
161 passerpid = getpid();
162 switch(pid = fork()){
163 case -1:
164 sysfatal("fork: %r");
166 case 0:
167 rfork(RFNOTEG);
168 return;
170 default:
171 break;
174 mainpid = pid;
175 notify(passer);
176 notifyon("sys: child");
177 notifyon("sys: usr2"); /* should already be on */
178 for(;;)
179 pause();
180 _exit(0);
183 void
184 threadbackground(void)
186 if(passerpid <= 1)
187 return;
188 postnote(PNPROC, passerpid, "sys: usr2");
191 /*
192 * Notes.
193 */
194 Channel *_threadnotechan;
195 static ulong sigs;
196 static Lock _threadnotelk;
197 static void _threadnoteproc(void*);
198 extern int _p9strsig(char*);
199 extern char *_p9sigstr(int);
201 Channel*
202 threadnotechan(void)
204 if(_threadnotechan == nil){
205 lock(&_threadnotelk);
206 if(_threadnotechan == nil){
207 _threadnotechan = chancreate(sizeof(char*), 1);
208 proccreate(_threadnoteproc, nil, 32*1024);
210 unlock(&_threadnotelk);
212 return _threadnotechan;
215 void
216 _threadnote(void *x, char *msg)
218 USED(x);
220 if(_threadexitsallstatus)
221 _kthreadexitproc(_threadexitsallstatus);
223 if(strcmp(msg, "sys: usr2") == 0)
224 noted(NCONT);
226 if(_threadnotechan == nil)
227 noted(NDFLT);
229 sigs |= 1<<_p9strsig(msg);
230 noted(NCONT);
233 void
234 _threadnoteproc(void *x)
236 int i;
237 sigset_t none;
238 Channel *c;
240 _threadinternalproc();
241 sigemptyset(&none);
242 pthread_sigmask(SIG_SETMASK, &none, 0);
244 c = _threadnotechan;
245 for(;;){
246 if(sigs == 0)
247 pause();
248 for(i=0; i<32; i++){
249 if((sigs&(1<<i)) == 0)
250 continue;
251 sigs &= ~(1<<i);
252 if(i == 0)
253 continue;
254 sendp(c, _p9sigstr(i));
259 void
260 _threadschednote(void)
264 void
265 _kmaininit(void)
267 sigset_t all;
269 sigfillset(&all);
270 pthread_sigmask(SIG_SETMASK, &all, 0);