⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jobs.c

📁 操作系统源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	{	int pid;	int pgrp;	TRACE(("forkshell(%%%d, 0x%x, %d) called\n", jp - jobtab, (int)n, mode));	INTOFF;	pid = fork();	if (pid == -1) {		TRACE(("Fork failed, errno=%d\n", errno));		INTON;		error("Cannot fork");	}	if (pid == 0) {		struct job *p;		int wasroot;		int i;		TRACE(("Child shell %d\n", getpid()));		wasroot = rootshell;		rootshell = 0;		for (i = njobs, p = jobtab ; --i >= 0 ; p++)			if (p->used)				freejob(p);		closescript();		INTON;		clear_traps();#if JOBS		jobctl = 0;		/* do job control only in root shell */		if (wasroot && mode != FORK_NOJOB && jflag) {			if (jp == NULL || jp->nprocs == 0)				pgrp = getpid();			else				pgrp = jp->ps[0].pid;			setpgrp(0, pgrp);			if (mode == FORK_FG) {				/*** this causes superfluous TIOCSPGRPS ***/				if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)					error("TIOCSPGRP failed, errno=%d\n", errno);			}			setsignal(SIGTSTP);			setsignal(SIGTTOU);		} else if (mode == FORK_BG) {			ignoresig(SIGINT);			ignoresig(SIGQUIT);			if ((jp == NULL || jp->nprocs == 0)			    && ! fd0_redirected_p ()) {				close(0);				if (open("/dev/null", O_RDONLY) != 0)					error("Can't open /dev/null");			}		}#else		if (mode == FORK_BG) {			ignoresig(SIGINT);			ignoresig(SIGQUIT);			if ((jp == NULL || jp->nprocs == 0)			    && ! fd0_redirected_p ()) {				close(0);				if (open("/dev/null", O_RDONLY) != 0)					error("Can't open /dev/null");			}		}#endif		if (wasroot && iflag) {			setsignal(SIGINT);			setsignal(SIGQUIT);			setsignal(SIGTERM);		}		return pid;	}	if (rootshell && mode != FORK_NOJOB && jflag) {		if (jp == NULL || jp->nprocs == 0)			pgrp = pid;		else			pgrp = jp->ps[0].pid;#if JOBS		setpgrp(pid, pgrp);#endif	}	if (mode == FORK_BG)		backgndpid = pid;		/* set $! */	if (jp) {		struct procstat *ps = &jp->ps[jp->nprocs++];		ps->pid = pid;		ps->status = -1;		ps->cmd = nullstr;		if (iflag && rootshell && n)			ps->cmd = commandtext(n);	}	INTON;	TRACE(("In parent shell:  child = %d\n", pid));	return pid;}/* * Wait for job to finish. * * Under job control we have the problem that while a child process is * running interrupts generated by the user are sent to the child but not * to the shell.  This means that an infinite loop started by an inter- * active user may be hard to kill.  With job control turned off, an * interactive user may place an interactive program inside a loop.  If * the interactive program catches interrupts, the user doesn't want * these interrupts to also abort the loop.  The approach we take here * is to have the shell ignore interrupt signals while waiting for a * forground process to terminate, and then send itself an interrupt * signal if the child process was terminated by an interrupt signal. * Unfortunately, some programs want to do a bit of cleanup and then * exit on interrupt; unless these processes terminate themselves by * sending a signal to themselves (instead of calling exit) they will * confuse this approach. */intwaitforjob(jp)	register struct job *jp;	{#if JOBS	int mypgrp = getpgrp(0);#endif	int status;	int st;	INTOFF;	TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));	while (jp->state == 0 && dowait(1, jp) != -1) ;#if JOBS	if (jp->jobctl) {		if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)			error("TIOCSPGRP failed, errno=%d\n", errno);	}	if (jp->state == JOBSTOPPED)		curjob = jp - jobtab + 1;#endif	status = jp->ps[jp->nprocs - 1].status;	/* convert to 8 bits */	if ((status & 0xFF) == 0)		st = status >> 8 & 0xFF;#if JOBS	else if ((status & 0xFF) == 0177)		st = (status >> 8 & 0x7F) + 128;#endif	else		st = (status & 0x7F) + 128;	if (! JOBS || jp->state == JOBDONE)		freejob(jp);	CLEAR_PENDING_INT;	if ((status & 0x7F) == SIGINT)		kill(getpid(), SIGINT);	INTON;	return st;}/* * Wait for a process to terminate. */STATIC intdowait(block, job)	struct job *job;	{	int pid;	int status;	struct procstat *sp;	struct job *jp;	struct job *thisjob;	int done;	int stopped;	int core;	TRACE(("dowait(%d) called\n", block));	do {		pid = waitproc(block, &status);		TRACE(("wait returns %d, status=%d, errno=%d\n",				pid, status, errno));	} while (pid == -1 && errno == EINTR);	if (pid <= 0)		return pid;	INTOFF;	thisjob = NULL;	for (jp = jobtab ; jp < jobtab + njobs ; jp++) {		if (jp->used) {			done = 1;			stopped = 1;			for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {				if (sp->pid == -1)					continue;				if (sp->pid == pid) {					TRACE(("Changin status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));					sp->status = status;					thisjob = jp;				}				if (sp->status == -1)					stopped = 0;				else if ((sp->status & 0377) == 0177)					done = 0;			}			if (stopped) {		/* stopped or done */				int state = done? JOBDONE : JOBSTOPPED;				if (jp->state != state) {					TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));					jp->state = state;#if JOBS					if (done && curjob == jp - jobtab + 1)						curjob = 0;		/* no current job */#endif				}			}		}	}	INTON;	if (! rootshell || ! iflag || (job && thisjob == job)) {#if JOBS		if ((status & 0xFF) == 0177)			status >>= 8;#endif		core = status & 0x80;		status &= 0x7F;		if (status != 0 && status != SIGINT && status != SIGPIPE) {			if (thisjob != job)				outfmt(out2, "%d: ", pid);#if JOBS			if (status == SIGTSTP && rootshell && iflag)				outfmt(out2, "%%%d ", job - jobtab + 1);#endif			if (status <= MAXSIG && sigmesg[status])				out2str(sigmesg[status]);			else				outfmt(out2, "Signal %d", status);			if (core)				out2str(" - core dumped");			out2c('\n');			flushout(&errout);		} else {			TRACE(("Not printing status: status=%d\n", status));		}	} else {		TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));		if (thisjob)			thisjob->changed = 1;	}	return pid;}/* * Do a wait system call.  If job control is compiled in, we accept * stopped processes.  If block is zero, we return a value of zero * rather than blocking. * * System V doesn't have a non-blocking wait system call.  It does * have a SIGCLD signal that is sent to a process when one of it's * children dies.  The obvious way to use SIGCLD would be to install * a handler for SIGCLD which simply bumped a counter when a SIGCLD * was received, and have waitproc bump another counter when it got * the status of a process.  Waitproc would then know that a wait * system call would not block if the two counters were different. * This approach doesn't work because if a process has children that * have not been waited for, System V will send it a SIGCLD when it * installs a signal handler for SIGCLD.  What this means is that when * a child exits, the shell will be sent SIGCLD signals continuously * until is runs out of stack space, unless it does a wait call before * restoring the signal handler.  The code below takes advantage of * this (mis)feature by installing a signal handler for SIGCLD and * then checking to see whether it was called.  If there are any * children to be waited for, it will be. * * If neither SYSV nor BSD is defined, we don't implement nonblocking * waits at all.  In this case, the user will not be informed when * a background process until the next time she runs a real program * (as opposed to running a builtin command or just typing return), * and the jobs command may give out of date information. */#ifdef SYSVSTATIC int gotsigchild;STATIC int onsigchild() {	gotsigchild = 1;}#endifSTATIC intwaitproc(block, status)	int *status;	{#ifdef BSD	int flags;#if JOBS	flags = WUNTRACED;#else	flags = 0;#endif	if (block == 0)		flags |= WNOHANG;	return wait3((union wait *)status, flags, (struct rusage *)NULL);#else#ifdef SYSV	int (*save)();	if (block == 0) {		gotsigchild = 0;		save = signal(SIGCLD, onsigchild);		signal(SIGCLD, save);		if (gotsigchild == 0)			return 0;	}	return wait(status);#else#if POSIX	return waitpid(-1, status, block == 0 ? WNOHANG : 0);#else	if (block == 0)		return 0;	return wait(status);#endif#endif#endif}/* * Return a string identifying a command (to be printed by the * jobs command. */STATIC char *cmdnextc;STATIC int cmdnleft;STATIC void cmdtxt(), cmdputs();STATIC char *commandtext(n)	union node *n;	{	char *name;	cmdnextc = name = ckmalloc(50);	cmdnleft = 50 - 4;	cmdtxt(n);	*cmdnextc = '\0';	return name;}STATIC voidcmdtxt(n)	union node *n;	{	union node *np;	struct nodelist *lp;	char *p;	int i;	char s[2];	if (n == NULL) return;	switch (n->type) {	case NSEMI:		cmdtxt(n->nbinary.ch1);		cmdputs("; ");		cmdtxt(n->nbinary.ch2);		break;	case NAND:		cmdtxt(n->nbinary.ch1);		cmdputs(" && ");		cmdtxt(n->nbinary.ch2);		break;	case NOR:		cmdtxt(n->nbinary.ch1);		cmdputs(" || ");		cmdtxt(n->nbinary.ch2);		break;	case NPIPE:		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {			cmdtxt(lp->n);			if (lp->next)				cmdputs(" | ");		}		break;	case NSUBSHELL:		cmdputs("(");		cmdtxt(n->nredir.n);		cmdputs(")");		break;	case NREDIR:	case NBACKGND:		cmdtxt(n->nredir.n);		break;	case NIF:		cmdputs("if ");		cmdtxt(n->nif.test);		cmdputs("; then ");		cmdtxt(n->nif.ifpart);		cmdputs("...");		break;	case NWHILE:		cmdputs("while ");		goto until;	case NUNTIL:		cmdputs("until ");until:		cmdtxt(n->nbinary.ch1);		cmdputs("; do ");		cmdtxt(n->nbinary.ch2);		cmdputs("; done");		break;	case NFOR:		cmdputs("for ");		cmdputs(n->nfor.var);		cmdputs(" in ...");		break;	case NCASE:		cmdputs("case ");		cmdputs(n->ncase.expr->narg.text);		cmdputs(" in ...");		break;	case NDEFUN:		cmdputs(n->narg.text);		cmdputs("() ...");		break;	case NCMD:		for (np = n->ncmd.args ; np ; np = np->narg.next) {			cmdtxt(np);			if (np->narg.next)				cmdputs(" ");		}		for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {			cmdputs(" ");			cmdtxt(np);		}		break;	case NARG:		cmdputs(n->narg.text);		break;	case NTO:		p = ">";  i = 1;  goto redir;	case NAPPEND:		p = ">>";  i = 1;  goto redir;	case NTOFD:		p = ">&";  i = 1;  goto redir;	case NFROM:		p = "<";  i = 0;  goto redir;	case NFROMFD:		p = "<&";  i = 0;  goto redir;redir:		if (n->nfile.fd != i) {			s[0] = n->nfile.fd + '0';			s[1] = '\0';			cmdputs(s);		}		cmdputs(p);		if (n->type == NTOFD || n->type == NFROMFD) {			s[0] = n->ndup.dupfd + '0';			s[1] = '\0';			cmdputs(s);		} else {			cmdtxt(n->nfile.fname);		}		break;	case NHERE:	case NXHERE:		cmdputs("<<...");		break;	default:		cmdputs("???");		break;	}}STATIC voidcmdputs(s)	char *s;	{	register char *p, *q;	register char c;	int subtype = 0;	if (cmdnleft <= 0)		return;	p = s;	q = cmdnextc;	while ((c = *p++) != '\0') {		if (c == CTLESC)			*q++ = *p++;		else if (c == CTLVAR) {			*q++ = '$';			if (--cmdnleft > 0)				*q++ = '{';			subtype = *p++;		} else if (c == '=' && subtype != 0) {			*q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];			subtype = 0;		} else if (c == CTLENDVAR) {			*q++ = '}';		} else if (c == CTLBACKQ | c == CTLBACKQ+CTLQUOTE)			cmdnleft++;		/* ignore it */		else			*q++ = c;		if (--cmdnleft <= 0) {			*q++ = '.';			*q++ = '.';			*q++ = '.';			break;		}	}	cmdnextc = q;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -