void const *ctx, struct timeval *when, fr_event_timer_t **parent);
int fr_event_timer_run(fr_event_list_t *el, struct timeval *when);
-int fr_event_user_insert(fr_event_list_t *el, fr_event_user_handler_t user, void *ctx) CC_HINT(nonnull(1,2));
+uintptr_t fr_event_user_insert(fr_event_list_t *el, fr_event_user_handler_t user, void *ctx) CC_HINT(nonnull(1,2));
int fr_event_user_delete(fr_event_list_t *el, fr_event_user_handler_t user, void *ctx) CC_HINT(nonnull(1,2));
int fr_event_post_insert(fr_event_list_t *el, fr_event_callback_t callback, void *uctx) CC_HINT(nonnull(1,2));
fr_atomic_queue_t *aq_control; //!< atomic queue for control messages sent to me
+ uintptr_t aq_ident; //!< identifier for control-plane events
+
fr_control_t *control; //!< the control plane
fr_ring_buffer_t *rb; //!< ring buffer for my control-plane messages
nr = talloc_zero(ctx, fr_network_t);
if (!nr) {
- nomem:
fr_strerror_printf("Failed allocating memory");
return NULL;
}
nr->aq_control = fr_atomic_queue_create(nr, 1024);
if (!nr->aq_control) {
talloc_free(nr);
- goto nomem;
+ return NULL;
+ }
+
+ nr->aq_ident = fr_event_user_insert(nr->el, fr_network_evfilt_user, nr);
+ if (!nr->aq_ident) {
+ fr_strerror_printf("Failed updating event list: %s", fr_strerror());
+ talloc_free(nr);
+ return NULL;
}
- nr->control = fr_control_create(nr, nr->kq, nr->aq_control, 1024);
+
+ nr->control = fr_control_create(nr, nr->kq, nr->aq_control, nr->aq_ident);
if (!nr->control) {
fr_strerror_printf("Failed creating control queue: %s", fr_strerror());
+ fail:
+ (void) fr_event_user_delete(nr->el, fr_network_evfilt_user, nr);
talloc_free(nr);
return NULL;
}
nr->rb = fr_ring_buffer_create(nr, FR_CONTROL_MAX_MESSAGES * FR_CONTROL_MAX_SIZE);
if (!nr->rb) {
fr_strerror_printf("Failed creating ring buffer: %s", fr_strerror());
- talloc_free(nr);
- return NULL;
+ fail2:
+ fr_control_free(nr->control);
+ goto fail;
}
if (fr_control_callback_add(nr->control, FR_CONTROL_ID_CHANNEL, nr, fr_network_channel_callback) < 0) {
fr_strerror_printf("Failed adding channel callback: %s", fr_strerror());
- talloc_free(nr);
- return NULL;
+ goto fail2;
}
if (fr_control_callback_add(nr->control, FR_CONTROL_ID_SOCKET, nr, fr_network_socket_callback) < 0) {
fr_strerror_printf("Failed adding socket callback: %s", fr_strerror());
- talloc_free(nr);
- return NULL;
+ goto fail2;
}
if (fr_control_callback_add(nr->control, FR_CONTROL_ID_WORKER, nr, fr_network_worker_callback) < 0) {
fr_strerror_printf("Failed adding worker callback: %s", fr_strerror());
- talloc_free(nr);
- return NULL;
+ goto fail2;
}
/*
*/
nr->sockets = rbtree_create(nr, socket_cmp, NULL, RBTREE_FLAG_NONE);
if (!nr->sockets) {
- talloc_free(nr);
- goto nomem;
+ fr_strerror_printf("Failed creating tree for sockets: %s", fr_strerror());
+ goto fail2;
}
nr->replies = fr_heap_create(reply_cmp, offsetof(fr_channel_data_t, channel.heap_id));
if (!nr->replies) {
- talloc_free(nr);
- goto nomem;
+ fr_strerror_printf("Failed creating heap for replies: %s", fr_strerror());
+ goto fail2;
}
nr->workers = fr_heap_create(worker_cmp, offsetof(fr_network_worker_t, heap_id));
if (!nr->workers) {
- talloc_free(nr);
- goto nomem;
+ fr_strerror_printf("Failed creating heap for workers: %s", fr_strerror());
+ fail3:
+ fr_heap_delete(nr->replies);
+ goto fail2;
}
nr->closing = fr_heap_create(worker_cmp, offsetof(fr_network_worker_t, heap_id));
if (!nr->closing) {
- talloc_free(nr);
- goto nomem;
+ fr_strerror_printf("Failed creating heap for exiting workers: %s", fr_strerror());
+ goto fail3;
}
#ifdef HAVE_PTHREAD_H
if (pthread_mutex_init(&nr->mutex, NULL) != 0) {
fr_strerror_printf("Failed initializing mutex");
- talloc_free(nr);
- return NULL;
+ fail4:
+ fr_heap_delete(nr->closing);
+ goto fail3;
}
#endif
- if (fr_event_user_insert(nr->el, fr_network_evfilt_user, nr) < 0) {
- fr_strerror_printf("Failed updating event list: %s", fr_strerror());
- talloc_free(nr);
- return NULL;
- }
-
if (fr_event_post_insert(nr->el, fr_network_post_event, nr) < 0) {
fr_strerror_printf("Failed inserting post-processing event");
- talloc_free(nr);
- return NULL;
+ goto fail4;
}
return nr;
int kq; //!< my kq
- fr_log_t *log; //!< log destination
+ fr_log_t *log; //!< log destination
fr_atomic_queue_t *aq_control; //!< atomic queue for control messages sent to me
+ uintptr_t aq_ident; //!< identifier for control-plane events
+
fr_control_t *control; //!< the control plane
fr_event_list_t *el; //!< our event list
FR_DLIST_INIT(worker->_name.list); \
worker->_name.heap = fr_heap_create(_func, offsetof(_type, _member)); \
if (!worker->_name.heap) { \
+ (void) fr_event_user_delete(worker->el, fr_worker_evfilt_user, worker); \
talloc_free(worker); \
goto nomem; \
} \
worker->aq_control = fr_atomic_queue_create(worker, 1024);
if (!worker->aq_control) {
+ fr_strerror_printf("Failed creating atomic queue");
+ fail:
talloc_free(worker);
- goto nomem;
+ return NULL;
}
- worker->control = fr_control_create(worker, worker->kq, worker->aq_control, 1024);
+ worker->aq_ident = fr_event_user_insert(worker->el, fr_worker_evfilt_user, worker);
+ if (!worker->aq_ident) {
+ fr_strerror_printf("Failed updating event list: %s", fr_strerror());
+ goto fail;
+ }
+
+ worker->control = fr_control_create(worker, worker->kq, worker->aq_control, worker->aq_ident);
if (!worker->control) {
- talloc_free(worker);
- goto nomem;;
+ fr_strerror_printf("Failed creating control plane: %s", fr_strerror());
+ fail2:
+ (void) fr_event_user_delete(worker->el, fr_worker_evfilt_user, worker);
+ goto fail;
}
if (fr_control_callback_add(worker->control, FR_CONTROL_ID_CHANNEL, worker, fr_worker_channel_callback) < 0) {
fr_strerror_printf("Failed adding control channel: %s", fr_strerror());
- talloc_free(worker);
- return NULL;
+ goto fail2;
}
WORKER_HEAP_INIT(to_decode, worker_message_cmp, fr_channel_data_t, channel.heap_id);
worker->runnable = fr_heap_create(worker_request_cmp, offsetof(REQUEST, heap_id));
if (!worker->runnable) {
- talloc_free(worker);
- goto nomem;;
+ fr_strerror_printf("Failed creating runnable heap");
+ goto fail;
}
FR_DLIST_INIT(worker->time_order);
FR_DLIST_INIT(worker->waiting_to_die);
- if (fr_event_user_insert(worker->el, fr_worker_evfilt_user, worker) < 0) {
- fr_strerror_printf("Failed updating event list: %s", fr_strerror());
- talloc_free(worker);
- return NULL;
- }
-
if (fr_event_post_insert(worker->el, fr_worker_post_event, worker) < 0) {
fr_strerror_printf("Failed inserting post-processing event");
- talloc_free(worker);
- return NULL;
+ fr_heap_delerte(worker->runnable);
+ goto fail2;
}
return worker;
void *ctx; //!< context for the callback.
} fr_event_post_t;
+
+/** Callbacks for user events
+ *
+ */
+typedef struct fr_event_user_t {
+ fr_dlist_t entry; //!< linked list of callback
+ uintptr_t ident; //!< the identifier of this event
+ fr_event_user_handler_t callback; //!< the callback to call
+ void *ctx; //!< context for the callback.
+} fr_event_user_t;
+
+
/** Stores all information relating to an event list
*
*/
int kq; //!< instance associated with this event list.
- fr_event_user_handler_t user; //!< callback for EVFILT_USER events
- void *user_ctx; //!< Context pointer to pass to the user callback.
-
+ fr_dlist_t user_callbacks; //!< EVFILT_USER callbacks
fr_dlist_t post_callbacks; //!< post-processing callbacks
struct kevent events[FR_EV_BATCH_FDS]; /* so it doesn't go on the stack every time */
/** Add a user callback to the event list.
*
* @param[in] el containing the timer events.
- * @param[in] user the callback for EVFILT_USER
- * @param[in] ctx user context for the callback
+ * @param[in] callback the callback for EVFILT_USER
+ * @param[in] uctx user context for the callback
* @return
- * - < 0 on error
- * - 0 on success
+ * - 0 on error
+ * - uintptr_t ident for EVFILT_USER signaling
*/
-int fr_event_user_insert(fr_event_list_t *el, fr_event_user_handler_t user, void *ctx)
+uintptr_t fr_event_user_insert(fr_event_list_t *el, fr_event_user_handler_t callback, void *uctx)
{
- el->user = user;
- el->user_ctx = ctx;
+ fr_event_user_t *user;
- return 0;
+ user = talloc(el, fr_event_user_t);
+ user->callback = callback;
+ user->ctx = uctx;
+ user->ident = (uintptr_t) user;
+
+ fr_dlist_insert_tail(&el->user_callbacks, &user->entry);
+
+ return user->ident;;
}
/** Delete a user callback to the event list.
*
* @param[in] el containing the timer events.
- * @param[in] user the callback for EVFILT_USER
- * @param[in] ctx user context for the callback
+ * @param[in] callback the callback for EVFILT_USER
+ * @param[in] uctx user context for the callback
* @return
* - < 0 on error
* - 0 on success
*/
-int fr_event_user_delete(fr_event_list_t *el, fr_event_user_handler_t user, void *ctx)
+int fr_event_user_delete(fr_event_list_t *el, fr_event_user_handler_t callback, void *uctx)
{
- if ((el->user != user) || (el->user_ctx != ctx)) return -1;
+ fr_dlist_t *entry, *next;
- el->user = NULL;
- el->user_ctx = NULL;
+ for (entry = FR_DLIST_FIRST(el->user_callbacks);
+ entry != NULL;
+ entry = next) {
+ fr_event_user_t *user;
- return 0;
+ next = FR_DLIST_NEXT(el->user_callbacks, entry);
+
+ user = fr_ptr_to_type(fr_event_user_t, entry, entry);
+ if ((user->callback == callback) &&
+ (user->ctx == uctx)) {
+ fr_dlist_remove(entry);
+ talloc_free(user);
+ return 0;
+ }
+ }
+
+ return -1;
}
/** Add a post-event callback to the event list.
/*
* Process any user events
*/
- if (el->user && (el->events[i].filter == EVFILT_USER)) {
+ if (el->events[i].filter == EVFILT_USER) {
/*
* This is just a "wakeup" event, which
* is always ignored.
*/
if (el->events[i].ident == 0) continue;
- el->user(el->kq, &el->events[i], el->user_ctx);
+ for (entry = FR_DLIST_FIRST(el->user_callbacks);
+ entry != NULL;
+ entry = FR_DLIST_NEXT(el->user_callbacks, entry)) {
+ fr_event_user_t *user;
+
+ user = fr_ptr_to_type(fr_event_user_t, entry, entry);
+
+ if (user->ident != el->events[i].ident) continue;
+
+ user->callback(el->kq, &el->events[i], user->ctx);
+ break;
+ }
+
continue;
}
el->status_ctx = status_ctx;
FR_DLIST_INIT(el->post_callbacks);
+ FR_DLIST_INIT(el->user_callbacks);
/*
* Set our "exit" callback as ident 0.