2020-05-21 20:15:10 +02:00
|
|
|
#include "reaper.h"
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <sys/epoll.h>
|
reaper: monitor SIGCHLD using the FDM instead of via a signalfd
In addition to letting the FDM do the low-level signal watching, this
patch also fixes a bug; multiple SIGCHLDs, be it delivered either through a
signal, or via a signalfd, can be coalesced, like all signals.
This means we need to loop on waitpid() with WNOHANG until there are
no more processes to reap.
This in turn requires a small change to the way reaper callbacks are
implemented.
Previously, the callback was allowed to do the wait(). This was
signalled back to the reaper through the callback’s return value.
Now, since we’ve already wait():ed, the process’ exit status is passed
as an argument to the reaper callback.
The callback for the client application has been updated accordingly;
it sets a flag in the terminal struct, telling term_destroy() that the
process has already been wait():ed on, and also stores the exit
status.
2021-02-10 16:22:51 +01:00
|
|
|
#include <signal.h>
|
2020-05-21 20:15:10 +02:00
|
|
|
#include <sys/wait.h>
|
reaper: monitor SIGCHLD using the FDM instead of via a signalfd
In addition to letting the FDM do the low-level signal watching, this
patch also fixes a bug; multiple SIGCHLDs, be it delivered either through a
signal, or via a signalfd, can be coalesced, like all signals.
This means we need to loop on waitpid() with WNOHANG until there are
no more processes to reap.
This in turn requires a small change to the way reaper callbacks are
implemented.
Previously, the callback was allowed to do the wait(). This was
signalled back to the reaper through the callback’s return value.
Now, since we’ve already wait():ed, the process’ exit status is passed
as an argument to the reaper callback.
The callback for the client application has been updated accordingly;
it sets a flag in the terminal struct, telling term_destroy() that the
process has already been wait():ed on, and also stores the exit
status.
2021-02-10 16:22:51 +01:00
|
|
|
#include <tllist.h>
|
2020-05-21 20:15:10 +02:00
|
|
|
|
|
|
|
|
#define LOG_MODULE "reaper"
|
2020-05-21 20:27:42 +02:00
|
|
|
#define LOG_ENABLE_DBG 0
|
2020-05-21 20:15:10 +02:00
|
|
|
#include "log.h"
|
|
|
|
|
|
2020-12-26 01:26:54 +01:00
|
|
|
struct child {
|
|
|
|
|
pid_t pid;
|
|
|
|
|
reaper_cb cb;
|
|
|
|
|
void *cb_data;
|
|
|
|
|
};
|
|
|
|
|
|
2020-05-21 20:15:10 +02:00
|
|
|
struct reaper {
|
|
|
|
|
struct fdm *fdm;
|
2020-12-26 01:26:54 +01:00
|
|
|
tll(struct child) children;
|
2020-05-21 20:15:10 +02:00
|
|
|
};
|
|
|
|
|
|
reaper: monitor SIGCHLD using the FDM instead of via a signalfd
In addition to letting the FDM do the low-level signal watching, this
patch also fixes a bug; multiple SIGCHLDs, be it delivered either through a
signal, or via a signalfd, can be coalesced, like all signals.
This means we need to loop on waitpid() with WNOHANG until there are
no more processes to reap.
This in turn requires a small change to the way reaper callbacks are
implemented.
Previously, the callback was allowed to do the wait(). This was
signalled back to the reaper through the callback’s return value.
Now, since we’ve already wait():ed, the process’ exit status is passed
as an argument to the reaper callback.
The callback for the client application has been updated accordingly;
it sets a flag in the terminal struct, telling term_destroy() that the
process has already been wait():ed on, and also stores the exit
status.
2021-02-10 16:22:51 +01:00
|
|
|
static bool fdm_reap(struct fdm *fdm, int signo, void *data);
|
2020-05-21 20:15:10 +02:00
|
|
|
|
|
|
|
|
struct reaper *
|
|
|
|
|
reaper_init(struct fdm *fdm)
|
|
|
|
|
{
|
2020-08-09 08:55:20 +01:00
|
|
|
struct reaper *reaper = malloc(sizeof(*reaper));
|
|
|
|
|
if (unlikely(reaper == NULL)) {
|
|
|
|
|
LOG_ERRNO("malloc() failed");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-21 20:15:10 +02:00
|
|
|
*reaper = (struct reaper){
|
|
|
|
|
.fdm = fdm,
|
|
|
|
|
.children = tll_init(),
|
|
|
|
|
};
|
|
|
|
|
|
reaper: monitor SIGCHLD using the FDM instead of via a signalfd
In addition to letting the FDM do the low-level signal watching, this
patch also fixes a bug; multiple SIGCHLDs, be it delivered either through a
signal, or via a signalfd, can be coalesced, like all signals.
This means we need to loop on waitpid() with WNOHANG until there are
no more processes to reap.
This in turn requires a small change to the way reaper callbacks are
implemented.
Previously, the callback was allowed to do the wait(). This was
signalled back to the reaper through the callback’s return value.
Now, since we’ve already wait():ed, the process’ exit status is passed
as an argument to the reaper callback.
The callback for the client application has been updated accordingly;
it sets a flag in the terminal struct, telling term_destroy() that the
process has already been wait():ed on, and also stores the exit
status.
2021-02-10 16:22:51 +01:00
|
|
|
if (!fdm_signal_add(fdm, SIGCHLD, &fdm_reap, reaper))
|
2020-05-21 20:15:10 +02:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
return reaper;
|
|
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
tll_free(reaper->children);
|
|
|
|
|
free(reaper);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
reaper_destroy(struct reaper *reaper)
|
|
|
|
|
{
|
|
|
|
|
if (reaper == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
reaper: monitor SIGCHLD using the FDM instead of via a signalfd
In addition to letting the FDM do the low-level signal watching, this
patch also fixes a bug; multiple SIGCHLDs, be it delivered either through a
signal, or via a signalfd, can be coalesced, like all signals.
This means we need to loop on waitpid() with WNOHANG until there are
no more processes to reap.
This in turn requires a small change to the way reaper callbacks are
implemented.
Previously, the callback was allowed to do the wait(). This was
signalled back to the reaper through the callback’s return value.
Now, since we’ve already wait():ed, the process’ exit status is passed
as an argument to the reaper callback.
The callback for the client application has been updated accordingly;
it sets a flag in the terminal struct, telling term_destroy() that the
process has already been wait():ed on, and also stores the exit
status.
2021-02-10 16:22:51 +01:00
|
|
|
fdm_signal_del(reaper->fdm, SIGCHLD);
|
2020-05-21 20:15:10 +02:00
|
|
|
tll_free(reaper->children);
|
|
|
|
|
free(reaper);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2020-12-26 01:26:54 +01:00
|
|
|
reaper_add(struct reaper *reaper, pid_t pid, reaper_cb cb, void *cb_data)
|
2020-05-21 20:15:10 +02:00
|
|
|
{
|
|
|
|
|
LOG_DBG("adding pid=%d", pid);
|
2020-12-26 01:26:54 +01:00
|
|
|
tll_push_back(
|
|
|
|
|
reaper->children,
|
|
|
|
|
((struct child){.pid = pid, .cb = cb, .cb_data = cb_data}));
|
2020-05-21 20:15:10 +02:00
|
|
|
}
|
|
|
|
|
|
2021-01-12 09:20:02 +01:00
|
|
|
void
|
|
|
|
|
reaper_del(struct reaper *reaper, pid_t pid)
|
|
|
|
|
{
|
|
|
|
|
tll_foreach(reaper->children, it) {
|
|
|
|
|
if (it->item.pid == pid) {
|
|
|
|
|
tll_remove(reaper->children, it);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-21 20:15:10 +02:00
|
|
|
static bool
|
reaper: monitor SIGCHLD using the FDM instead of via a signalfd
In addition to letting the FDM do the low-level signal watching, this
patch also fixes a bug; multiple SIGCHLDs, be it delivered either through a
signal, or via a signalfd, can be coalesced, like all signals.
This means we need to loop on waitpid() with WNOHANG until there are
no more processes to reap.
This in turn requires a small change to the way reaper callbacks are
implemented.
Previously, the callback was allowed to do the wait(). This was
signalled back to the reaper through the callback’s return value.
Now, since we’ve already wait():ed, the process’ exit status is passed
as an argument to the reaper callback.
The callback for the client application has been updated accordingly;
it sets a flag in the terminal struct, telling term_destroy() that the
process has already been wait():ed on, and also stores the exit
status.
2021-02-10 16:22:51 +01:00
|
|
|
fdm_reap(struct fdm *fdm, int signo, void *data)
|
2020-05-21 20:15:10 +02:00
|
|
|
{
|
|
|
|
|
struct reaper *reaper = data;
|
|
|
|
|
|
reaper: monitor SIGCHLD using the FDM instead of via a signalfd
In addition to letting the FDM do the low-level signal watching, this
patch also fixes a bug; multiple SIGCHLDs, be it delivered either through a
signal, or via a signalfd, can be coalesced, like all signals.
This means we need to loop on waitpid() with WNOHANG until there are
no more processes to reap.
This in turn requires a small change to the way reaper callbacks are
implemented.
Previously, the callback was allowed to do the wait(). This was
signalled back to the reaper through the callback’s return value.
Now, since we’ve already wait():ed, the process’ exit status is passed
as an argument to the reaper callback.
The callback for the client application has been updated accordingly;
it sets a flag in the terminal struct, telling term_destroy() that the
process has already been wait():ed on, and also stores the exit
status.
2021-02-10 16:22:51 +01:00
|
|
|
while (true) {
|
|
|
|
|
int status;
|
|
|
|
|
pid_t pid = waitpid(-1, &status, WNOHANG);
|
|
|
|
|
if (pid <= 0)
|
|
|
|
|
break;
|
2020-05-21 20:15:10 +02:00
|
|
|
|
reaper: monitor SIGCHLD using the FDM instead of via a signalfd
In addition to letting the FDM do the low-level signal watching, this
patch also fixes a bug; multiple SIGCHLDs, be it delivered either through a
signal, or via a signalfd, can be coalesced, like all signals.
This means we need to loop on waitpid() with WNOHANG until there are
no more processes to reap.
This in turn requires a small change to the way reaper callbacks are
implemented.
Previously, the callback was allowed to do the wait(). This was
signalled back to the reaper through the callback’s return value.
Now, since we’ve already wait():ed, the process’ exit status is passed
as an argument to the reaper callback.
The callback for the client application has been updated accordingly;
it sets a flag in the terminal struct, telling term_destroy() that the
process has already been wait():ed on, and also stores the exit
status.
2021-02-10 16:22:51 +01:00
|
|
|
if (WIFEXITED(status))
|
|
|
|
|
LOG_DBG("pid=%d: exited with status=%d", pid, WEXITSTATUS(status));
|
|
|
|
|
else if (WIFSIGNALED(status))
|
|
|
|
|
LOG_DBG("pid=%d: killed by signal=%d", pid, WTERMSIG(status));
|
|
|
|
|
else
|
|
|
|
|
LOG_DBG("pid=%d: died of unknown resason", pid);
|
2020-05-21 20:15:10 +02:00
|
|
|
|
reaper: monitor SIGCHLD using the FDM instead of via a signalfd
In addition to letting the FDM do the low-level signal watching, this
patch also fixes a bug; multiple SIGCHLDs, be it delivered either through a
signal, or via a signalfd, can be coalesced, like all signals.
This means we need to loop on waitpid() with WNOHANG until there are
no more processes to reap.
This in turn requires a small change to the way reaper callbacks are
implemented.
Previously, the callback was allowed to do the wait(). This was
signalled back to the reaper through the callback’s return value.
Now, since we’ve already wait():ed, the process’ exit status is passed
as an argument to the reaper callback.
The callback for the client application has been updated accordingly;
it sets a flag in the terminal struct, telling term_destroy() that the
process has already been wait():ed on, and also stores the exit
status.
2021-02-10 16:22:51 +01:00
|
|
|
tll_foreach(reaper->children, it) {
|
|
|
|
|
struct child *_child = &it->item;
|
2020-12-26 01:26:54 +01:00
|
|
|
|
reaper: monitor SIGCHLD using the FDM instead of via a signalfd
In addition to letting the FDM do the low-level signal watching, this
patch also fixes a bug; multiple SIGCHLDs, be it delivered either through a
signal, or via a signalfd, can be coalesced, like all signals.
This means we need to loop on waitpid() with WNOHANG until there are
no more processes to reap.
This in turn requires a small change to the way reaper callbacks are
implemented.
Previously, the callback was allowed to do the wait(). This was
signalled back to the reaper through the callback’s return value.
Now, since we’ve already wait():ed, the process’ exit status is passed
as an argument to the reaper callback.
The callback for the client application has been updated accordingly;
it sets a flag in the terminal struct, telling term_destroy() that the
process has already been wait():ed on, and also stores the exit
status.
2021-02-10 16:22:51 +01:00
|
|
|
if (_child->pid != pid)
|
|
|
|
|
continue;
|
2021-01-12 09:30:27 +01:00
|
|
|
|
reaper: monitor SIGCHLD using the FDM instead of via a signalfd
In addition to letting the FDM do the low-level signal watching, this
patch also fixes a bug; multiple SIGCHLDs, be it delivered either through a
signal, or via a signalfd, can be coalesced, like all signals.
This means we need to loop on waitpid() with WNOHANG until there are
no more processes to reap.
This in turn requires a small change to the way reaper callbacks are
implemented.
Previously, the callback was allowed to do the wait(). This was
signalled back to the reaper through the callback’s return value.
Now, since we’ve already wait():ed, the process’ exit status is passed
as an argument to the reaper callback.
The callback for the client application has been updated accordingly;
it sets a flag in the terminal struct, telling term_destroy() that the
process has already been wait():ed on, and also stores the exit
status.
2021-02-10 16:22:51 +01:00
|
|
|
/* Make sure we remove it *before* the callback, since it too
|
|
|
|
|
* may remove it */
|
|
|
|
|
struct child child = it->item;
|
|
|
|
|
tll_remove(reaper->children, it);
|
2020-12-26 01:26:54 +01:00
|
|
|
|
reaper: monitor SIGCHLD using the FDM instead of via a signalfd
In addition to letting the FDM do the low-level signal watching, this
patch also fixes a bug; multiple SIGCHLDs, be it delivered either through a
signal, or via a signalfd, can be coalesced, like all signals.
This means we need to loop on waitpid() with WNOHANG until there are
no more processes to reap.
This in turn requires a small change to the way reaper callbacks are
implemented.
Previously, the callback was allowed to do the wait(). This was
signalled back to the reaper through the callback’s return value.
Now, since we’ve already wait():ed, the process’ exit status is passed
as an argument to the reaper callback.
The callback for the client application has been updated accordingly;
it sets a flag in the terminal struct, telling term_destroy() that the
process has already been wait():ed on, and also stores the exit
status.
2021-02-10 16:22:51 +01:00
|
|
|
if (child.cb != NULL)
|
|
|
|
|
child.cb(reaper, child.pid, status, child.cb_data);
|
2020-12-26 01:26:54 +01:00
|
|
|
|
reaper: monitor SIGCHLD using the FDM instead of via a signalfd
In addition to letting the FDM do the low-level signal watching, this
patch also fixes a bug; multiple SIGCHLDs, be it delivered either through a
signal, or via a signalfd, can be coalesced, like all signals.
This means we need to loop on waitpid() with WNOHANG until there are
no more processes to reap.
This in turn requires a small change to the way reaper callbacks are
implemented.
Previously, the callback was allowed to do the wait(). This was
signalled back to the reaper through the callback’s return value.
Now, since we’ve already wait():ed, the process’ exit status is passed
as an argument to the reaper callback.
The callback for the client application has been updated accordingly;
it sets a flag in the terminal struct, telling term_destroy() that the
process has already been wait():ed on, and also stores the exit
status.
2021-02-10 16:22:51 +01:00
|
|
|
break;
|
2020-05-21 20:15:10 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|