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
|
// SPDX-License-Identifier: GPL-3.0-or-later
#include "../libnetdata.h"
int os_waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options) {
#if defined(HAVE_WAITID)
return waitid(idtype, id, infop, options);
#else
// emulate waitid() using waitpid()
// a cache for WNOWAIT
static const struct pid_status empty = { 0, 0 };
static __thread struct pid_status last = { 0, 0 }; // the cache
struct pid_status current = { 0, 0 };
// zero the infop structure
memset(infop, 0, sizeof(*infop));
// from the infop structure we use only 3 fields:
// - si_pid
// - si_code
// - si_status
// so, we update only these 3
switch(idtype) {
case P_ALL:
current.pid = waitpid((pid_t)-1, ¤t.status, options);
if(options & WNOWAIT)
last = current;
else
last = empty;
break;
case P_PID:
if(last.pid == (pid_t)id) {
current = last;
last = empty;
}
else
current.pid = waitpid((pid_t)id, ¤t.status, options);
break;
default:
errno = ENOSYS;
return -1;
}
if (current.pid > 0) {
if (WIFEXITED(current.status)) {
infop->si_code = CLD_EXITED;
infop->si_status = WEXITSTATUS(current.status);
} else if (WIFSIGNALED(current.status)) {
infop->si_code = WTERMSIG(current.status) == SIGABRT ? CLD_DUMPED : CLD_KILLED;
infop->si_status = WTERMSIG(current.status);
} else if (WIFSTOPPED(current.status)) {
infop->si_code = CLD_STOPPED;
infop->si_status = WSTOPSIG(current.status);
} else if (WIFCONTINUED(current.status)) {
infop->si_code = CLD_CONTINUED;
infop->si_status = SIGCONT;
}
infop->si_pid = current.pid;
return 0;
} else if (current.pid == 0) {
// No change in state, depends on WNOHANG
return 0;
}
return -1;
#endif
}
|