summaryrefslogtreecommitdiff
path: root/wait.c
blob: 668eb9b5592b2d28ea250ee282940de7ffc0df61 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "rc.h"

#include <errno.h>

#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif

bool forked = FALSE;

typedef struct Pid Pid;

static struct Pid {
	pid_t pid;
	int stat;
	bool alive;
	Pid *n;
} *plist = NULL;

extern pid_t rc_fork() {
	Pid *new;
	struct Pid *p, *q;
	pid_t pid = fork();

	switch (pid) {
	case -1:
		uerror("fork");
		rc_error(NULL);
		/* NOTREACHED */
	case 0:
		forked = TRUE;
		sigchk();
		p = plist; q = 0;
		while (p) {
			if (q) efree(q);
			q = p;
			p = p->n;
		}
		if (q) efree(q);
		plist = 0;
		return 0;
	default:
		new = enew(Pid);
		new->pid = pid;
		new->alive = TRUE;
		new->n = plist;
		plist = new;
		return pid;
	}
}

extern pid_t rc_wait4(pid_t pid, int *stat, bool nointr) {
	Pid *r, *prev;

	/* Find the child on the list. */
	for (r = plist, prev = NULL; r != NULL; prev = r, r = r->n)
		if (r->pid == pid)
			break;

	/* Uh-oh, not there. */
	if (r == NULL) {
		errno = ECHILD; /* no children */
		uerror("wait");
		*stat = 0x100; /* exit(1) */
		return -1;
	}

	/* If it's still alive, wait() for it. */
	while (r->alive) {
		int ret;
		Pid *q;

		ret = rc_wait(stat);

		if (ret < 0) {
			if (errno == ECHILD)
				panic("lost child");
			if (nointr)
				continue;
			else
				return ret;
		}

		for (q = plist; q != NULL; q = q->n)
			if (q->pid == ret) {
				q->alive = FALSE;
				q->stat = *stat;
				break;
			}
	}
	*stat = r->stat;
	if (prev == NULL)
		plist = r->n; /* remove element from head of list */
	else
		prev->n = r->n;
	efree(r);
	return pid;
}

extern List *sgetapids() {
	List *r;
	Pid *p;
	for (r = NULL, p = plist; p != NULL; p = p->n) {
		List *q;
		if (!p->alive)
			continue;
		q = nnew(List);
		q->w = nprint("%d", p->pid);
		q->m = NULL;
		q->n = r;
		r = q;
	}
	return r;
}

extern void waitforall() {
	int stat;

	while (plist != NULL) {
		pid_t pid = rc_wait4(plist->pid, &stat, FALSE);
		if (pid > 0)
			setstatus(pid, stat);
		else {
			set(FALSE);
			if (errno == EINTR)
				return;
		}
		sigchk();
	}
}