add linux_emul base, reorganize docs
[openbsd_emul.git] / linux_emul_base / proc.c
CommitLineData
cae36a52 1#include <u.h>
2#include <libc.h>
3#include <ureg.h>
4#include "dat.h"
5#include "fns.h"
6#include "linux.h"
7
8static int timernotefd;
9static void timerproc(void*);
10
11static int
12pidhash(int pid)
13{
14 return (pid - 1) % MAXPROC;
15}
16
17Uproc*
18getproc(int tid)
19{
20 Uproc *p;
21
22 if(tid > 0){
23 p = &proctab.proc[pidhash(tid)];
24 if(p->tid == tid)
25 return p;
26 }
27 return nil;
28}
29
30Uproc*
31getprocn(int n)
32{
33 Uproc *p;
34
35 p = &proctab.proc[n];
36 if(p->tid > 0)
37 return p;
38 return nil;
39}
40
41static Uproc*
42allocproc(void)
43{
44 Uproc *p;
45 int tid, i;
46
47 for(i=0; i<MAXPROC; i++){
48 tid = proctab.nextpid++;
49 p = &proctab.proc[pidhash(tid)];
50 if(p->tid <= 0){
51 proctab.alloc++;
52
53 p->tid = tid;
54 p->pid = tid;
55 p->pgid = tid;
56 p->psid = tid;
57 return p;
58 }
59 }
60
61 trace("allocproc(): out of processes");
62 return nil;
63}
64
65static void
66freeproc(Uproc *p)
67{
68 Uwait *w;
69
70 while(w = p->freewait){
71 p->freewait = w->next;
72 free(w);
73 }
74 exittrace(p);
75 free(p->comm);
76 free(p->root);
77 free(p->cwd);
78 free(p->kcwd);
79 memset(p, 0, sizeof(*p));
80 proctab.alloc--;
81}
82
83void initproc(void)
84{
85 Uproc *p;
86 char buf[1024];
87 int pid;
88
89 proctab.nextpid = 10;
90
91 p = allocproc();
92 p->kpid = getpid();
93 snprint(buf, sizeof(buf), "/proc/%d/note", p->kpid);
94 p->notefd = open(buf, OWRITE);
95 snprint(buf, sizeof(buf), "/proc/%d/args", p->kpid);
96 p->argsfd = open(buf, ORDWR);
97
98 current = p;
99
100 inittrace();
101 inittime();
102 initsignal();
103 initmem();
104 inittls();
105 initfile();
106
107 if((pid = procfork(timerproc, nil, 0)) < 0)
108 panic("initproc: unable to fork timerproc: %r");
109
110 snprint(buf, sizeof(buf), "/proc/%d/note", pid);
111 timernotefd = open(buf, OWRITE);
112
113 current->root = nil;
114 current->cwd = kstrdup(getwd(buf, sizeof(buf)));
115 current->kcwd = kstrdup(current->cwd);
116 current->linkloop = 0;
117 current->starttime = nsec();
118
119 inittrap();
120}
121
122void
123setprocname(char *s)
124{
125 if(current == nil){
126 char buf[32];
127 int fd;
128
129 snprint(buf, sizeof(buf), "/proc/%d/args", getpid());
130 if((fd = open(buf, OWRITE)) >= 0){
131 write(fd, s, strlen(s));
132 close(fd);
133 }
134 } else {
135 write(current->argsfd, s, strlen(s));
136 }
137}
138
139static void
140intrnote(void *, char *msg)
141{
142 if(strncmp(msg, "interrupt", 9) == 0)
143 noted(NCONT);
144 noted(NDFLT);
145}
146
147struct kprocforkargs
148{
149 int flags;
150 void (*func)(void *aux);
151 void *aux;
152};
153
154static int
155kprocfork(void *arg)
156{
157 struct kprocforkargs args;
158 int pid;
159
160 memmove(&args, arg, sizeof(args));
161
162 if((pid = rfork(RFPROC|RFMEM|args.flags)) != 0)
163 return pid;
164
165 notify(intrnote);
166
167 unmapuserspace();
168 current = nil;
169
170 profme();
171 args.func(args.aux);
172 longjmp(exitjmp, 1);
173 return -1;
174}
175
176/*
177 * procfork starts a kernel process running on kstack.
178 * that process will have linux memory segments (stack, private,
179 * shared) unmapped but plan9 segments (text, bss, stack) shared.
180 * here is no Uproc associated with it! current will be set to nil so
181 * you cant call sys_????() functions in here.
182 * procfork returns the plan9 pid. (usefull for posting notes)
183 */
184int procfork(void (*func)(void *aux), void *aux, int flags)
185{
186 struct kprocforkargs args;
187
188 args.flags = flags;
189 args.func = func;
190 args.aux = aux;
191
192 return onstack(kstack, kprocfork, &args);
193}
194
195static void *Intr = (void*)~0;
196
197static char Notifyme[] = "notifyme";
198static char Wakeme[] = "wakeme";
199static char Xchange[] = "xchange";
200
201static char Wakeup[] = "wakeup";
202static char Abort[] = "abort";
203
204int notifyme(int on)
205{
206 Uproc *p;
207
208 p = current;
209 qlock(p);
210 if(on){
211 if(p->notified || signalspending(p)){
212 qunlock(p);
213 return 1;
214 }
215 if(p->state == nil)
216 p->state = Notifyme;
217 } else {
218 p->state = nil;
219 }
220 qunlock(p);
221 return 0;
222}
223
224void wakeme(int on)
225{
226 Uproc *p;
227
228 p = current;
229 qlock(p);
230 if(on){
231 if(p->state == nil)
232 p->state = Wakeme;
233 } else {
234 p->state = nil;
235 }
236 qunlock(p);
237}
238
239int sleepproc(QLock *l, int flags)
240{
241 Uproc *p;
242 void *ret;
243 char *x;
244
245 p = current;
246 qlock(p);
247 x = p->state;
248 if(x == nil || x == Wakeme){
249 p->xstate = x;
250 p->state = Xchange;
251 if(l != nil)
252 qunlock(l);
253 qunlock(p);
254 if(flags && signalspending(p)){
255 ret = Intr;
256 } else {
257 ret = rendezvous(p, Xchange);
258 }
259 if(ret == Intr){
260 qlock(p);
261 if(p->state != Xchange){
262 while((ret = rendezvous(p, Xchange)) == Intr)
263 ;
264 } else {
265 p->state = x;
266 }
267 qunlock(p);
268 }
269 if(l != nil)
270 qlock(l);
271 } else {
272 p->state = Wakeme;
273 ret = x;
274 qunlock(p);
275 }
276 return (ret == Wakeup) ? 0 : -ERESTART;
277}
278
279static int
280wakeup(Uproc *proc, char *m, int force)
281{
282 char *x;
283
284 if(proc != nil){
285 qlock(proc);
286 x = proc->state;
287
288 if(x == Wakeme){
289 proc->state = m;
290 qunlock(proc);
291 return 1;
292 }
293 if(x == Xchange){
294 proc->state = proc->xstate;
295 proc->xstate = nil;
296 qunlock(proc);
297 while(rendezvous(proc, m) == Intr)
298 ;
299 return 1;
300 }
301 if((m != Wakeup) && (proc->notified == 0)){
302 if(x == Notifyme)
303 proc->state = nil;
304 if(x == Notifyme || force){
305 proc->notified = 1;
306 qunlock(proc);
307 write(proc->notefd, "interrupt", 9);
308 return 1;
309 }
310 }
311 qunlock(proc);
312 }
313 return 0;
314}
315
316Uwait* addwaitq(Uwaitq *q)
317{
318 Uproc *p;
319 Uwait *w;
320
321 p = current;
322 if(w = p->freewait){
323 p->freewait = w->next;
324 } else {
325 w = kmalloc(sizeof(*w));
326 }
327
328 w->next = nil;
329
330 w->proc = p;
331 w->file = nil;
332
333 w->q = q;
334 qlock(q);
335 w->nextq = q->w;
336 q->w = w;
337 qunlock(q);
338
339 return w;
340}
341
342void delwaitq(Uwait *w)
343{
344 Uwaitq *q;
345 Uwait **x;
346
347 q = w->q;
348 qlock(q);
349 for(x = &q->w; *x; x=&((*x)->nextq)){
350 if(*x == w){
351 *x = w->nextq;
352 break;
353 }
354 }
355 qunlock(q);
356
357 w->q = nil;
358 w->nextq = nil;
359
360 w->proc = nil;
361 putfile(w->file);
362 w->file = nil;
363
364 w->next = current->freewait;
365 current->freewait = w;
366}
367
368int requeue(Uwaitq *q1, Uwaitq *q2, int nrequeue)
369{
370 int n;
371 Uwait *w;
372
373 n = 1000;
374 for(;;){
375 qlock(q1);
376 if(canqlock(q2))
377 break;
378 qunlock(q1);
379 if(--n <= 0)
380 return 0;
381 sleep(0);
382 }
383 n = 0;
384 while((w = q1->w) && (n < nrequeue)){
385 q1->w = w->nextq;
386 w->q = q2;
387 w->nextq = q2->w;
388 q2->w = w;
389 n++;
390 }
391 qunlock(q2);
392 qunlock(q1);
393 return n;
394}
395
396int wakeq(Uwaitq *q, int nwake)
397{
398 int n;
399 Uwait *w;
400
401 n = 0;
402 if(q != nil){
403 qlock(q);
404 for(w = q->w; w && n < nwake; w=w->nextq)
405 n += wakeup(w->proc, Wakeup, 0);
406 qunlock(q);
407 }
408 return n;
409}
410
411int sleepq(Uwaitq *q, QLock *l, int flags)
412{
413 Uwait *w;
414 int ret;
415
416 w = addwaitq(q);
417 ret = sleepproc(l, flags);
418 delwaitq(w);
419
420 return ret;
421}
422
423static Uproc *alarmq;
424
425int
426procsetalarm(Uproc *proc, vlong t)
427{
428 Uproc **pp;
429 int ret;
430
431 if(proc->alarm && t >= proc->alarm)
432 return 0;
433 ret = (alarmq == nil) || (t < alarmq->alarm);
434 for(pp = &alarmq; *pp; pp = &((*pp)->alarmq)){
435 if(*pp == proc){
436 *pp = proc->alarmq;
437 break;
438 }
439 }
440 for(pp = &alarmq; *pp; pp = &((*pp)->alarmq))
441 if((*pp)->alarm > t)
442 break;
443 proc->alarm = t;
444 proc->alarmq = *pp;
445 *pp = proc;
446 return ret;
447}
448
449void
450setalarm(vlong t)
451{
452 qlock(&proctab);
453 if(procsetalarm(current, t))
454 write(timernotefd, "interrupt", 9);
455 qunlock(&proctab);
456}
457
458/* signal.c */
459extern void alarmtimer(Uproc *proc, vlong now);
460
461static void
462timerproc(void*)
463{
464 Uproc *h;
465 vlong now;
466 long m;
467
468 setprocname("timerproc()");
469
470 while(proctab.alloc > 0){
471 qlock(&proctab);
472 m = 2000;
473 now = nsec();
474 while(h = alarmq){
475 if(now < h->alarm){
476 m = (h->alarm - now) / 1000000;
477 break;
478 }
479 alarmq = h->alarmq;
480 h->alarm = 0;
481 h->alarmq = nil;
482 if(h->timeout){
483 if(now >= h->timeout){
484 h->timeout = 0;
485 wakeup(h, Wakeup, 0);
486 } else
487 procsetalarm(h, h->timeout);
488 }
489 alarmtimer(h, now);
490 }
491 qunlock(&proctab);
492 sleep((m + (1000/HZ-1))/(1000/HZ));
493 }
494}
495
496/*
497static void
498timerproc(void *)
499{
500 Uproc *p;
501 vlong expire, now, wake, dead;
502 int err, i, alive;
503 char c;
504
505 setprocname("timerproc()");
506 dead = 0;
507 for(;;){
508 qlock(&proctab);
509 now = nsec();
510 wake = now + 60000000000LL;
511 alive = 0;
512 for(i=0; i<MAXPROC; i++){
513 if((p = getprocn(i)) == nil)
514 continue;
515 if(p->wstate & WEXITED)
516 continue;
517 if(p->kpid <= 0)
518 continue;
519
520 if(now >= dead){
521 if(read(p->argsfd, &c, 1) < 0){
522 err = mkerror();
523 if(err != -EINTR && err != -ERESTART){
524 p->kpid = 0;
525 qunlock(&proctab);
526 exitproc(p, SIGKILL, 1);
527 qlock(&proctab);
528 continue;
529 }
530 }
531 }
532 alive++;
533 expire = p->timeout;
534 if(expire > 0){
535 if(now >= expire){
536 p->timeout = 0;
537 wakeup(p, Wakeup, 0);
538 } else {
539 if(expire < wake)
540 wake = expire;
541 }
542 }
543 expire = alarmtimer(p, now, wake);
544 if(expire < wake)
545 wake = expire;
546 }
547 qunlock(&proctab);
548
549 if(now >= dead)
550 dead = now + 5000000000LL;
551 if(dead < wake)
552 wake = dead;
553 if(alive == 0)
554 break;
555 wake -= now;
556
557 sleep(wake/1000000LL);
558 }
559}
560*/
561
562int sys_waitpid(int pid, int *pexit, int opt)
563{
564 int i, n, m, status;
565 Uproc *p;
566
567 trace("sys_waitpid(%d, %p, %d)", pid, pexit, opt);
568
569 m = WEXITED;
570 if(opt & WUNTRACED)
571 m |= WSTOPPED;
572 if(opt & WCONTINUED)
573 m |= WCONTINUED;
574
575 qlock(&proctab);
576 for(;;){
577 n = 0;
578 for(i=0; i<MAXPROC; i++){
579 if((p = getprocn(i)) == nil)
580 continue;
581 if(p == current)
582 continue;
583 if((p->exitsignal != SIGCHLD) && (opt & (WALL|WCLONE))==0)
584 continue;
585 if(p->ppid != current->pid)
586 continue;
587 if(pid > 0){
588 if(p->pid != pid)
589 continue;
590 } else if(pid == 0){
591 if(p->pgid != current->pgid)
592 continue;
593 } else if(pid < -1){
594 if(p->pgid != -pid)
595 continue;
596 }
597 n++;
598 trace("sys_waitpid(): child %d wstate %x", p->pid, p->wstate);
599 if(p->wevent & m)
600 goto found;
601 }
602 if(n == 0){
603 qunlock(&proctab);
604 trace("sys_waitpid(): no children we can wait for");
605 return -ECHILD;
606 }
607 if(opt & WNOHANG){
608 qunlock(&proctab);
609 trace("sys_waitpid(): no exited/stoped/cont children");
610 return 0;
611 }
612 if((i = sleepproc(&proctab, 1)) < 0){
613 qunlock(&proctab);
614 return i;
615 }
616 }
617
618found:
619 pid = p->pid;
620 status = p->exitcode;
621 p->wevent &= ~(p->wevent & m);
622 if(p->wstate & WEXITED){
623 trace("sys_waitpid(): found zombie %d exitcode %d", pid, status);
624 freeproc(p);
625 }
626 qunlock(&proctab);
627 if(pexit)
628 *pexit = status;
629 return pid;
630}
631
632struct linux_rusage {
633 struct linux_timeval ru_utime; /* user time used */
634 struct linux_timeval ru_stime; /* system time used */
635 long ru_maxrss; /* maximum resident set size */
636 long ru_ixrss; /* integral shared memory size */
637 long ru_idrss; /* integral unshared data size */
638 long ru_isrss; /* integral unshared stack size */
639 long ru_minflt; /* page reclaims */
640 long ru_majflt; /* page faults */
641 long ru_nswap; /* swaps */
642 long ru_inblock; /* block input operations */
643 long ru_oublock; /* block output operations */
644 long ru_msgsnd; /* messages sent */
645 long ru_msgrcv; /* messages received */
646 long ru_nsignals; /* signals received */
647 long ru_nvcsw; /* voluntary context switches */
648 long ru_nivcsw; /* involuntary context switches */
649};
650
651int sys_wait4(int pid, int *pexit, int opt, void *prusage)
652{
653 int ret;
654 struct linux_rusage *ru = prusage;
655
656 trace("sys_wait4(%d, %p, %d, %p)", pid, pexit, opt, prusage);
657
658 ret = sys_waitpid(pid, pexit, opt);
659 if(ru != nil)
660 memset(ru, 0, sizeof(*ru));
661
662 return ret;
663}
664
665int
666threadcount(int pid)
667{
668 Uproc *p;
669 int i, n;
670
671 n = 0;
672 for(i = 0; i<MAXPROC; i++){
673 p = getprocn(i);
674 if(p != nil && p->pid == pid)
675 n++;
676 }
677 return n;
678}
679
680int
681killproc(Uproc *p, Usiginfo *info, int group)
682{
683 int i, n;
684 Uproc *w;
685 int sig, err;
686
687 if((err = sendsignal(p, info, group)) <= 0)
688 return err;
689 w = p;
690 sig = info->signo;
691 if(group && !wantssignal(w, sig)){
692 for(i=1, n = p->tid + 1; i<MAXPROC; i++, n++){
693 if((p = getprocn(pidhash(n))) == nil)
694 continue;
695 if(p->pid != w->pid)
696 continue;
697 if(!wantssignal(p, info->signo))
698 continue;
699 w = p;
700 break;
701 }
702 }
703 wakeup(w, Abort, (sig == SIGKILL || sig == SIGSTOP || sig == SIGALRM));
704 return 0;
705}
706
707enum
708{
709 CLD_EXITED = 1,
710 CLD_KILLED,
711 CLD_DUMPED,
712 CLD_TRAPPED,
713 CLD_STOPPED,
714 CLD_CONTINUED,
715};
716
717/*
718 * queue the exit signal into the parent process. this
719 * doesnt do the wakeup like killproc().
720 */
721static int
722sendexitsignal(Uproc *parent, Uproc *proc, int sig, int code)
723{
724 Usiginfo si;
725
726 memset(&si, 0, sizeof(si));
727 switch(si.signo = sig){
728 case SIGCHLD:
729 switch(code & 0xFF){
730 case 0:
731 si.code = CLD_EXITED;
732 break;
733 case SIGSTOP:
734 si.code = CLD_STOPPED;
735 break;
736 case SIGCONT:
737 si.code = CLD_CONTINUED;
738 break;
739 case SIGKILL:
740 si.code = CLD_KILLED;
741 break;
742 default:
743 si.code = CLD_DUMPED;
744 break;
745 }
746 si.chld.pid = proc->pid;
747 si.chld.uid = proc->uid;
748 si.chld.status = code;
749 }
750 return sendsignal(parent, &si, 1);
751}
752
753/*
754 * wakeup all threads who are in the same thread group
755 * as p including p. must be called with proctab locked.
756 */
757static void
758wakeupall(Uproc *p, char *m, int force)
759{
760 int pid, i, n;
761
762 pid = p->pid;
763 for(i=0, n = p->tid; i<MAXPROC; i++, n++)
764 if(p = getprocn(pidhash(n)))
765 if(p->pid == pid)
766 wakeup(p, m, force);
767}
768
769static void
770zap(void *)
771{
772 exitproc(current, 0, 0);
773}
774
775void
776zapthreads(void)
777{
778 Uproc *p;
779 int i, n, z;
780
781 for(;;){
782 z = 0;
783 for(i=1, n = current->tid+1; i<MAXPROC; i++, n++){
784 if((p = getprocn(pidhash(n))) == nil)
785 continue;
786 if(p->pid != current->pid || p == current)
787 continue;
788 if(p->kpid <= 0)
789 continue;
790
791 trace("zapthreads() zapping thread %p", p);
792 p->tracearg = current;
793 p->traceproc = zap;
794 wakeup(p, Abort, 1);
795 z++;
796 }
797 if(z == 0)
798 break;
799 sleepproc(&proctab, 0);
800 }
801}
802
803struct kexitprocargs
804{
805 Uproc *proc;
806 int code;
807 int group;
808};
809
810#pragma profile off
811
812static int
813kexitproc(void *arg)
814{
815 struct kexitprocargs *args;
816 Uproc *proc;
817 int code, group;
818 Uproc *parent, *child, **pp;
819 int i;
820
821 args = arg;
822 proc = args->proc;
823 code = args->code;
824 group = args->group;
825
826 if(proc == current){
827 trace("kexitproc: cleartidptr = %p", proc->cleartidptr);
828 if(okaddr(proc->cleartidptr, sizeof(*proc->cleartidptr), 1))
829 *proc->cleartidptr = 0;
830 sys_futex((ulong*)proc->cleartidptr, 1, MAXPROC, nil, nil, 0);
831
832 qlock(&proctab);
833 exitsignal();
834 qunlock(&proctab);
835
836 exitmem();
837 }
838
839 exitfile(proc);
840
841 close(proc->notefd); proc->notefd = -1;
842 close(proc->argsfd); proc->argsfd = -1;
843
844 qlock(&proctab);
845
846 for(pp = &alarmq; *pp; pp = &((*pp)->alarmq)){
847 if(*pp == proc){
848 *pp = proc->alarmq;
849 proc->alarmq = nil;
850 break;
851 }
852 }
853
854 /* reparent children, and reap when zombies */
855 for(i=0; i<MAXPROC; i++){
856 if((child = getprocn(i)) == nil)
857 continue;
858 if(child->ppid != proc->pid)
859 continue;
860 child->ppid = 0;
861 if(child->wstate & WEXITED)
862 freeproc(child);
863 }
864
865 /* if we got zapped, just free the proc and wakeup zapper */
866 if((proc == current) && (proc->traceproc == zap) && (parent = proc->tracearg)){
867 freeproc(proc);
868 wakeup(parent, Wakeup, 0);
869 goto zapped;
870 }
871
872 if(group && proc == current)
873 zapthreads();
874
875 parent = getproc(proc->ppid);
876 if((threadcount(proc->pid)==1) && parent &&
877 (proc->exitsignal == SIGCHLD) && !ignoressignal(parent, SIGCHLD)){
878
879 /* we are zombie */
880 proc->exitcode = code;
881 proc->wstate = WEXITED;
882 proc->wevent = proc->wstate;
883 if(proc == current){
884 current->kpid = 0;
885 sendexitsignal(parent, proc, proc->exitsignal, code);
886 wakeupall(parent, Abort, 0);
887 qunlock(&proctab);
888 longjmp(exitjmp, 1);
889 } else {
890 sendexitsignal(parent, proc, proc->exitsignal, code);
891 }
892 } else {
893 /* we are clone */
894 if(parent && proc->exitsignal > 0)
895 sendexitsignal(parent, proc, proc->exitsignal, code);
896 freeproc(proc);
897 }
898 if(parent)
899 wakeupall(parent, Abort, 0);
900
901zapped:
902 qunlock(&proctab);
903
904 if(proc == current)
905 longjmp(exitjmp, 1);
906
907 return 0;
908}
909
910void exitproc(Uproc *proc, int code, int group)
911{
912 struct kexitprocargs args;
913
914 trace("exitproc(%p, %d, %d)", proc, code, group);
915
916 args.proc = proc;
917 args.code = code;
918 args.group = group;
919
920 if(proc == current){
921 onstack(kstack, kexitproc, &args);
922 } else {
923 kexitproc(&args);
924 }
925}
926
927struct kstoparg
928{
929 Uproc *stopper;
930 int code;
931};
932
933static void
934stop(void *aux)
935{
936 struct kstoparg *arg = aux;
937
938 stopproc(current, arg->code, 0);
939}
940
941void stopproc(Uproc *proc, int code, int group)
942{
943 struct kstoparg *arg;
944 Uproc *p, *parent;
945 int i, n, z;
946
947 trace("stopproc(%p, %d, %d)", proc, code, group);
948
949 qlock(&proctab);
950 proc->exitcode = code;
951 proc->wstate = WSTOPPED;
952 proc->wevent = proc->wstate;
953
954 if((proc == current) && (proc->traceproc == stop) && (arg = proc->tracearg)){
955 proc->traceproc = nil;
956 proc->tracearg = nil;
957 wakeup(arg->stopper, Wakeup, 0);
958 qunlock(&proctab);
959 return;
960 }
961
962 /* put all threads in the stopped state */
963 arg = nil;
964 while(group){
965 if(arg == nil){
966 arg = kmalloc(sizeof(*arg));
967 arg->stopper = current;
968 arg->code = code;
969 }
970 z = 0;
971 for(i=1, n = proc->tid+1; i<MAXPROC; i++, n++){
972 if((p = getprocn(pidhash(n))) == nil)
973 continue;
974 if(p->pid != proc->pid || p == proc)
975 continue;
976 if(p->kpid <= 0)
977 continue;
978 if(p->wstate & (WSTOPPED | WEXITED))
979 continue;
980
981 trace("stopproc() stopping thread %p", p);
982 p->tracearg = arg;
983 p->traceproc = stop;
984 wakeup(p, Abort, 1);
985 z++;
986 }
987 if(z == 0)
988 break;
989 sleepproc(&proctab, 0);
990 }
991 free(arg);
992
993 if(parent = getproc(proc->ppid)){
994 if(group && !ignoressignal(parent, SIGCHLD))
995 sendexitsignal(parent, proc, SIGCHLD, code);
996 wakeupall(parent, Abort, 0);
997 }
998 qunlock(&proctab);
999}
1000
1001void contproc(Uproc *proc, int code, int group)
1002{
1003 Uproc *p, *parent;
1004 int i, n;
1005
1006 trace("contproc(%p, %d, %d)", proc, code, group);
1007
1008 qlock(&proctab);
1009 proc->exitcode = code;
1010 proc->wstate = WCONTINUED;
1011 proc->wevent = proc->wstate;
1012 if(group){
1013 for(i=1, n = proc->tid+1; i<MAXPROC; i++, n++){
1014 if((p = getprocn(pidhash(n))) == nil)
1015 continue;
1016 if(p->pid != proc->pid || p == proc)
1017 continue;
1018 if(p->kpid <= 0)
1019 continue;
1020 if((p->wstate & WSTOPPED) == 0)
1021 continue;
1022 if(p->wstate & (WCONTINUED | WEXITED))
1023 continue;
1024
1025 trace("contproc() waking thread %p", p);
1026 p->exitcode = code;
1027 p->wstate = WCONTINUED;
1028 p->wevent = p->wstate;
1029 wakeup(p, Wakeup, 0);
1030 }
1031 }
1032 if(parent = getproc(proc->ppid)){
1033 if(group && !ignoressignal(parent, SIGCHLD))
1034 sendexitsignal(parent, proc, SIGCHLD, code);
1035 wakeupall(parent, Abort, 0);
1036 }
1037 qunlock(&proctab);
1038}
1039
1040int sys_exit(int code)
1041{
1042 trace("sys_exit(%d)", code);
1043
1044 exitproc(current, (code & 0xFF)<<8, 0);
1045 return -1;
1046}
1047
1048int sys_exit_group(int code)
1049{
1050 trace("sys_exit_group(%d)", code);
1051
1052 exitproc(current, (code & 0xFF)<<8, 1);
1053 return -1;
1054}
1055
1056struct kcloneprocargs
1057{
1058 int flags;
1059 void *newstack;
1060 int *parenttidptr;
1061 void *tlsdescr;
1062 int *childtidptr;
1063};
1064
1065static int
1066kcloneproc(void *arg)
1067{
1068 struct kcloneprocargs args;
1069 struct linux_user_desc tls;
1070 Ureg ureg;
1071 int rflags, pid, tid;
1072 char buf[80];
1073 Uproc *new;
1074
1075 memmove(&args, arg, sizeof(args));
1076 memmove(&ureg, current->ureg, sizeof(ureg));
1077 if(args.flags & CLONE_SETTLS){
1078 if(!okaddr(args.tlsdescr, sizeof(tls), 0))
1079 return -EFAULT;
1080 memmove(&tls, args.tlsdescr, sizeof(tls));
1081 }
1082
1083 qlock(&proctab);
1084 if((new = allocproc()) == nil){
1085 qunlock(&proctab);
1086 return -EAGAIN;
1087 }
1088 tid = new->tid;
1089
1090 if(args.flags & CLONE_PARENT_SETTID){
1091 if(!okaddr(args.parenttidptr, sizeof(*args.parenttidptr), 1)){
1092 freeproc(new);
1093 qunlock(&proctab);
1094 return -EFAULT;
1095 }
1096 *args.parenttidptr = tid;
1097 }
1098
1099 rflags = RFPROC;
1100 if(args.flags & CLONE_VM)
1101 rflags |= RFMEM;
1102
1103 qlock(current);
1104 if((pid = rfork(rflags)) < 0){
1105 freeproc(new);
1106 qunlock(current);
1107 qunlock(&proctab);
1108
1109 trace("kcloneproc(): rfork failed: %r");
1110 return mkerror();
1111 }
1112
1113 if(pid){
1114 /* parent */
1115 new->kpid = pid;
1116 new->exitsignal = args.flags & 0xFF;
1117 new->innote = 0;
1118 new->ureg = &ureg;
1119 new->syscall = current->syscall;
1120 new->sysret = current->sysret;
1121 new->comm = nil;
1122 new->ncomm = 0;
1123 new->linkloop = 0;
1124 new->root = current->root ? kstrdup(current->root) : nil;
1125 new->cwd = kstrdup(current->cwd);
1126 new->kcwd = kstrdup(current->kcwd);
1127 new->starttime = nsec();
1128
1129 snprint(buf, sizeof(buf), "/proc/%d/note", pid);
1130 new->notefd = open(buf, OWRITE);
1131 snprint(buf, sizeof(buf), "/proc/%d/args", pid);
1132 new->argsfd = open(buf, ORDWR);
1133
1134 if(args.flags & (CLONE_THREAD | CLONE_PARENT)){
1135 new->ppid = current->ppid;
1136 } else {
1137 new->ppid = current->pid;
1138 }
1139
1140 if(args.flags & CLONE_THREAD)
1141 new->pid = current->pid;
1142
1143 new->cleartidptr = nil;
1144 if(args.flags & CLONE_CHILD_CLEARTID)
1145 new->cleartidptr = args.childtidptr;
1146
1147 new->pgid = current->pgid;
1148 new->psid = current->psid;
1149 new->uid = current->uid;
1150 new->gid = current->gid;
1151
1152 clonetrace(new, !(args.flags & CLONE_THREAD));
1153 clonesignal(new, !(args.flags & CLONE_SIGHAND), !(args.flags & CLONE_THREAD));
1154 clonemem(new, !(args.flags & CLONE_VM));
1155 clonefile(new, !(args.flags & CLONE_FILES));
1156 clonetls(new);
1157 qunlock(&proctab);
1158
1159 while(rendezvous(new, 0) == (void*)~0)
1160 ;
1161
1162 qunlock(current);
1163
1164 return tid;
1165 }
1166
1167 /* child */
1168 current = new;
1169 profme();
1170
1171 /* wait for parent to copy our resources */
1172 while(rendezvous(new, 0) == (void*)~0)
1173 ;
1174
1175 trace("kcloneproc(): hello world");
1176
1177 if(args.flags & CLONE_SETTLS)
1178 sys_set_thread_area(&tls);
1179
1180 if(args.flags & CLONE_CHILD_SETTID)
1181 if(okaddr(args.childtidptr, sizeof(*args.childtidptr), 1))
1182 *args.childtidptr = tid;
1183
1184 if(args.newstack != nil)
1185 current->ureg->sp = (ulong)args.newstack;
1186 current->sysret(0);
1187 retuser();
1188
1189 return -1;
1190}
1191
1192#pragma profile on
1193
1194int sys_linux_clone(int flags, void *newstack, int *parenttidptr, int *tlsdescr, void *childtidptr)
1195{
1196 struct kcloneprocargs a;
1197
1198 trace("sys_linux_clone(%x, %p, %p, %p, %p)", flags, newstack, parenttidptr, childtidptr, tlsdescr);
1199
1200 a.flags = flags;
1201 a.newstack = newstack;
1202 a.parenttidptr = parenttidptr;
1203 a.childtidptr = childtidptr;
1204 a.tlsdescr = tlsdescr;
1205
1206 return onstack(kstack, kcloneproc, &a);
1207}
1208
1209int sys_fork(void)
1210{
1211 trace("sys_fork()");
1212
1213 return sys_linux_clone(SIGCHLD, nil, nil, nil, nil);
1214}
1215
1216int sys_vfork(void)
1217{
1218 trace("sys_vfork()");
1219
1220 return sys_fork();
1221}
1222
1223int sys_getpid(void)
1224{
1225 trace("sys_getpid()");
1226
1227 return current->pid;
1228}
1229
1230int sys_getppid(void)
1231{
1232 trace("sys_getppid()");
1233
1234 return current->ppid;
1235}
1236
1237int sys_gettid(void)
1238{
1239 trace("sys_gettid()");
1240
1241 return current->tid;
1242}
1243
1244int sys_setpgid(int pid, int pgid)
1245{
1246 int i, n;
1247
1248 trace("sys_setpgid(%d, %d)", pid, pgid);
1249
1250 if(pgid == 0)
1251 pgid = current->pgid;
1252 if(pid == 0)
1253 pid = current->pid;
1254
1255 n = 0;
1256 qlock(&proctab);
1257 for(i=0; i<MAXPROC; i++){
1258 Uproc *p;
1259
1260 if((p = getprocn(i)) == nil)
1261 continue;
1262 if(p->pid != pid)
1263 continue;
1264
1265 p->pgid = pgid;
1266 n++;
1267 }
1268 qunlock(&proctab);
1269
1270 return n ? 0 : -ESRCH;
1271}
1272
1273int sys_getpgid(int pid)
1274{
1275 int i;
1276 int pgid;
1277
1278 trace("sys_getpgid(%d)", pid);
1279
1280 pgid = -ESRCH;
1281 if(pid == 0)
1282 return current->pgid;
1283 qlock(&proctab);
1284 for(i=0; i<MAXPROC; i++){
1285 Uproc *p;
1286
1287 if((p = getprocn(i)) == nil)
1288 continue;
1289 if(p->pid != pid)
1290 continue;
1291
1292 pgid = p->pgid;
1293 break;
1294 }
1295 qunlock(&proctab);
1296
1297 return pgid;
1298}
1299
1300int sys_getpgrp(void)
1301{
1302 trace("sys_getpgrp()");
1303
1304 return sys_getpgid(0);
1305}
1306
1307int sys_getuid(void)
1308{
1309 trace("sys_getuid()");
1310
1311 return current->uid;
1312}
1313
1314int sys_getgid(void)
1315{
1316 trace("sys_getgid()");
1317
1318 return current->gid;
1319}
1320
1321int sys_setuid(int uid)
1322{
1323 trace("sys_setuid(%d)", uid);
1324
1325 current->uid = uid;
1326 return 0;
1327}
1328
1329int sys_setgid(int gid)
1330{
1331 trace("sys_setgid(%d)", gid);
1332
1333 current->gid = gid;
1334 return 0;
1335}
1336
1337int sys_setresuid(int ruid, int euid, int suid)
1338{
1339 trace("sys_setresuid(%d, %d, %d)", ruid, euid, suid);
1340
1341 return 0;
1342}
1343
1344int sys_setresgid(int rgid, int egid, int sgid)
1345{
1346 trace("sys_setresgid(%d, %d, %d)", rgid, egid, sgid);
1347
1348 return 0;
1349}
1350int sys_setreuid(int ruid, int euid)
1351{
1352 trace("sys_setreuid(%d, %d)", ruid, euid);
1353
1354 return 0;
1355}
1356
1357int sys_setregid(int rgid, int egid)
1358{
1359 trace("sys_setregid(%d, %d)", rgid, egid);
1360
1361 return 0;
1362}
1363
1364int sys_getresuid(int *ruid, int *euid, int *suid)
1365{
1366 trace("sys_getresuid(%p, %p, %p)", ruid, euid, suid);
1367
1368 if(ruid == nil)
1369 return -EINVAL;
1370 if(euid == nil)
1371 return -EINVAL;
1372 if(suid == nil)
1373 return -EINVAL;
1374
1375 *ruid = current->uid;
1376 *euid = current->uid;
1377 *suid = current->uid;
1378
1379 return 0;
1380}
1381
1382int sys_getresgid(int *rgid, int *egid, int *sgid)
1383{
1384 trace("sys_getresgid(%p, %p, %p)", rgid, egid, sgid);
1385
1386 if(rgid == nil)
1387 return -EINVAL;
1388 if(egid == nil)
1389 return -EINVAL;
1390 if(sgid == nil)
1391 return -EINVAL;
1392
1393 *rgid = current->gid;
1394 *egid = current->gid;
1395 *sgid = current->gid;
1396
1397 return 0;
1398}
1399
1400int sys_setsid(void)
1401{
1402 int i;
1403
1404 trace("sys_setsid()");
1405
1406 if(current->pid == current->pgid)
1407 return -EPERM;
1408
1409 qlock(&proctab);
1410 for(i=0; i<MAXPROC; i++){
1411 Uproc *p;
1412
1413 if((p = getprocn(i)) == nil)
1414 continue;
1415 if(p->pid != current->pid)
1416 continue;
1417 p->pgid = current->pid;
1418 p->psid = current->pid;
1419 }
1420 qunlock(&proctab);
1421
1422 settty(nil);
1423
1424 return current->pgid;
1425}
1426
1427int sys_getsid(int pid)
1428{
1429 int i, pgid;
1430
1431 trace("sys_getsid(%d)", pid);
1432
1433 pgid = -ESRCH;
1434 if(pid == 0)
1435 pid = current->pid;
1436 qlock(&proctab);
1437 for(i=0; i<MAXPROC; i++){
1438 Uproc *p;
1439
1440 if((p = getprocn(i)) == nil)
1441 continue;
1442 if(p->pid != pid)
1443 continue;
1444 if(p->pid != p->psid)
1445 continue;
1446 pgid = p->pgid;
1447 break;
1448 }
1449 qunlock(&proctab);
1450
1451 return pgid;
1452}
1453
1454int sys_getgroups(int size, int *groups)
1455{
1456 trace("sys_getgroups(%d, %p)", size, groups);
1457 if(size < 0)
1458 return -EINVAL;
1459 return 0;
1460}
1461
1462int sys_setgroups(int size, int *groups)
1463{
1464 trace("sys_setgroups(%d, %p)", size, groups);
1465 return 0;
1466}
1467
1468struct linux_utsname
1469{
1470 char sysname[65];
1471 char nodename[65];
1472 char release[65];
1473 char version[65];
1474 char machine[65];
1475 char domainname[65];
1476};
1477
1478int sys_uname(void *a)
1479{
1480 struct linux_utsname *p = a;
1481
1482 trace("sys_uname(%p)", a);
1483
1484 strncpy(p->sysname, "Linux", 65);
1485 strncpy(p->nodename, sysname(), 65);
1486 strncpy(p->release, "3.2.1", 65);
1487 strncpy(p->version, "linuxemu", 65);
1488 strncpy(p->machine, "i386", 65);
1489 strncpy(p->domainname, sysname(), 65);
1490
1491 return 0;
1492}
1493
1494int sys_personality(ulong p)
1495{
1496 trace("sys_personality(%lux)", p);
1497
1498 if(p != 0 && p != 0xffffffff)
1499 return -EINVAL;
1500 return 0;
1501}
1502
1503int sys_tkill(int tid, int sig)
1504{
1505 int err;
1506
1507 trace("sys_tkill(%d, %S)", tid, sig);
1508
1509 err = -EINVAL;
1510 if(tid > 0){
1511 Uproc *p;
1512
1513 err = -ESRCH;
1514 qlock(&proctab);
1515 if(p = getproc(tid)){
1516 Usiginfo si;
1517
1518 memset(&si, 0, sizeof(si));
1519 si.signo = sig;
1520 si.code = SI_TKILL;
1521 si.kill.pid = current->tid;
1522 si.kill.uid = current->uid;
1523 err = killproc(p, &si, 0);
1524 }
1525 qunlock(&proctab);
1526 }
1527 return err;
1528}
1529
1530int sys_tgkill(int pid, int tid, int sig)
1531{
1532 int err;
1533
1534 trace("sys_tgkill(%d, %d, %S)", pid, tid, sig);
1535
1536 err = -EINVAL;
1537 if(tid > 0){
1538 Uproc *p;
1539
1540 err = -ESRCH;
1541 qlock(&proctab);
1542 if((p = getproc(tid)) && (p->pid == pid)){
1543 Usiginfo si;
1544
1545 memset(&si, 0, sizeof(si));
1546 si.signo = sig;
1547 si.code = SI_TKILL;
1548 si.kill.pid = current->tid;
1549 si.kill.uid = current->uid;
1550 err = killproc(p, &si, 0);
1551 }
1552 qunlock(&proctab);
1553 }
1554 return err;
1555}
1556
1557int sys_rt_sigqueueinfo(int pid, int sig, void *info)
1558{
1559 int err;
1560 Uproc *p;
1561 Usiginfo si;
1562
1563 trace("sys_rt_sigqueueinfo(%d, %S, %p)", pid, sig, info);
1564
1565 err = -ESRCH;
1566 qlock(&proctab);
1567 if(p = getproc(pid)){
1568 memset(&si, 0, sizeof(si));
1569 linux2siginfo(info, &si);
1570 si.signo = sig;
1571 si.code = SI_QUEUE;
1572 err = killproc(p, &si, 1);
1573 }
1574 qunlock(&proctab);
1575 return err;
1576}
1577
1578enum {
1579 PIDMAPBITS1 = 8*sizeof(ulong),
1580};
1581
1582int sys_kill(int pid, int sig)
1583{
1584 int i, j, n;
1585 Uproc *p;
1586 Usiginfo si;
1587 ulong pidmap[(MAXPROC + PIDMAPBITS1-1) / PIDMAPBITS1];
1588 ulong m;
1589
1590 trace("sys_kill(%d, %S)", pid, sig);
1591
1592 n = 0;
1593 memset(pidmap, 0, sizeof(pidmap));
1594 qlock(&proctab);
1595 for(i=0; i<MAXPROC; i++){
1596 if((p = getprocn(i)) == nil)
1597 continue;
1598 if(p->wstate & WEXITED)
1599 continue;
1600 if(p->kpid <= 0)
1601 continue;
1602
1603 if(pid == 0){
1604 if(p->pgid != current->pgid)
1605 continue;
1606 } else if(pid == -1){
1607 if(p->pid <= 1)
1608 continue;
1609 if(p->tid == current->tid)
1610 continue;
1611 } else if(pid < -1) {
1612 if(p->pgid != -pid)
1613 continue;
1614 } else {
1615 if(p->pid != pid)
1616 continue;
1617 }
1618
1619 /* make sure we send only one signal per pid */
1620 j = pidhash(p->pid);
1621 m = 1 << (j % PIDMAPBITS1);
1622 j /= PIDMAPBITS1;
1623 if(pidmap[j] & m)
1624 continue;
1625 pidmap[j] |= m;
1626
1627 if(sig > 0){
1628 memset(&si, 0, sizeof(si));
1629 si.signo = sig;
1630 si.code = SI_USER;
1631 si.kill.pid = current->tid;
1632 si.kill.uid = current->uid;
1633 killproc(p, &si, 1);
1634 }
1635 n++;
1636 }
1637 qunlock(&proctab);
1638 if(n == 0)
1639 return -ESRCH;
1640 return 0;
1641}
1642
1643int sys_set_tid_address(int *tidptr)
1644{
1645 trace("sys_set_tid_address(%p)", tidptr);
1646
1647 current->cleartidptr = tidptr;
1648 return current->pid;
1649}
1650
1651struct linux_sched_param
1652{
1653 int sched_priority;
1654};
1655
1656int sys_sched_setscheduler(int pid, int policy, void *param)
1657{
1658 trace("sys_sched_setscheduler(%d, %d, %p)", pid, policy, param);
1659
1660 if(getproc(pid) == nil)
1661 return -ESRCH;
1662 return 0;
1663}
1664
1665int sys_sched_getscheduler(int pid)
1666{
1667 trace("sys_sched_getscheduler(%d)", pid);
1668
1669 if(getproc(pid) == nil)
1670 return -ESRCH;
1671 return 0;
1672}
1673
1674int sys_sched_setparam(int pid, void *param)
1675{
1676 trace("sys_sched_setparam(%d, %p)", pid, param);
1677
1678 if(getproc(pid) == nil)
1679 return -ESRCH;
1680 return 0;
1681}
1682
1683int sys_sched_getparam(int pid, void *param)
1684{
1685 struct linux_sched_param *p = param;
1686
1687 trace("sys_sched_getparam(%d, %p)", pid, param);
1688
1689 if(getproc(pid) == nil)
1690 return -ESRCH;
1691 if(p == nil)
1692 return -EINVAL;
1693 p->sched_priority = 0;
1694
1695 return 0;
1696}
1697
1698int sys_sched_yield(void)
1699{
1700 trace("sys_sched_yield()");
1701
1702 sleep(0);
1703 return 0;
1704}
1705
1706enum {
1707 RLIMIT_CPU,
1708 RLIMIT_FSIZE,
1709 RLIMIT_DATA,
1710 RLIMIT_STACK,
1711 RLIMIT_CORE,
1712 RLIMIT_RSS,
1713 RLIMIT_NPROC,
1714 RLIMIT_NOFILE,
1715 RLIMIT_MEMLOCK,
1716 RLIMIT_AS,
1717 RLIMIT_LOCKS,
1718 RLIMIT_SIGPENDING,
1719 RLIMIT_MSGQUEUE,
1720
1721 RLIM_NLIMITS,
1722
1723 RLIM_INFINITY = ~0UL,
1724};
1725
1726struct linux_rlimit
1727{
1728 ulong rlim_cur;
1729 ulong rlim_max;
1730};
1731
1732int sys_getrlimit(long resource, void *rlim)
1733{
1734 struct linux_rlimit *r = rlim;
1735
1736 trace("sys_getrlimit(%ld, %p)", resource, rlim);
1737
1738 if(resource >= RLIM_NLIMITS)
1739 return -EINVAL;
1740 if(rlim == nil)
1741 return -EFAULT;
1742
1743 r->rlim_cur = RLIM_INFINITY;
1744 r->rlim_max = RLIM_INFINITY;
1745
1746 switch(resource){
1747 case RLIMIT_STACK:
1748 r->rlim_cur = USTACK;
1749 r->rlim_max = USTACK;
1750 break;
1751 case RLIMIT_CORE:
1752 r->rlim_cur = 0;
1753 break;
1754 case RLIMIT_NPROC:
1755 r->rlim_cur = MAXPROC;
1756 r->rlim_max = MAXPROC;
1757 break;
1758 case RLIMIT_NOFILE:
1759 r->rlim_cur = MAXFD;
1760 r->rlim_max = MAXFD;
1761 break;
1762 }
1763 return 0;
1764}
1765
1766int sys_setrlimit(long resource, void *rlim)
1767{
1768 trace("sys_setrlimit(%ld, %p)", resource, rlim);
1769
1770 if(resource >= RLIM_NLIMITS)
1771 return -EINVAL;
1772 if(rlim == nil)
1773 return -EFAULT;
1774
1775 return -EPERM;
1776}
1777