-/*
+/*
Unix SMB/CIFS implementation.
common events code for signal events
#include "replace.h"
#include "system/filesys.h"
#include "system/wait.h"
+#define TEVENT_DEPRECATED 1
#include "tevent.h"
#include "tevent_internal.h"
#include "tevent_util.h"
-#define TEVENT_NUM_SIGNALS 64
-
/* maximum number of SA_SIGINFO signals to hold in the queue.
NB. This *MUST* be a power of 2, in order for the ring buffer
wrap to work correctly. Thanks to Petr Vandrovec <petr@vandrovec.name>
for this. */
-#define TEVENT_SA_INFO_QUEUE_COUNT 64
+#define TEVENT_SA_INFO_QUEUE_COUNT 256
+
+size_t tevent_num_signals(void)
+{
+ return TEVENT_NUM_SIGNALS;
+}
+
+size_t tevent_sa_info_queue_count(void)
+{
+ return TEVENT_SA_INFO_QUEUE_COUNT;
+}
struct tevent_sigcounter {
uint32_t count;
uint32_t seen;
};
+#if defined(HAVE___SYNC_FETCH_AND_ADD)
+#define TEVENT_SIG_INCREMENT(s) __sync_fetch_and_add(&((s).count), 1)
+#elif defined(HAVE_ATOMIC_ADD_32)
+#define TEVENT_SIG_INCREMENT(s) atomic_add_32(&((s).count), 1)
+#else
#define TEVENT_SIG_INCREMENT(s) (s).count++
+#endif
#define TEVENT_SIG_SEEN(s, n) (s).seen += (n)
#define TEVENT_SIG_PENDING(s) ((s).seen != (s).count)
*/
static void tevent_common_signal_handler(int signum)
{
- char c = 0;
struct tevent_common_signal_list *sl;
struct tevent_context *ev = NULL;
int saved_errno = errno;
for (sl = sig_state->sig_handlers[signum]; sl; sl = sl->next) {
if (sl->se->event_ctx && sl->se->event_ctx != ev) {
ev = sl->se->event_ctx;
- /* doesn't matter if this pipe overflows */
- (void) write(ev->pipe_fds[1], &c, 1);
+ tevent_common_wakeup(ev);
}
}
*/
static int tevent_signal_destructor(struct tevent_signal *se)
{
- struct tevent_common_signal_list *sl;
- sl = talloc_get_type(se->additional_data,
- struct tevent_common_signal_list);
+ if (se->destroyed) {
+ tevent_common_check_double_free(se, "tevent_signal double free");
+ goto done;
+ }
+ se->destroyed = true;
+
+ TALLOC_FREE(se->additional_data);
- if (se->event_ctx) {
+ if (se->event_ctx != NULL) {
DLIST_REMOVE(se->event_ctx->signal_events, se);
}
- talloc_free(sl);
-
if (sig_state->sig_handlers[se->signum] == NULL) {
/* restore old handler, if any */
if (sig_state->oldact[se->signum]) {
sigaction(se->signum, sig_state->oldact[se->signum], NULL);
- sig_state->oldact[se->signum] = NULL;
+ TALLOC_FREE(sig_state->oldact[se->signum]);
}
#ifdef SA_SIGINFO
if (se->sa_flags & SA_SIGINFO) {
if (sig_state->sig_info[se->signum]) {
- talloc_free(sig_state->sig_info[se->signum]);
- sig_state->sig_info[se->signum] = NULL;
+ TALLOC_FREE(sig_state->sig_info[se->signum]);
}
}
#endif
}
- return 0;
-}
+ se->event_ctx = NULL;
+done:
+ if (se->busy) {
+ return -1;
+ }
+ se->wrapper = NULL;
-/*
- this is part of the pipe hack needed to avoid the signal race condition
-*/
-static void signal_pipe_handler(struct tevent_context *ev, struct tevent_fd *fde,
- uint16_t flags, void *_private)
-{
- char c[16];
- /* its non-blocking, doesn't matter if we read too much */
- (void) read(fde->fd, c, sizeof(c));
+ return 0;
}
/*
struct tevent_signal *se;
struct tevent_common_signal_list *sl;
sigset_t set, oldset;
+ int ret;
+
+ ret = tevent_common_wakeup_init(ev);
+ if (ret != 0) {
+ errno = ret;
+ return NULL;
+ }
if (signum >= TEVENT_NUM_SIGNALS) {
errno = EINVAL;
}
}
- se = talloc(mem_ctx?mem_ctx:ev, struct tevent_signal);
+ se = talloc_zero(mem_ctx?mem_ctx:ev, struct tevent_signal);
if (se == NULL) return NULL;
- se->event_ctx = ev;
- se->signum = signum;
- se->sa_flags = sa_flags;
- se->handler = handler;
- se->private_data = private_data;
- se->handler_name = handler_name;
- se->location = location;
- se->additional_data = NULL;
-
- sl = talloc(se, struct tevent_common_signal_list);
+ sl = talloc_zero(se, struct tevent_common_signal_list);
if (!sl) {
talloc_free(se);
return NULL;
}
sl->se = se;
- se->additional_data = sl;
+
+ *se = (struct tevent_signal) {
+ .event_ctx = ev,
+ .signum = signum,
+ .sa_flags = sa_flags,
+ .handler = handler,
+ .private_data = private_data,
+ .handler_name = handler_name,
+ .location = location,
+ .additional_data= sl,
+ };
/* Ensure, no matter the destruction order, that we always have a handle on the global sig_state */
if (!talloc_reference(se, sig_state)) {
return NULL;
}
- /* we need to setup the pipe hack handler if not already
- setup */
- if (ev->pipe_fde == NULL) {
- if (pipe(ev->pipe_fds) == -1) {
- talloc_free(se);
- return NULL;
- }
- ev_set_blocking(ev->pipe_fds[0], false);
- ev_set_blocking(ev->pipe_fds[1], false);
- ev->pipe_fde = tevent_add_fd(ev, ev, ev->pipe_fds[0],
- TEVENT_FD_READ,
- signal_pipe_handler, NULL);
- if (!ev->pipe_fde) {
- close(ev->pipe_fds[0]);
- close(ev->pipe_fds[1]);
- talloc_free(se);
- return NULL;
- }
- }
-
/* only install a signal handler if not already installed */
if (sig_state->sig_handlers[signum] == NULL) {
struct sigaction act;
}
}
#endif
- sig_state->oldact[signum] = talloc(sig_state, struct sigaction);
+ sig_state->oldact[signum] = talloc_zero(sig_state, struct sigaction);
if (sig_state->oldact[signum] == NULL) {
talloc_free(se);
- return NULL;
+ return NULL;
}
if (sigaction(signum, &act, sig_state->oldact[signum]) == -1) {
+ talloc_free(sig_state->oldact[signum]);
+ sig_state->oldact[signum] = NULL;
talloc_free(se);
return NULL;
}
return se;
}
-struct tevent_se_exists {
- struct tevent_se_exists **myself;
-};
-
-static int tevent_se_exists_destructor(struct tevent_se_exists *s)
+int tevent_common_invoke_signal_handler(struct tevent_signal *se,
+ int signum, int count, void *siginfo,
+ bool *removed)
{
- *s->myself = NULL;
+ struct tevent_context *handler_ev = se->event_ctx;
+ bool remove = false;
+
+ if (removed != NULL) {
+ *removed = false;
+ }
+
+ if (se->event_ctx == NULL) {
+ return 0;
+ }
+
+ se->busy = true;
+ if (se->wrapper != NULL) {
+ handler_ev = se->wrapper->wrap_ev;
+
+ tevent_wrapper_push_use_internal(handler_ev, se->wrapper);
+ se->wrapper->ops->before_signal_handler(
+ se->wrapper->wrap_ev,
+ se->wrapper->private_state,
+ se->wrapper->main_ev,
+ se,
+ signum,
+ count,
+ siginfo,
+ se->handler_name,
+ se->location);
+ }
+ se->handler(handler_ev, se, signum, count, siginfo, se->private_data);
+ if (se->wrapper != NULL) {
+ se->wrapper->ops->after_signal_handler(
+ se->wrapper->wrap_ev,
+ se->wrapper->private_state,
+ se->wrapper->main_ev,
+ se,
+ signum,
+ count,
+ siginfo,
+ se->handler_name,
+ se->location);
+ tevent_wrapper_pop_use_internal(handler_ev, se->wrapper);
+ }
+ se->busy = false;
+
+#ifdef SA_RESETHAND
+ if (se->sa_flags & SA_RESETHAND) {
+ remove = true;
+ }
+#endif
+
+ if (se->destroyed) {
+ talloc_set_destructor(se, NULL);
+ remove = true;
+ }
+
+ if (remove) {
+ TALLOC_FREE(se);
+ if (removed != NULL) {
+ *removed = true;
+ }
+ }
+
return 0;
}
if (!sig_state || !TEVENT_SIG_PENDING(sig_state->got_signal)) {
return 0;
}
-
+
for (i=0;i<TEVENT_NUM_SIGNALS+1;i++) {
struct tevent_common_signal_list *sl, *next;
struct tevent_sigcounter counter = sig_state->signal_count[i];
uint32_t count = tevent_sig_count(counter);
+ int ret;
#ifdef SA_SIGINFO
/* Ensure we null out any stored siginfo_t entries
* after processing for debugging purposes. */
}
for (sl=sig_state->sig_handlers[i];sl;sl=next) {
struct tevent_signal *se = sl->se;
- struct tevent_se_exists *exists;
next = sl->next;
- /*
- * We have to be careful to not touch "se"
- * after it was deleted in its handler. Thus
- * we allocate a child whose destructor will
- * tell by nulling out itself that its parent
- * is gone.
- */
- exists = talloc(se, struct tevent_se_exists);
- if (exists == NULL) {
- continue;
- }
- exists->myself = &exists;
- talloc_set_destructor(
- exists, tevent_se_exists_destructor);
-
#ifdef SA_SIGINFO
if (se->sa_flags & SA_SIGINFO) {
uint32_t j;
* signals in the ringbuffer. */
uint32_t ofs = (counter.seen + j)
% TEVENT_SA_INFO_QUEUE_COUNT;
- se->handler(ev, se, i, 1,
- (void*)&sig_state->sig_info[i][ofs],
- se->private_data);
- if (!exists) {
+ bool removed = false;
+
+ ret = tevent_common_invoke_signal_handler(
+ se, i, 1,
+ (void*)&sig_state->sig_info[i][ofs],
+ &removed);
+ if (ret != 0) {
+ tevent_abort(ev, "tevent_common_invoke_signal_handler() failed");
+ }
+ if (removed) {
break;
}
}
-#ifdef SA_RESETHAND
- if (exists && (se->sa_flags & SA_RESETHAND)) {
- talloc_free(se);
- }
-#endif
- talloc_free(exists);
continue;
}
#endif
- se->handler(ev, se, i, count, NULL, se->private_data);
-#ifdef SA_RESETHAND
- if (exists && (se->sa_flags & SA_RESETHAND)) {
- talloc_free(se);
+
+ ret = tevent_common_invoke_signal_handler(se, i, count,
+ NULL, NULL);
+ if (ret != 0) {
+ tevent_abort(ev, "tevent_common_invoke_signal_handler() failed");
}
-#endif
- talloc_free(exists);
}
#ifdef SA_SIGINFO
- if (clear_processed_siginfo) {
+ if (clear_processed_siginfo && sig_state->sig_info[i] != NULL) {
uint32_t j;
for (j=0;j<count;j++) {
uint32_t ofs = (counter.seen + j)
void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se)
{
- struct tevent_common_signal_list *sl;
- sl = talloc_get_type(se->additional_data,
- struct tevent_common_signal_list);
-
- tevent_common_signal_list_destructor(sl);
-
- if (sig_state->sig_handlers[se->signum] == NULL) {
- if (sig_state->oldact[se->signum]) {
- sigaction(se->signum, sig_state->oldact[se->signum], NULL);
- sig_state->oldact[se->signum] = NULL;
- }
- }
+ tevent_signal_destructor(se);
+ talloc_set_destructor(se, NULL);
return;
}