#include "array.h"
#include "ioloop.h"
#include "write-full.h"
+#include "llist.h"
#include "lib-signals.h"
#include <stdio.h>
# define SI_NOINFO -1
#endif
+struct signal_ioloop {
+ struct signal_ioloop *prev, *next;
+
+ int refcount;
+ struct ioloop *ioloop;
+};
+
struct signal_handler {
signal_handler_t *handler;
void *context;
enum libsig_flags flags;
struct signal_handler *next;
- struct ioloop *current_ioloop;
+ struct signal_ioloop *sig_ioloop;
bool expected:1;
bool shadowed:1;
static bool signals_initialized = FALSE;
static unsigned int signals_expected = 0;
static struct io *io_sig = NULL;
+static struct signal_ioloop *signal_ioloops = NULL;
static siginfo_t pending_signals[MAX_SIGNAL_VALUE+1];
static ARRAY(siginfo_t) pending_shadowed_signals;
the system call might be restarted */
}
+static struct signal_ioloop *
+lib_signals_ioloop_find(struct ioloop *ioloop)
+{
+ struct signal_ioloop *l;
+
+ for (l = signal_ioloops; l != NULL; l = l->next) {
+ if (l->ioloop == ioloop)
+ break;
+ }
+ return l;
+}
+
+static struct signal_ioloop *
+lib_signals_ioloop_ref(struct ioloop *ioloop)
+{
+ struct signal_ioloop *l;
+
+ l = lib_signals_ioloop_find(ioloop);
+ if (l == NULL) {
+ l = i_new(struct signal_ioloop, 1);
+ l->ioloop = ioloop;
+ DLLIST_PREPEND(&signal_ioloops, l);
+ }
+ l->refcount++;
+ return l;
+}
+
+static void lib_signals_ioloop_unref(struct signal_ioloop **_sig_ioloop)
+{
+ struct signal_ioloop *sig_ioloop = *_sig_ioloop;
+
+ *_sig_ioloop = NULL;
+
+ if (sig_ioloop == NULL)
+ return;
+ i_assert(sig_ioloop->refcount > 0);
+ if (--sig_ioloop->refcount > 0)
+ return;
+ DLLIST_REMOVE(&signal_ioloops, sig_ioloop);
+ i_free(sig_ioloop);
+}
+
+static void signal_handler_free(struct signal_handler *h)
+{
+ lib_signals_ioloop_unref(&h->sig_ioloop);
+ i_free(h);
+}
+
static void signal_handle_shadowed(void)
{
const siginfo_t *sis;
i_assert(sis[i].si_signo > 0);
for (h = signal_handlers[sis[i].si_signo]; h != NULL;
h = h->next) {
+ i_assert(h->sig_ioloop != NULL);
if ((h->flags & LIBSIG_FLAG_DELAYED) == 0 ||
(h->flags & LIBSIG_FLAG_IOLOOP_AUTOMOVE) != 0)
continue;
if (h->shadowed &&
- h->current_ioloop != current_ioloop) {
+ h->sig_ioloop->ioloop != current_ioloop) {
shadowed = TRUE;
continue;
}
continue;
for (h = signal_handlers[signo]; h != NULL; h = h->next) {
+ i_assert(h->sig_ioloop != NULL);
if ((h->flags & LIBSIG_FLAG_DELAYED) == 0) {
/* handler already called immediately in signal
context */
continue;
}
if ((h->flags & LIBSIG_FLAG_IOLOOP_AUTOMOVE) == 0 &&
- h->current_ioloop != current_ioloop) {
+ h->sig_ioloop->ioloop != current_ioloop) {
/* cannot run handler in current ioloop
(shadowed) */
h->shadowed = TRUE;
first ioloop. */
for (int signo = 0; signo < MAX_SIGNAL_VALUE; signo++) {
for (h = signal_handlers[signo]; h != NULL; h = h->next) {
- if (h->current_ioloop == NULL)
- h->current_ioloop = current_ioloop;
+ if (h->sig_ioloop == NULL)
+ h->sig_ioloop = lib_signals_ioloop_ref(current_ioloop);
}
}
h->handler = handler;
h->context = context;
h->flags = flags;
- h->current_ioloop = current_ioloop;
+ if (current_ioloop != NULL)
+ h->sig_ioloop = lib_signals_ioloop_ref(current_ioloop);
/* atomically set to signal_handlers[] list */
h->next = signal_handlers[signo];
if (h->expected)
signals_expected--;
- i_free(h);
+ signal_handler_free(h);
h = h_next;
}
}
*p = h->next;
if (h->expected)
lib_signals_update_expected_signals(FALSE);
- i_free(h);
+ signal_handler_free(h);
return;
}
}
if (h->handler == handler && h->context == context) {
i_assert((h->flags & LIBSIG_FLAG_DELAYED) != 0);
i_assert((h->flags & LIBSIG_FLAG_IOLOOP_AUTOMOVE) == 0);
- h->current_ioloop = current_ioloop;
+ lib_signals_ioloop_unref(&h->sig_ioloop);
+ h->sig_ioloop = lib_signals_ioloop_ref(current_ioloop);
/* check whether we can now handle any shadowed delayed
signals */
signal_check_shadowed();
if (array_is_created(&pending_shadowed_signals))
array_free(&pending_shadowed_signals);
+ i_assert(signal_ioloops == NULL);
}