union {
struct {
fr_time_t *recv_time; //!< time original request was received (network -> worker)
- fr_dlist_t list; //!< list of unprocessed packets for the worker
+ fr_dlist_t entry; //!< list of unprocessed packets for the worker
bool is_dup; //!< dup, new, etc.
} request;
#include <freeradius-devel/io/worker.h>
#include <freeradius-devel/io/network.h>
#include <freeradius-devel/io/listen.h>
-#include <freeradius-devel/util/dlist.h>
/*
* Define our own debugging.
fr_channel_data_t *pending; //!< the currently pending partial packet
fr_heap_t *waiting; //!< packets waiting to be written
-
- fr_dlist_t entry; //!< for deleted sockets
} fr_network_socket_t;
/*
memcpy(&s->listen, data, sizeof(s->listen));
MEM(s->waiting = fr_heap_create(s, waiting_cmp, fr_channel_data_t, channel.heap_id));
- FR_DLIST_INIT(s->entry);
talloc_set_destructor(s, _network_socket_free);
memcpy(&s->listen, data, sizeof(s->listen));
MEM(s->waiting = fr_heap_create(s, waiting_cmp, fr_channel_data_t, channel.heap_id));
- FR_DLIST_INIT(s->entry);
talloc_set_destructor(s, _network_socket_free);
fr_schedule_thread_instantiate_t worker_thread_instantiate; //!< thread instantiation callback
void *worker_instantiate_ctx; //!< thread instantiation context
- fr_dlist_t workers; //!< list of workers
+ fr_dlist_head_t workers; //!< list of workers
fr_network_t *single_network; //!< for single-threaded mode
fr_worker_t *single_worker; //!< for single-threaded mode
{
#ifdef HAVE_PTHREAD_H
int i;
- fr_dlist_t *entry, *next;
+ fr_schedule_worker_t *sw, *next;
#endif
fr_schedule_t *sc;
/*
* Create the list which holds the workers.
*/
- FR_DLIST_INIT(sc->workers);
+ fr_dlist_init(&sc->workers, offsetof(fr_schedule_worker_t, entry));
memset(&sc->semaphore, 0, sizeof(sc->semaphore));
if (sem_init(&sc->semaphore, 0, SEMAPHORE_LOCKED) != 0) {
* Create all of the workers.
*/
for (i = 0; i < sc->max_workers; i++) {
- fr_schedule_worker_t *sw;
-
fr_log(sc->log, L_DBG, "Creating %d/%d workers\n", i, sc->max_workers);
/*
sw->id = i;
sw->sc = sc;
sw->status = FR_CHILD_INITIALIZING;
- fr_dlist_insert_head(&sc->workers, &sw->entry);
+ fr_dlist_insert_head(&sc->workers, sw);
if (fr_schedule_pthread_create(&sw->pthread_id, fr_schedule_worker_thread, sw) < 0) {
fr_log(sc->log, L_ERR, "Failed creating worker %d: %s\n", i, fr_strerror());
/*
* See if all of the workers have started.
*/
- for (entry = FR_DLIST_FIRST(sc->workers);
- entry != NULL;
- entry = next) {
- fr_schedule_worker_t *sw;
-
- next = FR_DLIST_NEXT(sc->workers, entry);
+ for (sw = fr_dlist_first(&sc->workers);
+ sw != NULL;
+ sw = next) {
- sw = fr_ptr_to_type(fr_schedule_worker_t, entry, entry);
+ next = fr_dlist_next(&sc->workers, sw);
if (sw->status != FR_CHILD_RUNNING) {
sc->num_workers--;
- fr_dlist_remove(entry);
+ fr_dlist_remove(&sc->workers, sw);
continue;
}
}
sc->running = false;
#ifdef HAVE_PTHREAD_H
- fr_dlist_t *entry;
-
/*
* Single threaded mode: kill the only network / worker we have.
*/
/*
* Signal all of the workers to exit.
*/
- for (entry = FR_DLIST_FIRST(sc->workers);
- entry != NULL;
- entry = FR_DLIST_NEXT(sc->workers, entry)) {
- sw = fr_ptr_to_type(fr_schedule_worker_t, entry, entry);
+ for (sw = fr_dlist_first(&sc->workers);
+ sw != NULL;
+ sw = fr_dlist_next(&sc->workers, sw)) {
fr_worker_exit(sw->worker);
}
/*
* Clean up the exited workers.
*/
- while ((entry = FR_DLIST_FIRST(sc->workers)) != NULL) {
+ while ((sw = fr_dlist_first(&sc->workers)) != NULL) {
sc->num_workers--;
- fr_dlist_remove(entry);
+
+ fr_dlist_remove(&sc->workers, sw);
/*
* Ensure that the thread has exited before
* exited before the main thread cleans up the
* module instances.
*/
- sw = fr_ptr_to_type(fr_schedule_worker_t, entry, entry);
if (pthread_join(sw->pthread_id, NULL) != 0) {
fr_log(sc->log, L_ERR, "Failed joining worker %i: %s", sw->id, fr_syserror(errno));
} else {
* @param[in] tt the time tracking structure.
* @param[in] when the event happened
*/
-void fr_time_tracking_start(fr_time_tracking_t *tt, fr_time_t when)
+void fr_time_tracking_start(fr_time_tracking_t *tt, fr_time_t when, fr_time_tracking_t *worker)
{
memset(tt, 0, sizeof(*tt));
tt->start = when;
tt->resumed = when;
- FR_DLIST_INIT(tt->list);
+ fr_dlist_init(&(worker->list), offsetof(fr_time_tracking_t, list.entry));
+ fr_dlist_entry_init(&tt->list.entry);
}
/*
* This request cannot be in any list.
*/
- rad_assert(tt->list.prev == &tt->list);
- rad_assert(tt->list.next == &tt->list);
+ rad_assert(tt->list.entry.prev == &(tt->list.entry));
+ rad_assert(tt->list.entry.next == &(tt->list.entry));
/*
* Update the time that the worker spent processing the request.
* Insert this request into the TAIL of the worker's list
* of waiting requests.
*/
- fr_dlist_insert_head(&worker->list, &tt->list);
+ fr_dlist_insert_head(&worker->list, tt);
}
* @param[in] tt the time tracking structure.
* @param[in] when the event happened
*/
-void fr_time_tracking_resume(fr_time_tracking_t *tt, fr_time_t when)
+void fr_time_tracking_resume(fr_time_tracking_t *tt, fr_time_t when, fr_time_tracking_t *worker)
{
tt->when = when;
tt->resumed = when;
* Remove this request into the workers list of waiting
* requests.
*/
- fr_dlist_remove(&tt->list);
+ fr_dlist_remove(&worker->list, tt);
}
fr_time_t running; //!< total time spent running
fr_time_t waiting; //!< total time spent waiting
- fr_dlist_t list; //!< for linking a request to various lists
+ fr_dlist_head_t list; //!< for linking a request to various lists
} fr_time_tracking_t;
#define NANOSEC (1000000000)
fr_time_t fr_time(void);
void fr_time_to_timeval(struct timeval *tv, fr_time_t when) CC_HINT(nonnull);
-void fr_time_tracking_start(fr_time_tracking_t *tt, fr_time_t when) CC_HINT(nonnull);
+void fr_time_tracking_start(fr_time_tracking_t *tt, fr_time_t when, fr_time_tracking_t *worker) CC_HINT(nonnull);
void fr_time_tracking_end(fr_time_tracking_t *tt, fr_time_t when, fr_time_tracking_t *worker) CC_HINT(nonnull);
void fr_time_tracking_yield(fr_time_tracking_t *tt, fr_time_t when, fr_time_tracking_t *worker) CC_HINT(nonnull);
-void fr_time_tracking_resume(fr_time_tracking_t *tt, fr_time_t when) CC_HINT(nonnull);
+void fr_time_tracking_resume(fr_time_tracking_t *tt, fr_time_t when, fr_time_tracking_t *worker) CC_HINT(nonnull);
void fr_time_tracking_debug(fr_time_tracking_t *tt, FILE *fp) CC_HINT(nonnull);
#ifdef __cplusplus
* Track things by priority and time.
*/
typedef struct fr_worker_heap_t {
- fr_dlist_t list; //!< list of things, ordered by time.
+ fr_dlist_head_t list; //!< list of things, ordered by time.
fr_heap_t *heap; //!< heap, ordered by priority
} fr_worker_heap_t;
* We need wrapper macros because we have multiple instances of
* the same code.
*/
-#define WORKER_HEAP_INIT(_name, _func, _type, _member) do { \
- FR_DLIST_INIT(worker->_name.list); \
- worker->_name.heap = fr_heap_create(worker, _func, _type, _member); \
+#define WORKER_HEAP_INIT(_name, _func) do { \
+ fr_dlist_init(&worker->_name.list, offsetof(fr_channel_data_t, request.entry)); \
+ worker->_name.heap = fr_heap_create(worker, _func, fr_channel_data_t, channel.heap_id); \
if (!worker->_name.heap) { \
(void) fr_event_user_delete(worker->el, fr_worker_evfilt_user, worker); \
talloc_free(worker); \
} \
} while (0)
-#define WORKER_HEAP_INSERT(_name, _var, _member) do { \
- fr_dlist_insert_head(&worker->_name.list, &_var->_member); \
- (void) fr_heap_insert(worker->_name.heap, _var); \
+#define WORKER_HEAP_INSERT(_name, _var) do { \
+ (void) fr_heap_insert(worker->_name.heap, _var); \
+ fr_dlist_insert_head(&worker->_name.list, _var); \
} while (0)
-#define WORKER_HEAP_POP(_name, _var, _member) do { \
- _var = fr_heap_pop(worker->_name.heap); \
- if (_var) fr_dlist_remove(&_var->_member); \
+#define WORKER_HEAP_POP(_name, _var) do { \
+ _var = fr_heap_pop(worker->_name.heap); \
+ if (_var) fr_dlist_remove(&worker->_name.list, _var); \
} while (0)
-#define WORKER_HEAP_EXTRACT(_name, _var, _member) do { \
- (void) fr_heap_extract(worker->_name.heap, _var); \
- fr_dlist_remove(&_var->_member); \
+#define WORKER_HEAP_EXTRACT(_name, _var) do { \
+ (void) fr_heap_extract(worker->_name.heap, _var); \
+ fr_dlist_remove(&worker->_name.list, _var); \
} while (0)
worker->num_requests++;
DEBUG3("\t%sreceived request %d", worker->name, worker->num_requests);
cd->channel.ch = ch;
- WORKER_HEAP_INSERT(to_decode, cd, request.list);
+ WORKER_HEAP_INSERT(to_decode, cd);
} while ((cd = fr_channel_recv_request(ch)) != NULL);
return true;
request->async->original_recv_time = NULL;
request->async->el = NULL;
request->async->process = NULL;
- fr_dlist_remove(&request->async->tracking.list);
+ fr_dlist_remove(&worker->tracking.list, &request->async->tracking);
request->async->channel = NULL;
request->async->packet_ctx = NULL;
request->async->listen = NULL;
*/
static void worker_stop_request(fr_worker_t *worker, REQUEST *request, fr_time_t now)
{
- fr_time_tracking_resume(&request->async->tracking, now);
+ fr_time_tracking_resume(&request->async->tracking, now, &worker->tracking);
(void) request->async->process(request->async->process_inst, request, FR_IO_ACTION_DONE);
/*
*/
static void fr_worker_check_timeouts(fr_worker_t *worker, fr_time_t now)
{
- fr_dlist_t *entry;
+ fr_channel_data_t *cd;
fr_time_t waiting;
/*
* We check it before the "to_decode" list, so that we
* don't check packets twice.
*/
- while ((entry = FR_DLIST_TAIL(worker->localized.list)) != NULL) {
- fr_channel_data_t *cd;
-
- cd = fr_ptr_to_type(fr_channel_data_t, request.list, entry);
+ while ((cd = fr_dlist_tail(&worker->localized.list)) != NULL) {
waiting = now - cd->m.when;
if (waiting < ((worker->max_request_time - 2) * (fr_time_t) NANOSEC)) break;
/*
* Waiting too long, delete it.
*/
- WORKER_HEAP_EXTRACT(localized, cd, request.list);
+ WORKER_HEAP_EXTRACT(localized, cd);
DEBUG3("TIMEOUT: Extracting packet from localized list");
fr_worker_nak(worker, cd, now);
}
/*
* Check the "to_decode" queue for old packets.
*/
- while ((entry = FR_DLIST_TAIL(worker->to_decode.list)) != NULL) {
+ while ((cd = fr_dlist_tail(&worker->to_decode.list)) != NULL) {
fr_message_t *lm;
- fr_channel_data_t *cd;
- cd = fr_ptr_to_type(fr_channel_data_t, request.list, entry);
waiting = now - cd->m.when;
if (waiting < (NANOSEC / 100)) break;
* Waiting too long, delete it.
*/
if (waiting > NANOSEC) {
- WORKER_HEAP_EXTRACT(to_decode, cd, request.list);
+ WORKER_HEAP_EXTRACT(to_decode, cd);
DEBUG3("TIMEOUT: Extracting packet from to_decode list");
nak:
/*
* 0.01 to 1s. Localize it.
*/
- WORKER_HEAP_EXTRACT(to_decode, cd, request.list);
+ WORKER_HEAP_EXTRACT(to_decode, cd);
lm = fr_message_localize(worker, &cd->m, sizeof(*cd));
if (!lm) {
DEBUG3("TIMEOUT: Failed localizing message from to_decode list: %s", fr_strerror());
}
cd = (fr_channel_data_t *) lm;
- WORKER_HEAP_INSERT(localized, cd, request.list);
+ WORKER_HEAP_INSERT(localized, cd);
}
}
DEBUG3("Worker %i found runnable request", fr_schedule_worker_id());
REQUEST_VERIFY(request);
rad_assert(request->runnable_id < 0);
- fr_time_tracking_resume(&request->async->tracking, now);
+ fr_time_tracking_resume(&request->async->tracking, now, &worker->tracking);
return request;
}
* the "to_decode" queue.
*/
do {
- WORKER_HEAP_POP(localized, cd, request.list);
+ WORKER_HEAP_POP(localized, cd);
if (!cd) {
- WORKER_HEAP_POP(to_decode, cd, request.list);
+ WORKER_HEAP_POP(to_decode, cd);
}
if (!cd) {
DEBUG3("Worker %i localized and decode lists are empty", fr_schedule_worker_id());
* Bootstrap the async state machine with the initial
* state of the request.
*/
- fr_time_tracking_start(&request->async->tracking, now);
+ fr_time_tracking_start(&request->async->tracking, now, &worker->tracking);
worker->num_active++;
rad_assert(request->runnable_id < 0);
* mark them as unused.
*/
while (true) {
- WORKER_HEAP_POP(to_decode, cd, request.list);
+ WORKER_HEAP_POP(to_decode, cd);
if (!cd) break;
fr_message_done(&cd->m);
}
while (true) {
- WORKER_HEAP_POP(localized, cd, request.list);
+ WORKER_HEAP_POP(localized, cd);
if (!cd) break;
fr_message_done(&cd->m);
}
* the worker thread is running.
*/
memset(&worker->tracking, 0, sizeof(worker->tracking));
- FR_DLIST_INIT(worker->tracking.list);
+ fr_dlist_init(&worker->tracking.list, offsetof(fr_time_tracking_t, list.entry));
worker->kq = fr_event_list_kq(worker->el);
rad_assert(worker->kq >= 0);
goto fail2;
}
- WORKER_HEAP_INIT(to_decode, worker_message_cmp, fr_channel_data_t, channel.heap_id);
- WORKER_HEAP_INIT(localized, worker_message_cmp, fr_channel_data_t, channel.heap_id);
+ WORKER_HEAP_INIT(to_decode, worker_message_cmp);
+ WORKER_HEAP_INIT(localized, worker_message_cmp);
worker->runnable = fr_heap_talloc_create(worker, worker_runnable_cmp, REQUEST, runnable_id);
if (!worker->runnable) {
struct fr_dlist_t *next;
} fr_dlist_t;
+typedef struct fr_dlist_head_t {
+ size_t offset;
+ fr_dlist_t entry;
+} fr_dlist_head_t;
+
/*
* Functions to manage a doubly linked list.
*/
-#define FR_DLIST_INIT(head) do { head.prev = head.next = &head; } while (0)
-static inline void fr_dlist_insert_head(fr_dlist_t *head, fr_dlist_t *entry)
+static inline void fr_dlist_entry_init(fr_dlist_t *entry)
+{
+ entry->prev = entry->next = entry;
+}
+
+static inline void fr_dlist_init(fr_dlist_head_t *head, size_t offset)
+{
+ fr_dlist_entry_init(&head->entry);
+ head->offset = offset;
+}
+
+static inline void fr_dlist_insert_head(fr_dlist_head_t *list_head, void *ptr)
{
+ fr_dlist_t *entry = (fr_dlist_t *) (((uint8_t *) ptr) + list_head->offset);
+ fr_dlist_t *head = &(list_head->entry);
+
if (!fr_cond_assert(head->next != NULL)) return;
if (!fr_cond_assert(head->prev != NULL)) return;
head->next = entry;
}
-static inline void fr_dlist_insert_tail(fr_dlist_t *head, fr_dlist_t *entry)
+static inline void fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
{
+ fr_dlist_t *entry = (fr_dlist_t *) (((uint8_t *) ptr) + list_head->offset);
+ fr_dlist_t *head = &(list_head->entry);
+
if (!fr_cond_assert(head->next != NULL)) return;
if (!fr_cond_assert(head->prev != NULL)) return;
/*
* Insert one list into the tail of another
*/
-static inline void fr_dlist_insert_tail_list(fr_dlist_t *head, fr_dlist_t *list)
+static inline void fr_dlist_insert_tail_list(fr_dlist_head_t *list_head, fr_dlist_t *list)
{
+ fr_dlist_t *head = &(list_head->entry);
+
if (!fr_cond_assert(head->next != NULL)) return;
if (!fr_cond_assert(head->prev != NULL)) return;
}
#endif
-static inline void fr_dlist_remove(fr_dlist_t *entry)
+static inline void fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
{
+ fr_dlist_t *entry = (fr_dlist_t *) (((uint8_t *) ptr) + list_head->offset);
+
if (!fr_cond_assert(entry->next != NULL)) return;
if (!fr_cond_assert(entry->prev != NULL)) return;
entry->prev = entry->next = entry;
}
-#define FR_DLIST_FIRST(head) ((head.next == &head) ? NULL : head.next)
-#define FR_DLIST_NEXT(head, p_entry) ((p_entry->next == &head) ? NULL : p_entry->next)
-#define FR_DLIST_TAIL(head) ((head.prev == &head) ? NULL : head.prev)
+static inline void *fr_dlist_next(fr_dlist_head_t *list_head, void *ptr)
+{
+ fr_dlist_t *entry = (fr_dlist_t *) (((uint8_t *) ptr) + list_head->offset);
+ fr_dlist_t *head = &(list_head->entry);
+
+ if (entry->next == head) return NULL;
+ entry = entry->next;
+ return (void *) (((uint8_t *) entry) - list_head->offset);
+}
+static inline void *fr_dlist_first(fr_dlist_head_t *list_head)
+{
+ fr_dlist_t *head = &(list_head->entry);
+
+ if (head->next == head) return NULL;
+
+ return (void *) (((uint8_t *) head->next) - list_head->offset);
+
+}
+
+static inline void *fr_dlist_tail(fr_dlist_head_t *list_head)
+{
+ fr_dlist_t *head = &(list_head->entry);
+
+ if (head->prev == head) return NULL;
+
+ return (void *) (((uint8_t *) head->prev) - list_head->offset);
+
+}
+
+#if 0
#ifdef WITH_VERIFY_PTR
# define FR_DLIST_VERIFY(_head, _type, _member) \
do { \
#else
# define FR_DLIST_VERIFY(_head, _type, _member)
#endif
+#endif
/** Convert a pointer to a member into a pointer to the parent structure.
*
int kq; //!< instance associated with this event list.
- fr_dlist_t pre_callbacks; //!< callbacks when we may be idle...
- fr_dlist_t user_callbacks; //!< EVFILT_USER callbacks
- fr_dlist_t post_callbacks; //!< post-processing callbacks
+ fr_dlist_head_t pre_callbacks; //!< callbacks when we may be idle...
+ fr_dlist_head_t user_callbacks; //!< EVFILT_USER callbacks
+ fr_dlist_head_t post_callbacks; //!< post-processing callbacks
struct kevent events[FR_EV_BATCH_FDS]; /* so it doesn't go on the stack every time */
user->uctx = uctx;
user->ident = (uintptr_t) user;
- fr_dlist_insert_tail(&el->user_callbacks, &user->entry);
+ fr_dlist_insert_tail(&el->user_callbacks, user);
return user->ident;;
}
*/
int fr_event_user_delete(fr_event_list_t *el, fr_event_user_handler_t callback, void *uctx)
{
- fr_dlist_t *entry, *next;
+ fr_event_user_t *user, *next;
- for (entry = FR_DLIST_FIRST(el->user_callbacks);
- entry != NULL;
- entry = next) {
- fr_event_user_t *user;
+ for (user = fr_dlist_first(&el->user_callbacks);
+ user != NULL;
+ user = next) {
+ next = fr_dlist_next(&el->user_callbacks, user);
- next = FR_DLIST_NEXT(el->user_callbacks, entry);
-
- user = fr_ptr_to_type(fr_event_user_t, entry, entry);
if ((user->callback == callback) &&
(user->uctx == uctx)) {
- fr_dlist_remove(entry);
+ fr_dlist_remove(&el->user_callbacks, user);
talloc_free(user);
return 0;
}
pre->callback = callback;
pre->uctx = uctx;
- fr_dlist_insert_tail(&el->pre_callbacks, &pre->entry);
+ fr_dlist_insert_tail(&el->pre_callbacks, pre);
return 0;
}
*/
int fr_event_pre_delete(fr_event_list_t *el, fr_event_status_cb_t callback, void *uctx)
{
- fr_dlist_t *entry, *next;
-
- for (entry = FR_DLIST_FIRST(el->pre_callbacks);
- entry != NULL;
- entry = next) {
- fr_event_pre_t *pre;
+ fr_event_pre_t *pre, *next;
- next = FR_DLIST_NEXT(el->pre_callbacks, entry);
+ for (pre = fr_dlist_first(&el->pre_callbacks);
+ pre != NULL;
+ pre = next) {
+ next = fr_dlist_next(&el->pre_callbacks, pre);
- pre = fr_ptr_to_type(fr_event_pre_t, entry, entry);
if ((pre->callback == callback) &&
(pre->uctx == uctx)) {
- fr_dlist_remove(entry);
+ fr_dlist_remove(&el->pre_callbacks, pre);
talloc_free(pre);
return 0;
}
post->callback = callback;
post->uctx = uctx;
- fr_dlist_insert_tail(&el->post_callbacks, &post->entry);
+ fr_dlist_insert_tail(&el->post_callbacks, post);
return 0;
}
*/
int fr_event_post_delete(fr_event_list_t *el, fr_event_cb_t callback, void *uctx)
{
- fr_dlist_t *entry, *next;
-
- for (entry = FR_DLIST_FIRST(el->post_callbacks);
- entry != NULL;
- entry = next) {
- fr_event_post_t *post;
+ fr_event_post_t *post, *next;
- next = FR_DLIST_NEXT(el->post_callbacks, entry);
+ for (post = fr_dlist_first(&el->post_callbacks);
+ post != NULL;
+ post = next) {
+ next = fr_dlist_next(&el->post_callbacks, post);
- post = fr_ptr_to_type(fr_event_post_t, entry, entry);
if ((post->callback == callback) &&
(post->uctx == uctx)) {
- fr_dlist_remove(entry);
+ fr_dlist_remove(&el->post_callbacks, post);
talloc_free(post);
return 0;
}
{
struct timeval when, *wake;
struct timespec ts_when, *ts_wake;
- fr_dlist_t *entry;
+ fr_event_pre_t *pre;
int num_fd_events, num_timer_events;
el->num_fd_events = 0;
* application has more work to do, in which case we
* re-set the timeout to be instant.
*/
- for (entry = FR_DLIST_FIRST(el->pre_callbacks);
- entry != NULL;
- entry = FR_DLIST_NEXT(el->pre_callbacks, entry)) {
- fr_event_pre_t *pre;
-
- pre = fr_ptr_to_type(fr_event_pre_t, entry, entry);
+ for (pre = fr_dlist_first(&el->pre_callbacks);
+ pre != NULL;
+ pre = fr_dlist_next(&el->pre_callbacks, pre)) {
if (pre->callback(pre->uctx, wake) > 0) {
num_timer_events++;
wake = &when;
void fr_event_service(fr_event_list_t *el)
{
int i;
- fr_dlist_t *entry;
+ fr_event_post_t *post;
struct timeval when;
if (unlikely(el->exit)) return;
/*
* Run all of the post-processing events.
*/
- for (entry = FR_DLIST_FIRST(el->post_callbacks);
- entry != NULL;
- entry = FR_DLIST_NEXT(el->post_callbacks, entry)) {
- fr_event_post_t *post;
-
+ for (post = fr_dlist_first(&el->post_callbacks);
+ post != NULL;
+ post = fr_dlist_next(&el->post_callbacks, post)) {
when = el->now;
- post = fr_ptr_to_type(fr_event_post_t, entry, entry);
post->callback(el, &when, post->uctx);
}
}
goto error;
}
- FR_DLIST_INIT(el->pre_callbacks);
- FR_DLIST_INIT(el->post_callbacks);
- FR_DLIST_INIT(el->user_callbacks);
+ fr_dlist_init(&el->pre_callbacks, offsetof(fr_event_pre_t, entry));
+ fr_dlist_init(&el->post_callbacks, offsetof(fr_event_post_t, entry));
+ fr_dlist_init(&el->user_callbacks, offsetof(fr_event_user_t, entry));
if (status) (void) fr_event_pre_insert(el, status, status_uctx);
pid_t pid;
} fr_child_t;
-fr_thread_local_setup(fr_dlist_t *, fr_children) /* macro */
+fr_thread_local_setup(fr_dlist_head_t *, fr_children) /* macro */
static void _fr_children_free(void *arg)
{
char *envp[MAX_ENVP];
size_t envlen = 0;
TALLOC_CTX *input_ctx = NULL;
- fr_dlist_t *list;
+ fr_dlist_head_t *list;
/*
* Stupid array decomposition...
list = fr_children;
if (!list) {
- list = talloc_zero(NULL, fr_dlist_t);
+ list = talloc_zero(NULL, fr_dlist_head_t);
if (!list) {
ERROR("Out of memory");
return -1;
}
- list->prev = list->next = list;
+ fr_dlist_init(list, offsetof(fr_child_t, entry));
fr_thread_local_set_destructor(fr_children, _fr_children_free, list);
} else {
- fr_dlist_t *entry, *next;
-
- entry = list->next;
+ fr_child_t *child, *next;
/*
* Clean up the children. ALL of them. This is
* slow as heck, but correct. :(
*/
- while (entry != list) {
+ for (child = fr_dlist_first(fr_children);
+ child != NULL;
+ child = next) {
int status;
- fr_child_t *child;
-
- next = entry->next;
- child = fr_ptr_to_type(fr_child_t, entry, entry);
+ next = fr_dlist_next(fr_children, child);
pid = waitpid(child->pid, &status, WNOHANG);
if (pid != 0) {
- fr_dlist_remove(entry);
+ fr_dlist_remove(fr_children, child);
talloc_free(child);
}
-
- entry = next;
}
}
fr_child_t *child;
MEM(child = talloc_zero(fr_children, fr_child_t));
- fr_dlist_insert_tail(fr_children, &child->entry);
+ fr_dlist_insert_tail(fr_children, child);
child->pid = pid;
}
uint64_t seq_start; //!< Number of first request in this sequence.
time_t cleanup; //!< When this entry should be cleaned up.
- fr_dlist_t list; //!< Entry in the list of things to expire.
+ fr_dlist_t entry; //!< Entry in the list of things to expire.
int tries;
//!< timeout.
uint32_t max_sessions; //!< Maximum number of sessions we track.
rbtree_t *tree; //!< rbtree used to lookup state value.
- fr_dlist_t to_expire; //!< Linked list of entries to free.
+ fr_dlist_head_t to_expire; //!< Linked list of entries to free.
uint32_t timeout; //!< How long to wait before cleaning up state entires.
*/
static int _state_tree_free(fr_state_tree_t *state)
{
- fr_dlist_t *next;
+ fr_state_entry_t *entry;
if (main_config->spawn_workers) pthread_mutex_destroy(&state->mutex);
DEBUG4("Freeing state tree %p", state);
- while ((next = FR_DLIST_FIRST(state->to_expire))) {
- fr_state_entry_t *entry;
-
- entry = fr_ptr_to_type(fr_state_entry_t, list, next);
+ while ((entry = fr_dlist_first(&state->to_expire))) {
state_entry_unlink(state, entry);
talloc_free(entry);
}
return NULL;
}
- FR_DLIST_INIT(state->to_expire);
+ fr_dlist_init(&state->to_expire, offsetof(fr_state_entry_t, entry));
/*
* We need to do controlled freeing of the
*/
(void) talloc_get_type_abort(entry, fr_state_entry_t);
- fr_dlist_remove(&entry->list);
+ fr_dlist_remove(&state->to_expire, entry);
rbtree_deletebydata(state->tree, entry);
* so we know it'll be cleaned up.
*/
if (entry->data) (void)fr_cond_assert(request_data_verify_parent(entry->ctx, entry->data));
-
- /*
- * Verify the state entry is no longer linked
- */
- rad_assert(entry->list.prev == &entry->list);
- rad_assert(entry->list.next == &entry->list);
#endif
/*
uint32_t x;
time_t now = time(NULL);
VALUE_PAIR *vp;
- fr_state_entry_t *entry;
+ fr_state_entry_t *entry, *next;
uint8_t old_state[sizeof(old->state)];
int old_tries = 0;
uint64_t timed_out = 0;
bool too_many = false;
- fr_dlist_t to_free, *next;
+ fr_dlist_head_t to_free;
- FR_DLIST_INIT(to_free);
+ fr_dlist_init(&to_free, offsetof(fr_state_entry_t, entry));
/*
* Clean up old entries.
*/
- next = FR_DLIST_FIRST(state->to_expire);
- while (next) {
- entry = fr_ptr_to_type(fr_state_entry_t, list, next);
+ for (entry = fr_dlist_first(&state->to_expire);
+ entry != NULL;
+ entry = next) {
(void)talloc_get_type_abort(entry, fr_state_entry_t); /* Allow examination */
- next = FR_DLIST_NEXT(state->to_expire, next); /* Advance *before* potential unlinking */
+ next = fr_dlist_next(&state->to_expire, entry); /* Advance *before* potential unlinking */
if (entry == old) continue;
*/
if (entry->cleanup < now) {
state_entry_unlink(state, entry);
- fr_dlist_insert_tail(&to_free, &entry->list);
+ fr_dlist_insert_tail(&to_free, entry);
timed_out++;
continue;
}
*/
if (!old->data) {
state_entry_unlink(state, old);
- fr_dlist_insert_tail(&to_free, &old->list);
+ fr_dlist_insert_tail(&to_free, old);
}
}
PTHREAD_MUTEX_UNLOCK(&state->mutex);
* be freed also, and it may have complex destructors associated
* with it.
*/
- while ((next = FR_DLIST_FIRST(to_free)) != NULL) {
- fr_dlist_remove(next);
- talloc_free(fr_ptr_to_type(fr_state_entry_t, list, next));
+ while ((entry = fr_dlist_first(&to_free)) != NULL) {
+ fr_dlist_remove(&to_free, entry);
+ talloc_free(entry);
}
/*
* Link it to the end of the list, which is implicitely
* ordered by cleanup time.
*/
- fr_dlist_insert_tail(&state->to_expire, &entry->list);
+ fr_dlist_insert_tail(&state->to_expire, entry);
return entry;
}
uint32_t max_outstanding; //!< number of packets to run in parallel
uint32_t outstanding; //!< number of currently outstanding records;
- fr_dlist_t list; //!< for retransmissions
+ fr_dlist_head_t list; //!< for retransmissions
bool vnode; //!< are we the vnode instance,
//!< or the filename_work instance?
uint8_t *partial, *end, *next, *p, *record_end;
uint8_t *stopped_search;
off_t done_offset;
- fr_dlist_t *entry;
rad_assert(*leftover < buffer_len);
rad_assert(inst->fd >= 0);
* Process retransmissions before anything else in the
* file.
*/
- entry = FR_DLIST_FIRST(inst->list);
- if (entry) {
- track = fr_ptr_to_type(fr_detail_entry_t, entry, entry);
-
- fr_dlist_remove(&track->entry);
+ track = fr_dlist_first(&inst->list);
+ if (track) {
+ fr_dlist_remove(&inst->list, track);
/*
* Don't over-write "leftover" bytes!
DEBUG("%s - retransmitting packet %d", inst->name, track->id);
track->count++;
- fr_dlist_insert_tail(&inst->list, &track->entry);
+ fr_dlist_insert_tail(&inst->list, &track);
if (inst->paused && (inst->outstanding < inst->max_outstanding)) {
(void) fr_event_filter_update(inst->el, inst->fd, FR_EVENT_FILTER_IO, resume_read);
proto_detail_work_t *inst = talloc_get_type_abort(instance, proto_detail_work_t);
RADCLIENT *client;
- FR_DLIST_INIT(inst->list);
+ fr_dlist_init(&inst->list, offsetof(fr_detail_entry_t, entry));
client = inst->client = talloc_zero(inst, RADCLIENT);
if (!inst->client) return 0;
*/
static int mod_link_free(rlm_radius_link_t *link)
{
- fr_dlist_remove(&link->entry);
+ fr_dlist_remove(&link->t->running, link);
/*
* Free the child's request io context. That will call
*/
radius_fixups(inst, request);
- fr_dlist_insert_tail(&t->running, &link->entry);
+ fr_dlist_insert_tail(&t->running, link);
talloc_set_destructor(link, mod_link_free);
/*
t->inst = instance;
t->el = el;
- FR_DLIST_INIT(t->running);
+ fr_dlist_init(&t->running, offsetof(rlm_radius_link_t, entry));
/*
* Allocate thread-specific data. The connections should
{
rlm_radius_thread_t *t = talloc_get_type_abort(thread, rlm_radius_thread_t);
rlm_radius_t const *inst = t->inst;
- fr_dlist_t *entry;
/*
* Tell the submodule to shut down all of its
* marked DONE, and (in an ideal world) resumed / cleaned
* up before this memory is freed.
*/
- entry = FR_DLIST_FIRST(t->running);
- if (entry != NULL) {
+ if (fr_dlist_first(&t->running) != NULL) {
ERROR("Module still has running requests!");
return -1;
}
rlm_radius_t const *inst; //!< Instance of the module.
fr_event_list_t *el; //!< This thread's event list.
- fr_dlist_t running; //!< running requests
+ fr_dlist_head_t running; //!< running requests
void *thread_io_ctx; //!< thread context for the IO submodule
} rlm_radius_thread_t;
fr_heap_t *queued; //!< Queued requests for some new connection.
fr_heap_t *active; //!< Active connections.
- fr_dlist_t blocked; //!< blocked connections, waiting for writable
- fr_dlist_t full; //!< Full connections.
- fr_dlist_t zombie; //!< Zombie connections.
- fr_dlist_t opening; //!< Opening connections.
+ fr_dlist_head_t blocked; //!< blocked connections, waiting for writable
+ fr_dlist_head_t full; //!< Full connections.
+ fr_dlist_head_t zombie; //!< Zombie connections.
+ fr_dlist_head_t opening; //!< Opening connections.
} rlm_radius_udp_thread_t;
typedef enum rlm_radius_udp_connection_state_t {
fr_event_timer_t const *zombie_ev; //!< Zombie timeout.
struct timeval zombie_start; //!< When the zombie period started.
- fr_dlist_t sent; //!< List of sent packets.
+ fr_dlist_head_t sent; //!< List of sent packets.
uint32_t max_packet_size; //!< Our max packet size. may be different from the parent.
int fd; //!< File descriptor.
/*
* No outstanding packets, we're idle.
*/
- if (FR_DLIST_FIRST(c->sent) == NULL) {
+ if (fr_dlist_first(&c->sent) == NULL) {
break;
}
rad_assert(u->rr != NULL);
rad_assert(u->c != NULL);
(void) rr_track_delete(u->c->id, u->rr);
- fr_dlist_remove(&u->entry);
+ fr_dlist_remove(&u->c->sent, u);
u->rr = NULL;
u->c = NULL;
break;
case PACKET_STATE_SENT:
rad_assert(u->rr != NULL);
rad_assert(u->c != NULL);
- fr_dlist_insert_tail(&u->c->sent, &u->entry);
+ fr_dlist_insert_tail(&u->c->sent, u);
break;
case PACKET_STATE_RESUMABLE:
case CONN_OPENING:
case CONN_FULL:
case CONN_BLOCKED:
- fr_dlist_remove(&c->entry);
+ fr_dlist_remove(&c->thread->blocked, c); /* we only need 'offset' from the list */
break;
case CONN_ACTIVE:
*/
if (state == CONN_BLOCKED) return;
- fr_dlist_remove(&c->entry);
+ fr_dlist_remove(&c->thread->blocked, c);
if (c->zombie_ev) (void) fr_event_timer_delete(c->thread->el, &c->zombie_ev);
break;
}
break;
case CONN_OPENING:
- fr_dlist_insert_head(&c->thread->opening, &c->entry);
+ fr_dlist_insert_head(&c->thread->opening, c);
break;
case CONN_ACTIVE:
case CONN_BLOCKED:
if (c->idle_ev) (void) fr_event_timer_delete(c->thread->el, &c->idle_ev);
- fr_dlist_insert_head(&c->thread->blocked, &c->entry);
+ fr_dlist_insert_head(&c->thread->blocked, c);
break;
case CONN_FULL:
if (c->idle_ev) (void) fr_event_timer_delete(c->thread->el, &c->idle_ev);
- fr_dlist_insert_head(&c->thread->full, &c->entry);
+ fr_dlist_insert_head(&c->thread->full, c);
break;
case CONN_ZOMBIE:
if (c->idle_ev) (void) fr_event_timer_delete(c->thread->el, &c->idle_ev);
- fr_dlist_insert_head(&c->thread->zombie, &c->entry);
+ fr_dlist_insert_head(&c->thread->zombie, c);
gettimeofday(&when, NULL);
c->zombie_start = when;
* timer events before reconnecting.
*/
if (state == FR_CONNECTION_STATE_CONNECTED) {
- fr_dlist_t *entry;
+ rlm_radius_udp_request_t *u;
/*
* Reset the Status-Server checks.
*/
if (c->status_u) {
- rlm_radius_udp_request_t *u = c->status_u;
+ u = c->status_u;
if (u->timer.ev) (void) fr_event_timer_delete(c->thread->el, &u->timer.ev);
/*
* Move "sent" packets back to the thread queue,
*/
- while ((entry = FR_DLIST_FIRST(c->sent)) != NULL) {
- rlm_radius_udp_request_t *u;
-
- u = fr_ptr_to_type(rlm_radius_udp_request_t, entry, entry);
+ while ((u = fr_dlist_first(&c->sent)) != NULL) {
state_transition(u, PACKET_STATE_THREAD);
}
}
rad_assert(c->zombie_ev == NULL);
memset(&c->zombie_start, 0, sizeof(c->zombie_start));
- FR_DLIST_INIT(c->sent);
+ fr_dlist_init(&c->sent, offsetof(rlm_radius_udp_request_t, entry));
/*
* Status-Server checks. Manually build the packet, and
* Initialize the link. Note that we don't set
* destructors.
*/
- FR_DLIST_INIT(link->entry);
link->request = request;
link->request_io_ctx = u;
/*
* Unitialize the UDP link.
*/
- FR_DLIST_INIT(u->entry);
u->code = c->inst->parent->status_check;
request->packet->code = u->code;
u->c = c;
*/
static int _conn_free(rlm_radius_udp_connection_t *c)
{
- fr_dlist_t *entry;
rlm_radius_udp_request_t *u;
rlm_radius_udp_thread_t *t = talloc_get_type_abort(c->thread, rlm_radius_udp_thread_t);
/*
* Move "sent" packets back to the main thread queue
*/
- while ((entry = FR_DLIST_FIRST(c->sent)) != NULL) {
- u = fr_ptr_to_type(rlm_radius_udp_request_t, entry, entry);
-
+ while ((u = fr_dlist_first(&c->sent)) != NULL) {
rad_assert(u->state == PACKET_STATE_SENT);
rad_assert(u->c == c);
case CONN_OPENING:
case CONN_FULL:
case CONN_ZOMBIE:
- fr_dlist_remove(&c->entry);
+ fr_dlist_remove(&c->thread->blocked, c);
break;
case CONN_ACTIVE:
talloc_free(c);
return;
}
- FR_DLIST_INIT(c->sent);
+ fr_dlist_init(&c->sent, offsetof(rlm_radius_udp_request_t, entry));
c->conn = fr_connection_alloc(c, t->el, &inst->parent->connection_timeout, &inst->parent->reconnection_delay,
_conn_init,
u->thread = t;
u->heap_id = -1;
u->timer.retry = &inst->parent->retry[u->code];
- FR_DLIST_INIT(u->entry);
+ fr_dlist_entry_init(&u->entry);
talloc_set_destructor(u, udp_request_free);
*/
c = fr_heap_peek(t->active);
if (!c) {
- fr_dlist_t *entry;
-
/*
* Only open one new connection at a time.
*/
- entry = FR_DLIST_FIRST(t->opening);
- if (!entry) conn_alloc(inst, t);
+ if (!fr_dlist_first(&t->opening)) conn_alloc(inst, t);
/*
* Add the request to the backlog. It will be
t->el = el;
t->queued = fr_heap_talloc_create(t, queue_cmp, rlm_radius_udp_request_t, heap_id);
- FR_DLIST_INIT(t->blocked);
- FR_DLIST_INIT(t->full);
- FR_DLIST_INIT(t->zombie);
- FR_DLIST_INIT(t->opening);
+ fr_dlist_init(&t->blocked, offsetof(rlm_radius_udp_connection_t, entry));
+ fr_dlist_init(&t->full, offsetof(rlm_radius_udp_connection_t, entry));
+ fr_dlist_init(&t->zombie, offsetof(rlm_radius_udp_connection_t, entry));
+ fr_dlist_init(&t->opening, offsetof(rlm_radius_udp_connection_t, entry));
t->active = fr_heap_talloc_create(t, conn_cmp, rlm_radius_udp_connection_t, heap_id);
static int mod_thread_detach(UNUSED fr_event_list_t *el, void *thread)
{
rlm_radius_udp_thread_t *t = talloc_get_type_abort(thread, rlm_radius_udp_thread_t);
- fr_dlist_t *entry;
if (fr_heap_num_elements(t->queued) != 0) {
ERROR("There are still queued requests");
*/
talloc_free_children(t);
- entry = FR_DLIST_FIRST(t->opening);
- if (entry != NULL) {
+ if (fr_dlist_first(&t->opening) != NULL) {
ERROR("There are still partially open sockets");
return -1;
}
id = talloc_zero(ctx, rlm_radius_id_t);
if (!id) return NULL;
- FR_DLIST_INIT(id->free_list);
+ fr_dlist_init(&id->free_list, offsetof(rlm_radius_request_t, entry));
for (i = 0; i < 256; i++) {
id->id[i].id = i;
- fr_dlist_insert_tail(&id->free_list, &id->id[i].entry);
+ fr_dlist_insert_tail(&id->free_list, &id->id[i]);
id->num_free++;
}
rlm_radius_request_t *rr_track_alloc(rlm_radius_id_t *id, REQUEST *request, int code, rlm_radius_link_t *link,
rlm_radius_retransmit_t *timer)
{
- fr_dlist_t *entry;
rlm_radius_request_t *rr;
retry:
- entry = FR_DLIST_FIRST(id->free_list);
- if (entry) {
+ rr = fr_dlist_first(&id->free_list);
+ if (rr) {
rad_assert(id->num_free > 0);
- rr = fr_ptr_to_type(rlm_radius_request_t, entry, entry);
-
rad_assert(rr->request == NULL);
/*
* Mark it as used, and remove it from the free list.
*/
- fr_dlist_remove(&rr->entry);
+ fr_dlist_remove(&id->free_list, rr);
id->num_free--;
/*
* Allocate a new one, and insert it into the appropriate subtree.
*/
rr = talloc_zero(id, rlm_radius_request_t);
- FR_DLIST_INIT(rr->entry);
rr->id = id->next_id;
done:
* Otherwise put it back on the free list.
*/
done:
- fr_dlist_insert_tail(&id->free_list, &rr->entry);
+ fr_dlist_insert_tail(&id->free_list, rr);
id->num_free++;
return 0;
int num_requests; //!< number of requests in the allocation
int num_free; //!< number of entries in the free list
- fr_dlist_t free_list; //!< so we allocate by least recently used
+ fr_dlist_head_t free_list; //!< so we allocate by least recently used
bool use_authenticator; //!< whether to use the request authenticator as an ID
int next_id; //!< next ID to allocate
fr_dict_attr_t const *type_da; //!< FreeRADIUS-Stats4-Type
fr_dict_attr_t const *ipv4_da; //!< FreeRADIUS-Stats4-IPv4-Address
fr_dict_attr_t const *ipv6_da; //!< FreeRADIUS-Stats4-IPv6-Address
- fr_dlist_t entry; //!< for threads to know about each other
+ fr_dlist_head_t list; //!< for threads to know about each other
uint64_t stats[FR_MAX_PACKET_CODE];
} rlm_stats_t;
rlm_stats_data_t *mydata)
{
rlm_stats_data_t *stats;
- fr_dlist_t *entry;
rlm_stats_thread_t *other;
#ifdef HAVE_PTHREAD_H
pthread_mutex_t *mutex;
* Loop over all of the other thread instances, locking
* them, and adding their statistics in.
*/
- for (entry = FR_DLIST_FIRST(t->inst->entry);
- entry != NULL;
- entry = FR_DLIST_NEXT(t->inst->entry, entry)) {
- other = fr_ptr_to_type(rlm_stats_thread_t, entry, entry);
+ for (other = fr_dlist_first(&t->inst->list);
+ other != NULL;
+ other = fr_dlist_next(&t->inst->list, other)) {
int i;
if (other == t) continue;
t->dst = rbtree_talloc_create(t, data_cmp, rlm_stats_data_t, NULL, RBTREE_FLAG_NONE);
PTHREAD_MUTEX_LOCK(&inst->mutex);
- fr_dlist_insert_head(&inst->entry, &t->entry);
+ fr_dlist_insert_head(&inst->list, t);
PTHREAD_MUTEX_UNLOCK(&inst->mutex);
return 0;
for (i = 0; i < FR_MAX_PACKET_CODE; i++) {
inst->stats[i] += t->stats[i];
}
- fr_dlist_remove(&t->entry);
+ fr_dlist_remove(&inst->list, t);
PTHREAD_MUTEX_UNLOCK(&inst->mutex);
return 0;
pthread_mutex_init(&inst->mutex, NULL);
#endif
- FR_DLIST_INIT(inst->entry);
+ fr_dlist_init(&inst->list, offsetof(rlm_stats_thread_t, entry));
return 0;
}
* Instead, all of it is done in the context of the
* parent.
*/
- FR_DLIST_INIT(child->async->tracking.list);
+ fr_dlist_init(&child->async->tracking.list, 0);
/*
* create {...} creates an empty copy.