xref: /plan9/sys/src/9/port/sysproc.c (revision 6a9fc400c33447ef5e1cda7185cb4de2c8e8010e)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"../port/error.h"
7 
8 #include	<a.out.h>
9 
10 int	shargs(char*, int, char**);
11 
12 Ref sysr1ref;
13 
14 long
15 sysr1(ulong *arg)
16 {
17 	long a;
18 
19 	a = *arg;
20 	if(a > 0)
21 		return incref(&sysr1ref);
22 	if(a < 0)
23 		return decref(&sysr1ref);
24 	return sysr1ref.ref;
25 
26 /*
27 	extern int chandebug;
28 	extern void dumpmount(void);
29 
30 	print("[%s %s %lud] r1 = %lud\n", up->user, up->text, up->pid, arg[0]);
31 	chandebug=!chandebug;
32 	if(chandebug)
33 		dumpmount();
34 
35 	return 0;
36 */
37 }
38 
39 long
40 sysrfork(ulong *arg)
41 {
42 	Proc *p;
43 	int n, i;
44 	Fgrp *ofg;
45 	Pgrp *opg;
46 	Rgrp *org;
47 	Egrp *oeg;
48 	ulong pid, flag;
49 	Mach *wm;
50 
51 	flag = arg[0];
52 	/* Check flags before we commit */
53 	if((flag & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG))
54 		error(Ebadarg);
55 	if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG))
56 		error(Ebadarg);
57 	if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG))
58 		error(Ebadarg);
59 
60 	if((flag&RFPROC) == 0) {
61 		if(flag & (RFMEM|RFNOWAIT))
62 			error(Ebadarg);
63 		if(flag & (RFFDG|RFCFDG)) {
64 			ofg = up->fgrp;
65 			if(flag & RFFDG)
66 				up->fgrp = dupfgrp(ofg);
67 			else
68 				up->fgrp = dupfgrp(nil);
69 			closefgrp(ofg);
70 		}
71 		if(flag & (RFNAMEG|RFCNAMEG)) {
72 			opg = up->pgrp;
73 			up->pgrp = newpgrp();
74 			if(flag & RFNAMEG)
75 				pgrpcpy(up->pgrp, opg);
76 			/* inherit noattach */
77 			up->pgrp->noattach = opg->noattach;
78 			closepgrp(opg);
79 		}
80 		if(flag & RFNOMNT)
81 			up->pgrp->noattach = 1;
82 		if(flag & RFREND) {
83 			org = up->rgrp;
84 			up->rgrp = newrgrp();
85 			closergrp(org);
86 		}
87 		if(flag & (RFENVG|RFCENVG)) {
88 			oeg = up->egrp;
89 			up->egrp = smalloc(sizeof(Egrp));
90 			up->egrp->ref = 1;
91 			if(flag & RFENVG)
92 				envcpy(up->egrp, oeg);
93 			closeegrp(oeg);
94 		}
95 		if(flag & RFNOTEG)
96 			up->noteid = incref(&noteidalloc);
97 		return 0;
98 	}
99 
100 	p = newproc();
101 
102 	p->fpsave = up->fpsave;
103 	p->scallnr = up->scallnr;
104 	p->s = up->s;
105 	p->nerrlab = 0;
106 	p->slash = up->slash;
107 	p->dot = up->dot;
108 	incref(p->dot);
109 
110 	memmove(p->note, up->note, sizeof(p->note));
111 	p->privatemem = up->privatemem;
112 	p->noswap = up->noswap;
113 	p->nnote = up->nnote;
114 	p->notified = 0;
115 	p->lastnote = up->lastnote;
116 	p->notify = up->notify;
117 	p->ureg = up->ureg;
118 	p->dbgreg = 0;
119 
120 	/* Make a new set of memory segments */
121 	n = flag & RFMEM;
122 	qlock(&p->seglock);
123 	if(waserror()){
124 		qunlock(&p->seglock);
125 		nexterror();
126 	}
127 	for(i = 0; i < NSEG; i++)
128 		if(up->seg[i])
129 			p->seg[i] = dupseg(up->seg, i, n);
130 	qunlock(&p->seglock);
131 	poperror();
132 
133 	/* File descriptors */
134 	if(flag & (RFFDG|RFCFDG)) {
135 		if(flag & RFFDG)
136 			p->fgrp = dupfgrp(up->fgrp);
137 		else
138 			p->fgrp = dupfgrp(nil);
139 	}
140 	else {
141 		p->fgrp = up->fgrp;
142 		incref(p->fgrp);
143 	}
144 
145 	/* Process groups */
146 	if(flag & (RFNAMEG|RFCNAMEG)) {
147 		p->pgrp = newpgrp();
148 		if(flag & RFNAMEG)
149 			pgrpcpy(p->pgrp, up->pgrp);
150 		/* inherit noattach */
151 		p->pgrp->noattach = up->pgrp->noattach;
152 	}
153 	else {
154 		p->pgrp = up->pgrp;
155 		incref(p->pgrp);
156 	}
157 	if(flag & RFNOMNT)
158 		up->pgrp->noattach = 1;
159 
160 	if(flag & RFREND)
161 		p->rgrp = newrgrp();
162 	else {
163 		incref(up->rgrp);
164 		p->rgrp = up->rgrp;
165 	}
166 
167 	/* Environment group */
168 	if(flag & (RFENVG|RFCENVG)) {
169 		p->egrp = smalloc(sizeof(Egrp));
170 		p->egrp->ref = 1;
171 		if(flag & RFENVG)
172 			envcpy(p->egrp, up->egrp);
173 	}
174 	else {
175 		p->egrp = up->egrp;
176 		incref(p->egrp);
177 	}
178 	p->hang = up->hang;
179 	p->procmode = up->procmode;
180 
181 	/* Craft a return frame which will cause the child to pop out of
182 	 * the scheduler in user mode with the return register zero
183 	 */
184 	forkchild(p, up->dbgreg);
185 
186 	p->parent = up;
187 	p->parentpid = up->pid;
188 	if(flag&RFNOWAIT)
189 		p->parentpid = 0;
190 	else {
191 		lock(&up->exl);
192 		up->nchild++;
193 		unlock(&up->exl);
194 	}
195 	if((flag&RFNOTEG) == 0)
196 		p->noteid = up->noteid;
197 
198 	p->fpstate = up->fpstate;
199 	pid = p->pid;
200 	memset(p->time, 0, sizeof(p->time));
201 	p->time[TReal] = MACHP(0)->ticks;
202 
203 	kstrdup(&p->text, up->text);
204 	kstrdup(&p->user, up->user);
205 	/*
206 	 *  since the bss/data segments are now shareable,
207 	 *  any mmu info about this process is now stale
208 	 *  (i.e. has bad properties) and has to be discarded.
209 	 */
210 	flushmmu();
211 	p->basepri = up->basepri;
212 	p->priority = up->basepri;
213 	p->fixedpri = up->fixedpri;
214 	p->mp = up->mp;
215 	wm = up->wired;
216 	if(wm)
217 		procwired(p, wm->machno);
218 	ready(p);
219 	sched();
220 	return pid;
221 }
222 
223 static ulong
224 l2be(long l)
225 {
226 	uchar *cp;
227 
228 	cp = (uchar*)&l;
229 	return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3];
230 }
231 
232 long
233 sysexec(ulong *arg)
234 {
235 	Segment *s, *ts;
236 	ulong t, d, b;
237 	int i;
238 	Chan *tc;
239 	char **argv, **argp;
240 	char *a, *charp, *args, *file;
241 	char *progarg[sizeof(Exec)/2+1], *elem, progelem[64];
242 	ulong ssize, spage, nargs, nbytes, n, bssend;
243 	int indir;
244 	Exec exec;
245 	char line[sizeof(Exec)];
246 	Fgrp *f;
247 	Image *img;
248 	ulong magic, text, entry, data, bss;
249 
250 	validaddr(arg[0], 1, 0);
251 	file = (char*)arg[0];
252 	indir = 0;
253 	elem = nil;
254 	if(waserror()){
255 		free(elem);
256 		nexterror();
257 	}
258 	for(;;){
259 		tc = namec(file, Aopen, OEXEC, 0);
260 		if(waserror()){
261 			cclose(tc);
262 			nexterror();
263 		}
264 		if(!indir)
265 			kstrdup(&elem, up->genbuf);
266 
267 		n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0);
268 		if(n < 2)
269 			error(Ebadexec);
270 		magic = l2be(exec.magic);
271 		text = l2be(exec.text);
272 		entry = l2be(exec.entry);
273 		if(n==sizeof(Exec) && (magic == AOUT_MAGIC)){
274 			if((text&KZERO) == KZERO
275 			|| entry < UTZERO+sizeof(Exec)
276 			|| entry >= UTZERO+sizeof(Exec)+text)
277 				error(Ebadexec);
278 			break; /* for binary */
279 		}
280 
281 		/*
282 		 * Process #! /bin/sh args ...
283 		 */
284 		memmove(line, &exec, sizeof(Exec));
285 		if(indir || line[0]!='#' || line[1]!='!')
286 			error(Ebadexec);
287 		n = shargs(line, n, progarg);
288 		if(n == 0)
289 			error(Ebadexec);
290 		indir = 1;
291 		/*
292 		 * First arg becomes complete file name
293 		 */
294 		progarg[n++] = file;
295 		progarg[n] = 0;
296 		validaddr(arg[1], BY2WD, 1);
297 		arg[1] += BY2WD;
298 		file = progarg[0];
299 		if(strlen(elem) >= sizeof progelem)
300 			error(Ebadexec);
301 		strcpy(progelem, elem);
302 		progarg[0] = progelem;
303 		poperror();
304 		cclose(tc);
305 	}
306 
307 	data = l2be(exec.data);
308 	bss = l2be(exec.bss);
309 	t = (UTZERO+sizeof(Exec)+text+(BY2PG-1)) & ~(BY2PG-1);
310 	d = (t + data + (BY2PG-1)) & ~(BY2PG-1);
311 	bssend = t + data + bss;
312 	b = (bssend + (BY2PG-1)) & ~(BY2PG-1);
313 	if(((t|d|b) & KZERO) == KZERO)
314 		error(Ebadexec);
315 
316 	/*
317 	 * Args: pass 1: count
318 	 */
319 	nbytes = BY2WD;		/* hole for profiling clock at top of stack */
320 	nargs = 0;
321 	if(indir){
322 		argp = progarg;
323 		while(*argp){
324 			a = *argp++;
325 			nbytes += strlen(a) + 1;
326 			nargs++;
327 		}
328 	}
329 	evenaddr(arg[1]);
330 	argp = (char**)arg[1];
331 	validaddr((ulong)argp, BY2WD, 0);
332 	while(*argp){
333 		a = *argp++;
334 		if(((ulong)argp&(BY2PG-1)) < BY2WD)
335 			validaddr((ulong)argp, BY2WD, 0);
336 		validaddr((ulong)a, 1, 0);
337 		nbytes += (vmemchr(a, 0, 0x7FFFFFFF) - a) + 1;
338 		nargs++;
339 	}
340 	ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1));
341 
342 	/*
343 	 * 8-byte align SP for those (e.g. sparc) that need it.
344 	 * execregs() will subtract another 4 bytes for argc.
345 	 */
346 	if((ssize+4) & 7)
347 		ssize += 4;
348 	spage = (ssize+(BY2PG-1)) >> PGSHIFT;
349 
350 	/*
351 	 * Build the stack segment, putting it in kernel virtual for the moment
352 	 */
353 	if(spage > TSTKSIZ)
354 		error(Enovmem);
355 
356 	qlock(&up->seglock);
357 	if(waserror()){
358 		qunlock(&up->seglock);
359 		nexterror();
360 	}
361 	up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG);
362 
363 	/*
364 	 * Args: pass 2: assemble; the pages will be faulted in
365 	 */
366 	argv = (char**)(TSTKTOP - ssize);
367 	charp = (char*)(TSTKTOP - nbytes);
368 	args = charp;
369 	if(indir)
370 		argp = progarg;
371 	else
372 		argp = (char**)arg[1];
373 
374 	for(i=0; i<nargs; i++){
375 		if(indir && *argp==0) {
376 			indir = 0;
377 			argp = (char**)arg[1];
378 		}
379 		*argv++ = charp + (USTKTOP-TSTKTOP);
380 		n = strlen(*argp) + 1;
381 		memmove(charp, *argp++, n);
382 		charp += n;
383 	}
384 
385 	free(up->text);
386 	up->text = elem;
387 	elem = nil;	/* so waserror() won't free elem */
388 	USED(elem);
389 
390 	/* copy args; easiest from new process's stack */
391 	n = charp - args;
392 	if(n > 128)	/* don't waste too much space on huge arg lists */
393 		n = 128;
394 	a = up->args;
395 	up->args = nil;
396 	free(a);
397 	up->args = smalloc(n);
398 	memmove(up->args, args, n);
399 	if(n>0 && up->args[n-1]!='\0'){
400 		/* make sure last arg is NUL-terminated */
401 		/* put NUL at UTF-8 character boundary */
402 		for(i=n-1; i>0; --i)
403 			if(fullrune(up->args+i, n-i))
404 				break;
405 		up->args[i] = 0;
406 		n = i+1;
407 	}
408 	up->nargs = n;
409 
410 	/*
411 	 * Committed.
412 	 * Free old memory.
413 	 * Special segments are maintained across exec
414 	 */
415 	for(i = SSEG; i <= BSEG; i++) {
416 		putseg(up->seg[i]);
417 		/* prevent a second free if we have an error */
418 		up->seg[i] = 0;
419 	}
420 	for(i = BSEG+1; i < NSEG; i++) {
421 		s = up->seg[i];
422 		if(s != 0 && (s->type&SG_CEXEC)) {
423 			putseg(s);
424 			up->seg[i] = 0;
425 		}
426 	}
427 
428 	/*
429 	 * Close on exec
430 	 */
431 	f = up->fgrp;
432 	for(i=0; i<=f->maxfd; i++)
433 		fdclose(i, CCEXEC);
434 
435 	/* Text.  Shared. Attaches to cache image if possible */
436 	/* attachimage returns a locked cache image */
437 	img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (t-UTZERO)>>PGSHIFT);
438 	ts = img->s;
439 	up->seg[TSEG] = ts;
440 	ts->flushme = 1;
441 	ts->fstart = 0;
442 	ts->flen = sizeof(Exec)+text;
443 	unlock(img);
444 
445 	/* Data. Shared. */
446 	s = newseg(SG_DATA, t, (d-t)>>PGSHIFT);
447 	up->seg[DSEG] = s;
448 
449 	/* Attached by hand */
450 	incref(img);
451 	s->image = img;
452 	s->fstart = ts->fstart+ts->flen;
453 	s->flen = data;
454 
455 	/* BSS. Zero fill on demand */
456 	up->seg[BSEG] = newseg(SG_BSS, d, (b-d)>>PGSHIFT);
457 
458 	/*
459 	 * Move the stack
460 	 */
461 	s = up->seg[ESEG];
462 	up->seg[ESEG] = 0;
463 	up->seg[SSEG] = s;
464 	qunlock(&up->seglock);
465 	poperror();	/* seglock */
466 	poperror();	/* elem */
467 	s->base = USTKTOP-USTKSIZE;
468 	s->top = USTKTOP;
469 	relocateseg(s, USTKTOP-TSTKTOP);
470 
471 	/*
472 	 *  '/' processes are higher priority (hack to make /ip more responsive).
473 	 */
474 	if(devtab[tc->type]->dc == L'/')
475 		up->basepri = PriRoot;
476 	up->priority = up->basepri;
477 	poperror();
478 	cclose(tc);
479 
480 	/*
481 	 *  At this point, the mmu contains info about the old address
482 	 *  space and needs to be flushed
483 	 */
484 	flushmmu();
485 	qlock(&up->debug);
486 	up->nnote = 0;
487 	up->notify = 0;
488 	up->notified = 0;
489 	up->privatemem = 0;
490 	procsetup(up);
491 	qunlock(&up->debug);
492 	if(up->hang)
493 		up->procctl = Proc_stopme;
494 
495 	return execregs(entry, ssize, nargs);
496 }
497 
498 int
499 shargs(char *s, int n, char **ap)
500 {
501 	int i;
502 
503 	s += 2;
504 	n -= 2;		/* skip #! */
505 	for(i=0; s[i]!='\n'; i++)
506 		if(i == n-1)
507 			return 0;
508 	s[i] = 0;
509 	*ap = 0;
510 	i = 0;
511 	for(;;) {
512 		while(*s==' ' || *s=='\t')
513 			s++;
514 		if(*s == 0)
515 			break;
516 		i++;
517 		*ap++ = s;
518 		*ap = 0;
519 		while(*s && *s!=' ' && *s!='\t')
520 			s++;
521 		if(*s == 0)
522 			break;
523 		else
524 			*s++ = 0;
525 	}
526 	return i;
527 }
528 
529 int
530 return0(void*)
531 {
532 	return 0;
533 }
534 
535 long
536 syssleep(ulong *arg)
537 {
538 
539 	int n;
540 
541 	n = arg[0];
542 	if(n <= 0) {
543 		up->priority = 0;
544 		sched();
545 		return 0;
546 	}
547 	if(n < TK2MS(1))
548 		n = TK2MS(1);
549 	tsleep(&up->sleep, return0, 0, n);
550 	return 0;
551 }
552 
553 long
554 sysalarm(ulong *arg)
555 {
556 	return procalarm(arg[0]);
557 }
558 
559 long
560 sysexits(ulong *arg)
561 {
562 	char *status;
563 	char *inval = "invalid exit string";
564 	char buf[ERRMAX];
565 
566 	status = (char*)arg[0];
567 	if(status){
568 		if(waserror())
569 			status = inval;
570 		else{
571 			validaddr((ulong)status, 1, 0);
572 			if(vmemchr(status, 0, ERRMAX) == 0){
573 				memmove(buf, status, ERRMAX);
574 				buf[ERRMAX-1] = 0;
575 				status = buf;
576 			}
577 		}
578 		poperror();
579 
580 	}
581 	pexit(status, 1);
582 	return 0;		/* not reached */
583 }
584 
585 long
586 sys_wait(ulong *arg)
587 {
588 	int pid;
589 	Waitmsg w;
590 	OWaitmsg *ow;
591 
592 	if(arg[0] == 0)
593 		return pwait(nil);
594 
595 	validaddr(arg[0], sizeof(OWaitmsg), 1);
596 	evenaddr(arg[0]);
597 	pid = pwait(&w);
598 	if(pid >= 0){
599 		ow = (OWaitmsg*)arg[0];
600 		readnum(0, ow->pid, NUMSIZE, w.pid, NUMSIZE);
601 		readnum(0, ow->time+TUser*NUMSIZE, NUMSIZE, w.time[TUser], NUMSIZE);
602 		readnum(0, ow->time+TSys*NUMSIZE, NUMSIZE, w.time[TSys], NUMSIZE);
603 		readnum(0, ow->time+TReal*NUMSIZE, NUMSIZE, w.time[TReal], NUMSIZE);
604 		strncpy(ow->msg, w.msg, sizeof(ow->msg));
605 		ow->msg[sizeof(ow->msg)-1] = '\0';
606 	}
607 	return pid;
608 }
609 
610 long
611 sysawait(ulong *arg)
612 {
613 	int i;
614 	int pid;
615 	Waitmsg w;
616 	ulong n;
617 
618 	n = arg[1];
619 	validaddr(arg[0], n, 1);
620 	pid = pwait(&w);
621 	if(pid < 0)
622 		return -1;
623 	i = snprint((char*)arg[0], n, "%d %lud %lud %lud %q",
624 		w.pid,
625 		w.time[TUser], w.time[TSys], w.time[TReal],
626 		w.msg);
627 
628 	return i;
629 }
630 
631 long
632 sysdeath(ulong*)
633 {
634 	pprint("deprecated system call\n");
635 	pexit("Suicide", 0);
636 	return 0;	/* not reached */
637 }
638 
639 void
640 werrstr(char *fmt, ...)
641 {
642 	va_list va;
643 
644 	if(up == nil)
645 		return;
646 
647 	va_start(va, fmt);
648 	vseprint(up->syserrstr, up->syserrstr+ERRMAX, fmt, va);
649 	va_end(va);
650 }
651 
652 static long
653 generrstr(char *buf, uint nbuf)
654 {
655 	char tmp[ERRMAX];
656 
657 	if(nbuf == 0)
658 		error(Ebadarg);
659 	validaddr((ulong)buf, nbuf, 1);
660 	if(nbuf > sizeof tmp)
661 		nbuf = sizeof tmp;
662 	memmove(tmp, buf, nbuf);
663 	/* make sure it's NUL-terminated */
664 	tmp[nbuf-1] = '\0';
665 	memmove(buf, up->syserrstr, nbuf);
666 	buf[nbuf-1] = '\0';
667 	memmove(up->syserrstr, tmp, nbuf);
668 	return 0;
669 }
670 
671 long
672 syserrstr(ulong *arg)
673 {
674 	return generrstr((char*)arg[0], arg[1]);
675 }
676 
677 /* compatibility for old binaries */
678 long
679 sys_errstr(ulong *arg)
680 {
681 	return generrstr((char*)arg[0], 64);
682 }
683 
684 long
685 sysnotify(ulong *arg)
686 {
687 	if(arg[0] != 0)
688 		validaddr(arg[0], sizeof(ulong), 0);
689 	up->notify = (int(*)(void*, char*))(arg[0]);
690 	return 0;
691 }
692 
693 long
694 sysnoted(ulong *arg)
695 {
696 	if(arg[0]!=NRSTR && !up->notified)
697 		error(Egreg);
698 	return 0;
699 }
700 
701 long
702 syssegbrk(ulong *arg)
703 {
704 	int i;
705 	ulong addr;
706 	Segment *s;
707 
708 	addr = arg[0];
709 	for(i = 0; i < NSEG; i++) {
710 		s = up->seg[i];
711 		if(s == 0 || addr < s->base || addr >= s->top)
712 			continue;
713 		switch(s->type&SG_TYPE) {
714 		case SG_TEXT:
715 		case SG_DATA:
716 		case SG_STACK:
717 			error(Ebadarg);
718 		default:
719 			return ibrk(arg[1], i);
720 		}
721 	}
722 
723 	error(Ebadarg);
724 	return 0;		/* not reached */
725 }
726 
727 long
728 syssegattach(ulong *arg)
729 {
730 	return segattach(up, arg[0], (char*)arg[1], arg[2], arg[3]);
731 }
732 
733 long
734 syssegdetach(ulong *arg)
735 {
736 	int i;
737 	ulong addr;
738 	Segment *s;
739 
740 	qlock(&up->seglock);
741 	if(waserror()){
742 		qunlock(&up->seglock);
743 		nexterror();
744 	}
745 
746 	s = 0;
747 	addr = arg[0];
748 	for(i = 0; i < NSEG; i++)
749 		if(s = up->seg[i]) {
750 			qlock(&s->lk);
751 			if((addr >= s->base && addr < s->top) ||
752 			   (s->top == s->base && addr == s->base))
753 				goto found;
754 			qunlock(&s->lk);
755 		}
756 
757 	error(Ebadarg);
758 
759 found:
760 	/* Check we are not detaching the current stack segment */
761 	if((ulong)arg >= s->base && (ulong)arg < s->top) {
762 		qunlock(&s->lk);
763 		error(Ebadarg);
764 	}
765 	up->seg[i] = 0;
766 	qunlock(&s->lk);
767 	putseg(s);
768 	qunlock(&up->seglock);
769 	poperror();
770 
771 	/* Ensure we flush any entries from the lost segment */
772 	flushmmu();
773 	return 0;
774 }
775 
776 long
777 syssegfree(ulong *arg)
778 {
779 	Segment *s;
780 	ulong from, to;
781 
782 	from = arg[0];
783 	s = seg(up, from, 1);
784 	if(s == nil)
785 		error(Ebadarg);
786 	to = (from + arg[1]) & ~(BY2PG-1);
787 	from = PGROUND(from);
788 
789 	if(to > s->top) {
790 		qunlock(&s->lk);
791 		error(Ebadarg);
792 	}
793 
794 	mfreeseg(s, from, (to - from) / BY2PG);
795 	qunlock(&s->lk);
796 	flushmmu();
797 
798 	return 0;
799 }
800 
801 /* For binary compatibility */
802 long
803 sysbrk_(ulong *arg)
804 {
805 	return ibrk(arg[0], BSEG);
806 }
807 
808 long
809 sysrendezvous(ulong *arg)
810 {
811 	ulong tag;
812 	ulong val;
813 	Proc *p, **l;
814 
815 	tag = arg[0];
816 	l = &REND(up->rgrp, tag);
817 	up->rendval = ~0UL;
818 
819 	lock(up->rgrp);
820 	for(p = *l; p; p = p->rendhash) {
821 		if(p->rendtag == tag) {
822 			*l = p->rendhash;
823 			val = p->rendval;
824 			p->rendval = arg[1];
825 
826 			while(p->mach != 0)
827 				;
828 			ready(p);
829 			unlock(up->rgrp);
830 			return val;
831 		}
832 		l = &p->rendhash;
833 	}
834 
835 	/* Going to sleep here */
836 	up->rendtag = tag;
837 	up->rendval = arg[1];
838 	up->rendhash = *l;
839 	*l = up;
840 	up->state = Rendezvous;
841 	unlock(up->rgrp);
842 	if (edf->isedf(up))
843 		edf->edfblock(up);
844 
845 	sched();
846 
847 	return up->rendval;
848 }
849