aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2021-06-04 16:30:04 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2021-06-07 17:37:21 +0200
commite0236584b489193fa00b47f06f0ff4f2cbc0aaf4 (patch)
tree01855ac9084f4d231c5f61b8952699fe1b3b82d5
parente9fd81a5c31782f36b512cf41ee98d0a4e4a82eb (diff)
osmo_select_shutdown_request(): allow finishing pending writes on SIGTERMneels/select_shutdown
Allow telling osmo_select_main* to only service pending writes (shutdown mode). Introduce API fuctions to indicate a shutdown request, and find out whether shutdown is complete. Some osmo programs have a curious sleep of few seconds upon receiving SIGTERM. The idea presumably was to finish off pending writes before halting the program. But a sleep() on program exit is annoying, especially when there usually are no pending writes, and when osmo-bsc is launched numerous times for tests. Change-Id: Ib94d4316924103459577087c2214188679db2227
-rw-r--r--include/osmocom/core/select.h3
-rw-r--r--src/select.c70
2 files changed, 72 insertions, 1 deletions
diff --git a/include/osmocom/core/select.h b/include/osmocom/core/select.h
index b4101998..e9f19a56 100644
--- a/include/osmocom/core/select.h
+++ b/include/osmocom/core/select.h
@@ -105,5 +105,8 @@ struct osmo_signalfd {
struct osmo_signalfd *
osmo_signalfd_setup(void *ctx, sigset_t set, osmo_signalfd_cb *cb, void *data);
+void osmo_select_shutdown_request();
+int osmo_select_shutdown_requested();
+bool osmo_select_shutdown_done();
/*! @} */
diff --git a/src/select.c b/src/select.c
index 71ee7f60..f7eb5ea3 100644
--- a/src/select.c
+++ b/src/select.c
@@ -69,6 +69,11 @@ struct poll_state {
static __thread struct poll_state g_poll;
#endif /* FORCE_IO_SELECT */
+/*! See osmo_select_shutdown_request() */
+static int _osmo_select_shutdown_requested = 0;
+/*! See osmo_select_shutdown_request() */
+static bool _osmo_select_shutdown_done = false;
+
/*! Set up an osmo-fd. Will not register it.
* \param[inout] ofd Osmo FD to be set-up
* \param[in] fd OS-level file descriptor number
@@ -316,6 +321,7 @@ static int poll_disp_fds(int n_fd)
struct osmo_fd *ufd;
unsigned int i;
int work = 0;
+ int shutdown_pending_writes = 0;
for (i = 0; i < n_fd; i++) {
struct pollfd *p = &g_poll.poll[i];
@@ -340,6 +346,11 @@ static int poll_disp_fds(int n_fd)
/* make sure we never report more than the user requested */
flags &= ufd->when;
+ if (_osmo_select_shutdown_requested > 0) {
+ if (ufd->when & OSMO_FD_WRITE)
+ shutdown_pending_writes++;
+ }
+
if (flags) {
work = 1;
/* make sure to clear any log context before processing the next incoming message
@@ -351,6 +362,9 @@ static int poll_disp_fds(int n_fd)
}
}
+ if (_osmo_select_shutdown_requested > 0 && !shutdown_pending_writes)
+ _osmo_select_shutdown_done = true;
+
return work;
}
@@ -370,7 +384,8 @@ static int _osmo_select_main(int polling)
return 0;
/* fire timers */
- osmo_timers_update();
+ if (!_osmo_select_shutdown_requested)
+ osmo_timers_update();
OSMO_ASSERT(osmo_ctx->select);
@@ -596,6 +611,59 @@ osmo_signalfd_setup(void *ctx, sigset_t set, osmo_signalfd_cb *cb, void *data)
#endif /* HAVE_SYS_SIGNALFD_H */
+/*! Request osmo_select_* to only service pending OSMO_FD_WRITE requests. Once all writes are done,
+ * osmo_select_shutdown_done() returns true. This allows for example to send all outbound packets before terminating the
+ * process.
+ *
+ * Usage example:
+ *
+ * static void signal_handler(int signum)
+ * {
+ * fprintf(stdout, "signal %u received\n", signum);
+ *
+ * switch (signum) {
+ * case SIGINT:
+ * case SIGTERM:
+ * // If the user hits Ctrl-C the third time, just terminate immediately.
+ * if (osmo_select_shutdown_requested() >= 2)
+ * exit(-1);
+ * // Request write-only mode in osmo_select_main_ctx()
+ * osmo_select_shutdown_request();
+ * break;
+ * [...]
+ * }
+ *
+ * main()
+ * {
+ * signal(SIGINT, &signal_handler);
+ * signal(SIGTERM, &signal_handler);
+ *
+ * [...]
+ *
+ * // After the signal_handler issued osmo_select_shutdown_request(), osmo_select_shutdown_done() returns true
+ * // as soon as all write queues are empty.
+ * while (!osmo_select_shutdown_done()) {
+ * osmo_select_main_ctx(0);
+ * }
+ * }
+ */
+void osmo_select_shutdown_request()
+{
+ _osmo_select_shutdown_requested++;
+};
+
+/*! Return the number of times osmo_select_shutdown_request() was called before. */
+int osmo_select_shutdown_requested()
+{
+ return _osmo_select_shutdown_requested;
+};
+
+/*! Return true after osmo_select_shutdown_requested() was called, and after an osmo_select poll loop found no more
+ * pending OSMO_FD_WRITE on any registered socket. */
+bool osmo_select_shutdown_done() {
+ return _osmo_select_shutdown_done;
+};
+
/*! @} */
#endif /* _HAVE_SYS_SELECT_H */