200 lines · 3.2 KB · C
RawDownload
#include "threadimpl.h" static Lock thewaitlock;static Channel *thewaitchan; static voidexecproc(void *v){	int pid;	Channel *c;	Execjob *e;	Waitmsg *w; 	e = v;	pid = _threadspawn(e->fd, e->cmd, e->argv);	sendul(e->c, pid);	if(pid > 0){		w = waitfor(pid);		if((c = thewaitchan) != nil)			sendp(c, w);		else			free(w);	}	threadexits(nil);} int_runthreadspawn(int *fd, char *cmd, char **argv){	int pid;	Execjob e; 	e.fd = fd;	e.cmd = cmd;	e.argv = argv;	e.c = chancreate(sizeof(void*), 0);	proccreate(execproc, &e, 65536);	pid = recvul(e.c);	chanfree(e.c);	return pid;} Channel*threadwaitchan(void){	if(thewaitchan)		return thewaitchan;	lock(&thewaitlock);	if(thewaitchan){		unlock(&thewaitlock);		return thewaitchan;	}	thewaitchan = chancreate(sizeof(Waitmsg*), 4);	chansetname(thewaitchan, "threadwaitchan");	unlock(&thewaitlock);	return thewaitchan;} int_threadspawn(int fd[3], char *cmd, char *argv[]){	int i, n, p[2], pid;	char exitstr[100]; 	notifyoff("sys: child");	/* do not let child note kill us */	if(pipe(p) < 0)		return -1;	if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0){		close(p[0]);		close(p[1]);		return -1;	}	switch(pid = fork()){	case -1:		close(p[0]);		close(p[1]);		return -1;	case 0:		/* can't RFNOTEG - will lose tty */		dup2(fd[0], 0);		dup2(fd[1], 1);		dup2(fd[2], 2);		if(!isatty(0) && !isatty(1) && !isatty(2))			rfork(RFNOTEG);		for(i=3; i<100; i++)			if(i != p[1])				close(i);		execvp(cmd, argv);		fprint(p[1], "%d", errno);		close(p[1]);		_exit(0);	} 	close(p[1]);	n = read(p[0], exitstr, sizeof exitstr-1);	close(p[0]);	if(n > 0){	/* exec failed */		free(waitfor(pid));		exitstr[n] = 0;		errno = atoi(exitstr);		return -1;	} 	close(fd[0]);	if(fd[1] != fd[0])		close(fd[1]);	if(fd[2] != fd[1] && fd[2] != fd[0])		close(fd[2]);	return pid;} intthreadspawn(int fd[3], char *cmd, char *argv[]){	return _runthreadspawn(fd, cmd, argv);} intthreadspawnl(int fd[3], char *cmd, ...){	char **argv, *s;	int n, pid;	va_list arg; 	va_start(arg, cmd);	for(n=0; va_arg(arg, char*) != nil; n++)		;	n++;	va_end(arg); 	argv = malloc(n*sizeof(argv[0]));	if(argv == nil)		return -1; 	va_start(arg, cmd);	for(n=0; (s=va_arg(arg, char*)) != nil; n++)		argv[n] = s;	argv[n] = 0;	va_end(arg); 	pid = threadspawn(fd, cmd, argv);	free(argv);	return pid;} int_threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[]){	int pid; 	pid = threadspawn(fd, cmd, argv);	if(cpid){		if(pid < 0)			chansendul(cpid, ~0);		else			chansendul(cpid, pid);	}	return pid;} voidthreadexec(Channel *cpid, int fd[3], char *cmd, char *argv[]){	if(_threadexec(cpid, fd, cmd, argv) >= 0)		threadexits("threadexec");} voidthreadexecl(Channel *cpid, int fd[3], char *cmd, ...){	char **argv, *s;	int n, pid;	va_list arg; 	va_start(arg, cmd);	for(n=0; va_arg(arg, char*) != nil; n++)		;	n++;	va_end(arg); 	argv = malloc(n*sizeof(argv[0]));	if(argv == nil){		if(cpid)			chansendul(cpid, ~0);		return;	} 	va_start(arg, cmd);	for(n=0; (s=va_arg(arg, char*)) != nil; n++)		argv[n] = s;	argv[n] = 0;	va_end(arg); 	pid = _threadexec(cpid, fd, cmd, argv);	free(argv); 	if(pid >= 0)		threadexits("threadexecl");}