30 RCSID(
"$Id: 465a09a359172389677a73e9109955ec4d7865e7 $")
32 #include <freeradius-devel/util/dlist.h>
33 #include <freeradius-devel/util/event.h>
34 #include <freeradius-devel/util/lst.h>
35 #include <freeradius-devel/util/log.h>
36 #include <freeradius-devel/util/rb.h>
37 #include <freeradius-devel/util/strerror.h>
38 #include <freeradius-devel/util/syserror.h>
39 #include <freeradius-devel/util/table.h>
40 #include <freeradius-devel/util/token.h>
41 #include <freeradius-devel/util/atexit.h>
57 #define FR_EV_BATCH_FDS (256)
60 #define fr_time() static_assert(0, "Use el->time for event loop timing")
63 #if !defined(SO_GET_FILTER) && defined(SO_ATTACH_FILTER)
64 # define SO_GET_FILTER SO_ATTACH_FILTER
67 #ifdef WITH_EVENT_DEBUG
68 # define EVENT_DEBUG(fmt, ...) printf("EVENT:");printf(fmt, ## __VA_ARGS__);printf("\n");
69 # ifndef EVENT_REPORT_FREQ
70 # define EVENT_REPORT_FREQ 5
73 # define EVENT_DEBUG(...)
78 {
L(
"EVFILT_AIO"), EVFILT_AIO },
81 {
L(
"EVFILT_EXCEPT"), EVFILT_EXCEPT },
83 #ifdef EVFILT_MACHPORT
84 {
L(
"EVFILT_MACHPORT"), EVFILT_MACHPORT },
86 {
L(
"EVFILT_PROC"), EVFILT_PROC },
87 {
L(
"EVFILT_READ"), EVFILT_READ },
88 {
L(
"EVFILT_SIGNAL"), EVFILT_SIGNAL },
89 {
L(
"EVFILT_TIMER"), EVFILT_TIMER },
90 {
L(
"EVFILT_VNODE"), EVFILT_VNODE },
91 {
L(
"EVFILT_WRITE"), EVFILT_WRITE }
95 #ifdef EVFILT_LIBKQUEUE
96 static int log_conf_kq;
144 #ifndef SO_GET_FILTER
145 # define FR_EVENT_FD_PCAP 0
179 .filter = EVFILT_READ,
180 .flags = EV_ADD | EV_ENABLE,
191 .filter = EVFILT_WRITE,
192 .flags = EV_ADD | EV_ENABLE,
205 .filter = EVFILT_VNODE,
206 .flags = EV_ADD | EV_ENABLE | EV_CLEAR,
207 .fflags = NOTE_DELETE,
214 .filter = EVFILT_VNODE,
215 .flags = EV_ADD | EV_ENABLE | EV_CLEAR,
216 .fflags = NOTE_WRITE,
223 .filter = EVFILT_VNODE,
224 .flags = EV_ADD | EV_ENABLE | EV_CLEAR,
225 .fflags = NOTE_EXTEND,
232 .filter = EVFILT_VNODE,
233 .flags = EV_ADD | EV_ENABLE | EV_CLEAR,
234 .fflags = NOTE_ATTRIB,
241 .filter = EVFILT_VNODE,
242 .flags = EV_ADD | EV_ENABLE | EV_CLEAR,
250 .filter = EVFILT_VNODE,
251 .flags = EV_ADD | EV_ENABLE | EV_CLEAR,
252 .fflags = NOTE_RENAME,
260 .filter = EVFILT_VNODE,
261 .flags = EV_ADD | EV_ENABLE | EV_CLEAR,
262 .fflags = NOTE_REVOKE,
271 .filter = EVFILT_VNODE,
272 .flags = EV_ADD | EV_ENABLE | EV_CLEAR,
273 .fflags = NOTE_FUNLOCK,
442 #ifdef WITH_EVENT_DEBUG
485 if (pos > high) high = pos;
508 fflags &= ~(1 << pos);
533 #define GET_FUNC(_ef, _offset) *((fr_event_fd_cb_t const *)((uint8_t const *)&(_ef)->active + _offset))
544 if (!*filter)
return NULL;
554 int our_fflags = *fflags;
557 if (!pos)
return NULL;
560 *fflags = our_fflags & ~(1 << pos);
679 #ifndef WITH_EVENT_DEBUG
687 struct kevent *
out = out_kev, *end =
out + outlen;
689 struct kevent add[10], *add_p = add;
692 EVENT_DEBUG(
"%p - Building new evset for FD %i (new %p, prev %p)",
el, ef->
fd,
new, prev);
699 bool has_current_func =
false;
700 bool has_prev_func =
false;
715 prev_fflags |= map->
fflags;
716 has_prev_func =
true;
724 current_fflags |= map->
fflags;
725 has_current_func =
true;
736 map->
type,
"<INVALID>"));
755 if (!(map + 1)->coalesce)
break;
767 if (has_current_func &&
768 (!has_prev_func || (current_fflags != prev_fflags))) {
773 EVENT_DEBUG(
"\tEV_SET EV_ADD filter %s (%i), flags %i, fflags %i",
776 EV_SET(add_p++, ef->
fd, map->
filter, map->
flags, current_fflags, 0, ef);
781 }
else if (!has_current_func && has_prev_func) {
782 EVENT_DEBUG(
"\tEV_SET EV_DELETE filter %s (%i), flags %i, fflags %i",
784 map->
filter, EV_DELETE, 0);
785 EV_SET(
out++, ef->
fd, map->
filter, EV_DELETE, 0, 0, ef);
795 for (i = 0; i < (
size_t)(add_p - add); i++) memcpy(
out++, &add[i],
sizeof(*
out));
797 return out - out_kev;
813 socklen_t opt_len =
sizeof(ef->
sock_type);
818 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &ef->
sock_type, &opt_len) == 0) {
821 if (
unlikely(getsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, NULL, &opt_len) < 0)) {
839 if (errno != ENOTSOCK) {
844 if (fstat(fd, &buf) < 0) {
849 if (S_ISDIR(buf.st_mode)) {
870 struct kevent evset[10];
880 memset(&funcs, 0,
sizeof(funcs));
895 ret = kevent(
el->
kq, evset,
count, NULL, 0, NULL);
897 "FD %i was closed without being removed from the KQ: %s",
972 if (ret < 0)
return -1;
1006 struct kevent evset[10];
1024 memcpy(&curr_active, &ef->
active,
sizeof(curr_active));
1025 memcpy(&curr_stored, &ef->
stored,
sizeof(curr_stored));
1030 for (i = 0; updates[i].
op; i++) {
1031 switch (updates[i].op) {
1049 ef, &ef->
active, &curr_active);
1052 memcpy(&ef->
active, &curr_active,
sizeof(curr_active));
1053 memcpy(&ef->
stored, &curr_stored,
sizeof(curr_stored));
1087 struct kevent evset[10];
1104 if (!ef_out || !*ef_out) {
1214 if (ef_out) *ef_out = ef;
1242 if (
unlikely(!read_fn && !write_fn)) {
1405 char const *err_file;
1409 err_file = ev->
file;
1410 err_line = ev->
line;
1412 err_file =
"not-available";
1421 "Event %p, lst_id %i, allocd %s[%u], was not found in the event lst or "
1422 "insertion list when freed: %s", ev, ev->
lst_id, err_file, err_line,
1524 char const *err_file;
1530 err_file = ev->
file;
1531 err_line = ev->
line;
1533 err_file =
"not-available";
1541 "Event %p, lst_id %i, allocd %s[%u], was not found in the event "
1542 "lst or insertion list when freed: %s", ev, ev->
lst_id,
1567 talloc_set_destructor(ev, NULL);
1625 if (likely(ret == 0)) *ev_p = NULL;
1645 struct kevent evset;
1650 EVENT_DEBUG(
"%p - Disabling event for PID %u - %p was freed", ev->
el, (
unsigned int)ev->
pid, ev);
1652 EV_SET(&evset, ev->
pid, EVFILT_PROC, EV_DELETE, NOTE_EXIT, 0, ev);
1654 (void) kevent(ev->
el->
kq, &evset, 1, NULL, 0, NULL);
1662 static inline CC_HINT(always_inline)
1671 el, (
unsigned int)kev->ident, (
unsigned int)kev->data);
1676 fr_assert((kev->fflags & NOTE_EXIT) != 0);
1699 if (callback) callback(
el, pid, (
int) kev->data,
uctx);
1714 EVENT_DEBUG(
"%p - PID %ld exited early, triggered through user event",
el, (
long)ev->
pid);
1746 struct kevent evset;
1756 .callback = callback,
1770 #ifndef NOTE_EXITSTATUS
1771 #define NOTE_EXITSTATUS (0)
1774 EVENT_DEBUG(
"%p - Adding exit waiter for PID %u",
el, (
unsigned int)pid);
1776 EV_SET(&evset, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT |
NOTE_EXITSTATUS, 0, ev);
1788 if (
unlikely(kevent(
el->
kq, &evset, 1, NULL, 0, NULL) < 0)) {
1823 ret = waitid(P_PID, pid, &info, WEXITED | WNOHANG | WNOWAIT);
1826 {
L(
"exited"), CLD_EXITED },
1827 {
L(
"killed"), CLD_KILLED },
1828 {
L(
"dumped"), CLD_DUMPED },
1829 {
L(
"trapped"), CLD_TRAPPED },
1830 {
L(
"stopped"), CLD_STOPPED },
1831 {
L(
"continued"), CLD_CONTINUED }
1835 switch (info.si_code) {
1839 EVENT_DEBUG(
"%p - PID %ld early exit - code %s (%i), status %i",
1841 info.si_code, info.si_status);
1866 "backup user event", (
long) pid);
1876 info.si_code, (
long) pid);
1890 }
else if (ret == 0) {
1908 if (ev_p) *ev_p = ev;
1916 static inline CC_HINT(always_inline)
1919 if (reap->callback) reap->callback(reap->el, pid, status, reap->uctx);
1929 waitpid(pid, &status, WNOHANG);
1931 EVENT_DEBUG(
"%s - Reaper reaped PID %u, status %u - %p", __FUNCTION__, pid, status, reap);
1945 EVENT_DEBUG(
"%s - Removing entry from pid_to_reap %i - %p", __FUNCTION__,
1990 EVENT_DEBUG(
"%s - Adding reaper for PID %u - %p", __FUNCTION__, pid, reap);
2016 struct kevent evset;
2025 EVENT_DEBUG(
"%p - %s - Reaper already called (logic error)... - %p",
2026 el, __FUNCTION__, i);
2036 if (
waitpid(i->pid_ev->pid, &status, WNOHANG) == i->pid_ev->pid) {
2037 EVENT_DEBUG(
"%p - %s - Reaper PID %u already exited - %p",
2038 el, __FUNCTION__, i->pid_ev->pid, i);
2047 EV_SET(&evset, i->pid_ev->pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, i);
2048 if (kevent(
kq, &evset, 1, NULL, 0, NULL) < 0) {
2049 EVENT_DEBUG(
"%p - %s - Failed adding reaper PID %u to tmp event loop - %p",
2050 el, __FUNCTION__, i->pid_ev->pid, i);
2068 EVENT_DEBUG(
"%p - %s - Reaper tmp loop error %s, forcing process reaping",
2074 EVENT_DEBUG(
"%p - %s - Reaper timeout waiting for process exit, forcing process reaping",
2082 EVENT_DEBUG(
"%p - %s - Reaper reaped PID %u, status %u - %p",
2083 el, __FUNCTION__, (
unsigned int)kev.ident, (
unsigned int)kev.data, reap);
2103 EVENT_DEBUG(
"%s - Reaper forcefully reaping PID %u - %p", __FUNCTION__, reap->pid_ev->pid, reap);
2105 if (kill(reap->pid_ev->pid, signal) < 0) {
2115 waitpid(reap->pid_ev->pid, &status, WNOHANG);
2144 struct kevent evset;
2146 EV_SET(&evset, (uintptr_t)ev, EVFILT_USER, EV_DELETE, 0, 0, 0);
2148 if (
unlikely(kevent(ev->el->kq, &evset, 1, NULL, 0, NULL) < 0)) {
2152 ev->is_registered =
false;
2158 static inline CC_HINT(always_inline)
2167 if (kev->ident == 0)
return;
2192 struct kevent evset;
2201 .callback = callback,
2209 EV_SET(&evset, (uintptr_t)ev,
2210 EVFILT_USER, EV_ADD | EV_DISPATCH, (trigger * NOTE_TRIGGER), 0, ev);
2212 if (
unlikely(kevent(
el->
kq, &evset, 1, NULL, 0, NULL) < 0)) {
2220 if (ev_p) *ev_p = ev;
2235 struct kevent evset;
2237 EV_SET(&evset, (uintptr_t)ev, EVFILT_USER, EV_ENABLE, NOTE_TRIGGER, 0, NULL);
2239 if (
unlikely(kevent(
el->
kq, &evset, 1, NULL, 0, NULL) < 0)) {
2344 if ((post->
callback == callback) &&
2400 callback(
el, *when,
uctx);
2417 struct timespec ts_when, *ts_wake;
2420 bool timer_event_ready =
false;
2448 timer_event_ready =
true;
2505 if (errno == EINTR) {
2520 if (!num_fd_events) {
2522 if (wait) timer_event_ready =
true;
2532 return num_fd_events + timer_event_ready;
2535 static inline CC_HINT(always_inline)
2541 fd_cb(
el, ef->fd, flags, ef->uctx);
2612 if (flags & EV_EOF) {
2618 #if defined(__linux__) && defined(SO_GET_FILTER)
2802 talloc_free_children(
el);
2828 #ifdef EVFILT_LIBKQUEUE
2833 void _event_kqueue_log(
char const *
fmt, ...)
2846 static int _event_kqueue_logging(
UNUSED void *
uctx)
2848 struct kevent kev, receipt;
2850 log_conf_kq = kqueue();
2856 EV_SET(&kev, 0, EVFILT_LIBKQUEUE, EV_ADD, NOTE_DEBUG_FUNC, (intptr_t)_event_kqueue_log, NULL);
2857 if (kevent(log_conf_kq, &kev, 1, &receipt, 1, &(
struct timespec){}) != 1) {
2864 EV_SET(&kev, 0, EVFILT_LIBKQUEUE, EV_ADD, NOTE_DEBUG, 1, NULL);
2865 if (kevent(log_conf_kq, &kev, 1, &receipt, 1, &(
struct timespec){}) != 1) {
2876 static int _event_kqueue_logging_stop(
UNUSED void *
uctx)
2878 struct kevent kev, receipt;
2880 EV_SET(&kev, 0, EVFILT_LIBKQUEUE, EV_ADD, NOTE_DEBUG_FUNC, 0, NULL);
2881 (void)kevent(log_conf_kq, &kev, 1, &receipt, 1, &(
struct timespec){});
2910 #ifdef EVFILT_LIBKQUEUE
2911 fr_atexit_global_once_ret(&ret, _event_kqueue_logging, _event_kqueue_logging_stop, NULL);
2953 EV_SET(&kev, 0, EVFILT_USER, EV_ADD | EV_CLEAR, NOTE_FFNOP, 0, NULL);
2954 if (kevent(
el->
kq, &kev, 1, NULL, 0, NULL) < 0) {
2959 #ifdef WITH_EVENT_DEBUG
2984 #ifdef WITH_EVENT_DEBUG
2986 { 1 }, { 10 }, { 100 },
2987 { 1000 }, { 10000 }, { 100000 },
2988 { 1000000 }, { 10000000 }, { 100000000 },
2989 { 1000000000 }, { 10000000000 }, { 100000000000 },
2990 { 1000000000000 }, { 10000000000000 }, { 100000000000000 },
2991 { 1000000000000000 }, { 10000000000000000 }, { 100000000000000000 },
2994 static const char *decade_names[18] = {
2995 "1ns",
"10ns",
"100ns",
2996 "1us",
"10us",
"100us",
2997 "1ms",
"10ms",
"100ms",
2998 "1s",
"10s",
"100s",
2999 "1Ks",
"10Ks",
"100Ks",
3000 "1Ms",
"10Ms",
"100Ms",
3008 } fr_event_counter_t;
3010 static int8_t event_timer_location_cmp(
void const *one,
void const *two)
3012 fr_event_counter_t
const *a = one;
3013 fr_event_counter_t
const *b = two;
3017 return CMP(a->line, b->line);
3032 TALLOC_CTX *tmp_ctx;
3044 locations[i] =
fr_rb_inline_alloc(tmp_ctx, fr_event_counter_t, node, event_timer_location_cmp, NULL);
3045 if (!locations[i])
goto oom;
3059 fr_event_counter_t find = { .file = ev->
file, .line = ev->
line };
3060 fr_event_counter_t *counter;
3064 counter = talloc(locations[i], fr_event_counter_t);
3065 if (!counter)
goto oom;
3066 counter->file = ev->
file;
3067 counter->line = ev->
line;
3080 pthread_mutex_lock(&print_lock);
3090 if (!
array[i])
continue;
3097 EVENT_DEBUG(
" events %5s - %5s : %zu", decade_names[i - 1], decade_names[i],
array[i]);
3103 fr_event_counter_t *counter = talloc_get_type_abort(node, fr_event_counter_t);
3106 counter->count, counter->file, counter->line);
3109 pthread_mutex_unlock(&print_lock);
3130 EVENT_DEBUG(
"%s[%u]: %p time=%" PRId64
" (%c), callback=%p",
3155 static void print_time(
void *ctx)
3163 printf(
"%d.%06d\n", usec /
USEC, usec %
USEC);
3174 if (rand_pool.
randcnt == 256) {
3184 int main(
int argc,
char **argv)
3194 memset(&rand_pool, 0,
sizeof(rand_pool));
3195 rand_pool.
randrsl[1] = time(NULL);
3201 for (i = 1; i < MAX; i++) {
3203 array[i] += event_rand() & 0xffff;
3212 int delay = (when - now) / 1000;
3214 printf(
"\tsleep %d microseconds\n", delay);
static int const char * fmt
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
#define DIAG_UNKNOWN_PRAGMAS
#define L(_str)
Helper for initialising arrays of string literals.
#define typeof_field(_type, _field)
Typeof field.
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
#define NDEBUG_LOCATION_VALS
#define NDEBUG_LOCATION_ARGS
Pass caller information to the function.
fr_dcursor_eval_t void const * uctx
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
int main(int argc, char **argv)
static fr_time_delta_t timeout
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
static bool fr_dlist_entry_in_list(fr_dlist_t const *entry)
Check if a list entry is part of a list.
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
static int fr_dlist_insert_head(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the head of a list.
#define fr_dlist_foreach_safe(_list_head, _type, _iter)
Iterate over the contents of a list allowing for removals.
Head of a doubly linked list.
Entry in a doubly linked list.
#define fr_event_user_insert(_ctx, _ev_p, _el, _trigger, _callback, _uctx)
fr_event_io_func_t io
Read/write functions.
void(* fr_event_timer_cb_t)(fr_event_list_t *el, fr_time_t now, void *uctx)
Called when a timer event fires.
struct fr_event_user_s fr_event_user_t
An opaquer user event handle.
void(* fr_event_fd_cb_t)(fr_event_list_t *el, int fd, int flags, void *uctx)
Called when an IO event occurs on a file descriptor.
@ FR_EVENT_OP_SUSPEND
Temporarily remove the relevant filter from kevent.
@ FR_EVENT_OP_RESUME
Reinsert the filter into kevent.
fr_event_filter_t
The type of filter to install for an FD.
@ FR_EVENT_FILTER_VNODE
Filter for vnode subfilters.
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
size_t offset
Offset of function in func struct.
struct fr_event_pid fr_event_pid_t
An opaque PID status handle.
fr_event_fd_cb_t read
Callback for when data is available.
void(* fr_event_pid_cb_t)(fr_event_list_t *el, pid_t pid, int status, void *uctx)
Called when a child process has exited.
void(* fr_event_error_cb_t)(fr_event_list_t *el, int fd, int flags, int fd_errno, void *uctx)
Called when an IO error event occurs on a file descriptor.
fr_time_t(* fr_event_time_source_t)(void)
Alternative time source, useful for testing.
int(* fr_event_status_cb_t)(fr_time_t now, fr_time_delta_t wake, void *uctx)
Called after each event loop cycle.
fr_event_op_t op
Operation to perform on function/filter.
#define fr_event_timer_at(...)
#define fr_event_timer_in(...)
void(* fr_event_user_cb_t)(fr_event_list_t *el, void *uctx)
Called when a user kevent occurs.
Callbacks for the FR_EVENT_FILTER_IO filter.
Structure describing a modification to a filter's state.
Callbacks for the FR_EVENT_FILTER_VNODE filter.
Union of all filter functions.
void fr_isaac(fr_randctx *ctx)
int fr_event_post_delete(fr_event_list_t *el, fr_event_timer_cb_t callback, void *uctx)
Delete a post-event callback from the event list.
void fr_event_service(fr_event_list_t *el)
Service any outstanding timer or file descriptor events.
fr_dlist_head_t ev_to_add
dlist of events to add
static int _event_timer_free(fr_event_timer_t *ev)
Remove an event from the event loop.
fr_event_list_t * fr_event_list_alloc(TALLOC_CTX *ctx, fr_event_status_cb_t status, void *status_uctx)
Initialise a new event list.
static fr_event_func_map_t filter_maps[]
static int8_t fr_event_timer_cmp(void const *a, void const *b)
Compare two timer events to see which one should occur first.
static int fr_event_fd_type_set(fr_event_fd_t *ef, int fd)
Discover the type of a file descriptor.
fr_dlist_t entry
List of deferred timer events.
fr_event_func_map_entry_t * func_to_ev
Function -> Event maps coalesced, out of order.
fr_event_error_cb_t error
Callback for when an error occurs on the FD.
char const * file
Source file this event was last updated in.
static int8_t fr_event_fd_cmp(void const *one, void const *two)
Compare two file descriptor handles.
fr_event_pid_cb_t callback
callback to run when the child exits
fr_event_funcs_t stored
Stored (set, but inactive) filter functions.
static ssize_t fr_event_build_evset(UNUSED fr_event_list_t *el, struct kevent out_kev[], size_t outlen, fr_event_funcs_t *active, fr_event_fd_t *ef, fr_event_funcs_t const *new, fr_event_funcs_t const *prev)
Build a new evset based on function pointers present.
fr_dlist_head_t pid_to_reap
A list of all orphaned child processes we're waiting to reap.
bool is_registered
Whether this fr_event_fd_t's FD has been registered with kevent.
fr_rb_tree_t * fds
Tree used to track FDs with filters in kqueue.
char const * file
Source file this event was last updated in.
fr_time_t fr_event_list_time(fr_event_list_t *el)
Get the current server time according to the event list.
int fr_event_pre_delete(fr_event_list_t *el, fr_event_status_cb_t callback, void *uctx)
Delete a pre-event callback from the event list.
fr_time_t fr_event_timer_when(fr_event_timer_t const *ev)
Internal timestamp representing when the timer should fire.
void fr_event_list_set_time_func(fr_event_list_t *el, fr_event_time_source_t func)
Override event list time source.
fr_event_list_t * el
Event list this event belongs to.
static void event_list_reap_run_callback(fr_event_pid_reap_t *reap, pid_t pid, int status)
Saves some boilerplate...
int line
Line this event was last updated on.
static int _event_fd_delete(fr_event_fd_t *ef)
Remove a file descriptor from the event loop and rbtree but don't explicitly free it.
int _fr_event_pid_reap(NDEBUG_LOCATION_ARGS fr_event_list_t *el, pid_t pid, fr_event_pid_cb_t callback, void *uctx)
Asynchronously wait for a PID to exit, then reap it.
fr_dlist_head_t pre_callbacks
callbacks when we may be idle...
void * uctx
Context pointer to pass to each file descriptor callback.
fr_event_status_cb_t callback
The callback to call.
fr_event_timer_cb_t callback
The callback to call.
static void _fr_event_pid_reap_cb(UNUSED fr_event_list_t *el, pid_t pid, int status, void *uctx)
Does the actual reaping of PIDs.
int line
Line this event was last updated on.
int line
Line this event was last updated on.
static size_t kevent_filter_table_len
fr_dlist_head_t post_callbacks
post-processing callbacks
int num_fd_events
Number of events in this event list.
fr_event_timer_cb_t callback
Callback to execute when the timer fires.
int _fr_event_user_insert(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx, fr_event_list_t *el, fr_event_user_t **ev_p, bool trigger, fr_event_user_cb_t callback, void *uctx)
Add a user callback to the event list.
fr_event_fd_type_t type
Type of events we're interested in.
static fr_table_num_sorted_t const fr_event_fd_type_table[]
static size_t fr_event_fd_type_table_len
int _fr_event_timer_in(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx, fr_event_list_t *el, fr_event_timer_t const **ev_p, fr_time_delta_t delta, fr_event_timer_cb_t callback, void const *uctx)
Insert a timer event into an event list.
uint16_t flags
Flags to use for inserting event.
waitpid(reap->pid_ev->pid, &status, 0)
fr_event_pid_cb_t callback
callback to run when the child exits
static int _event_list_free(fr_event_list_t *el)
Cleanup an event list.
bool coalesce
Coalesce this map with the next.
fr_dlist_t entry
Entry in free list.
int fr_event_corral(fr_event_list_t *el, fr_time_t now, bool wait)
Gather outstanding timer and file descriptor events.
static int _event_free_indexes(UNUSED void *uctx)
Free any memory we allocated for indexes.
fr_event_fd_cb_t fr_event_fd_cb(fr_event_fd_t *ef, int kq_filter, int kq_fflags)
Returns the appropriate callback function for a given event.
void * uctx
Context for the callback.
bool is_registered
Whether this user event has been registered with the event loop.
void const * uctx
Context pointer to pass to the callback.
int type
Type this filter applies to.
uint64_t fr_event_list_num_timers(fr_event_list_t *el)
Return the number of timer events currently scheduled.
fr_event_func_map_t const * map
Function map between fr_event_funcs_t and kevent filters.
void * uctx
Context for the callback.
int _fr_event_pid_wait(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx, fr_event_list_t *el, fr_event_pid_t const **ev_p, pid_t pid, fr_event_pid_cb_t callback, void *uctx)
Insert a PID event into an event list.
char const * name
Name of the event.
int fr_event_user_trigger(fr_event_list_t *el, fr_event_user_t *ev)
Trigger a user event.
char const * file
Source file this event was last updated in.
void * fr_event_fd_uctx(fr_event_fd_t *ef)
Returns the uctx associated with an fr_event_fd_t handle.
int line
Line this event was last updated on.
uintptr_t armour
protection flag from being deleted.
int kq
instance associated with this event list.
fr_event_user_cb_t callback
The callback to call.
int fr_event_fd_unarmour(fr_event_list_t *el, int fd, fr_event_filter_t filter, uintptr_t armour)
Unarmour an FD.
int sock_type
The type of socket SOCK_STREAM, SOCK_RAW etc...
uint64_t fr_event_list_num_fds(fr_event_list_t *el)
Return the number of file descriptors is_registered with this event loop.
void * uctx
Context pointer to pass to each file descriptor callback.
fr_event_func_idx_type_t idx_type
What type of index we use for event to function mapping.
fr_event_timer_t const ** parent
A pointer to the parent structure containing the timer event.
#define GET_FUNC(_ef, _offset)
static fr_event_fd_cb_t event_fd_func(fr_event_fd_t *ef, int *filter, int *fflags)
Figure out which function to call given a kevent.
static int _fr_event_reap_free(fr_event_pid_reap_t *reap)
pid_t pid
child to wait for
bool in_handler
Deletes should be deferred until after the handlers complete.
static void event_pid_eval(fr_event_list_t *el, struct kevent *kev)
Evaluate a EVFILT_PROC event.
int fr_event_list_kq(fr_event_list_t *el)
Return the kq associated with an event list.
fr_time_t now
The last time the event list was serviced.
void * uctx
Context for the callback.
bool is_registered
Whether this user event has been registered with the event loop.
int fr_event_timer_delete(fr_event_timer_t const **ev_p)
Delete a timer event from the event list.
int fr_event_post_insert(fr_event_list_t *el, fr_event_timer_cb_t callback, void *uctx)
Add a post-event callback to the event list.
fr_event_list_t * el
Event list this event belongs to.
struct fr_event_pid::@129 early_exit
Fields that are only used if we're being triggered by a user event.
bool fr_event_list_empty(fr_event_list_t *el)
Return whether the event loop has any active events.
static int _event_build_indexes(UNUSED void *uctx)
fr_lst_index_t lst_id
Where to store opaque lst data.
unsigned int fr_event_list_reap_signal(fr_event_list_t *el, fr_time_delta_t timeout, int signal)
Send a signal to all the processes we have in our reap list, and reap them.
int16_t filter
Filter to apply.
static void event_fd_func_index_build(fr_event_func_map_t *map)
static void fr_event_fd_noop(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, UNUSED void *uctx)
Placeholder callback to avoid branches in service loop.
fr_dlist_t entry
If the fr_event_pid is in the detached, reap state, it's inserted into a list associated with the eve...
bool fr_event_loop_exiting(fr_event_list_t *el)
Check to see whether the event loop is in the process of exiting.
fr_dlist_t entry
Linked list of callback.
int _fr_event_filter_update(NDEBUG_LOCATION_ARGS fr_event_list_t *el, int fd, fr_event_filter_t filter, fr_event_update_t const updates[])
Suspend/resume a subset of filters.
char const * file
Source file this event was last updated in.
int _fr_event_fd_move(NDEBUG_LOCATION_ARGS fr_event_list_t *dst, fr_event_list_t *src, int fd, fr_event_filter_t filter)
Move a file descriptor event from one event list to another.
fr_event_func_map_entry_t ** ev_to_func
Function -> Event maps in index order.
int _fr_event_fd_insert(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx, fr_event_fd_t **ef_out, fr_event_list_t *el, int fd, fr_event_fd_cb_t read_fn, fr_event_fd_cb_t write_fn, fr_event_error_cb_t error, void *uctx)
Associate I/O callbacks with a file descriptor.
@ FR_EVENT_FD_FILE
is a file.
@ FR_EVENT_FD_DIRECTORY
is a directory.
@ FR_EVENT_FD_SOCKET
is a socket.
fr_event_pid_t const * pid_ev
pid_ev this reaper is bound to.
fr_event_funcs_t active
Active filter functions.
int fr_event_pre_insert(fr_event_list_t *el, fr_event_status_cb_t callback, void *uctx)
Add a pre-event callback to the event list.
int fr_event_timer_run(fr_event_list_t *el, fr_time_t *when)
Run a single scheduled timer event.
static void _fr_event_pid_early_exit(fr_event_list_t *el, void *uctx)
Called on the next loop through the event loop when inserting an EVFILT_PROC event fails.
static void event_user_eval(fr_event_list_t *el, struct kevent *kev)
fr_event_list_t * el
Event list this event belongs to.
static fr_table_num_sorted_t const kevent_filter_table[]
TALLOC_CTX * linked_ctx
talloc ctx this event was bound to.
static void event_callback(fr_event_list_t *el, fr_event_fd_t *ef, int *filter, int flags, int *fflags)
void fr_event_loop_exit(fr_event_list_t *el, int code)
Signal an event loop exit with the specified code.
void * uctx
Context pointer to pass to each file descriptor callback.
static int _event_pid_free(fr_event_pid_t *ev)
Remove PID wait event from kevent if the fr_event_pid_t is freed.
fr_event_list_t * el
Event list this event belongs to.
int fd
File descriptor we're listening for events on.
size_t offset
Offset of function pointer in structure.
int will_exit
Will exit on next call to fr_event_corral.
int fr_event_fd_delete(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Remove a file descriptor from the event loop.
fr_dlist_t entry
Linked list of callback.
int fr_event_loop(fr_event_list_t *el)
Run an event loop.
int _fr_event_timer_at(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx, fr_event_list_t *el, fr_event_timer_t const **ev_p, fr_time_t when, fr_event_timer_cb_t callback, void const *uctx)
Insert a timer event into an event list.
int exit
If non-zero event loop will prevent the addition of new events, and will return immediately from the ...
fr_rb_node_t node
Entry in the tree of file descriptor handles.
fr_event_time_source_t time
Where our time comes from.
fr_dlist_head_t fd_to_free
File descriptor events pending deletion.
bool dispatch
Whether the event list is currently dispatching events.
struct kevent events[FR_EV_BATCH_FDS]
int _fr_event_filter_insert(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx, fr_event_fd_t **ef_out, fr_event_list_t *el, int fd, fr_event_filter_t filter, void *funcs, fr_event_error_cb_t error, void *uctx)
Insert a filter for the specified fd.
TALLOC_CTX * linked_ctx
talloc ctx this event was bound to.
fr_event_fd_t * fr_event_fd_handle(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Get the opaque event handle from a file descriptor.
fr_event_pid_t const ** parent
fr_lst_t * times
of timer events to be executed.
static int _event_user_delete(fr_event_user_t *ev)
Memory will not be freed if we fail to remove the event from the kqueue.
fr_time_t when
When this timer should fire.
@ FR_EVENT_FUNC_IDX_FILTER
Sign flip is performed i.e. -1 = 0The filter is used / as the index in the ev to func index.
@ FR_EVENT_FUNC_IDX_FFLAGS
The bit position of the flags in FFLAGS is used to provide the index.
int fr_event_fd_armour(fr_event_list_t *el, int fd, fr_event_filter_t filter, uintptr_t armour)
Armour an FD.
fr_event_list_t * el
Event list containing this timer.
uint32_t fflags
fflags to pass to filter.
A file descriptor/filter event.
Specifies a mapping between a function pointer in a structure and its respective event.
Stores all information relating to an event list.
Hold additional information for automatically reaped PIDs.
Callbacks to perform after all timers and FDs have been checked.
Callbacks to perform when the event handler is about to check the events.
Callbacks for kevent() user events.
void fr_vlog(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt, va_list ap)
Send a server log message to its destination.
@ L_DBG_LVL_3
3rd highest priority debug messages (-xxx | -Xx).
@ L_DBG
Only displayed when debugging is enabled.
int fr_lst_extract(fr_lst_t *lst, void *data)
Remove an element from an LST.
void * fr_lst_iter_next(fr_lst_t *lst, fr_lst_iter_t *iter)
Get the next entry in an LST.
int fr_lst_insert(fr_lst_t *lst, void *data)
unsigned int fr_lst_num_elements(fr_lst_t *lst)
void * fr_lst_peek(fr_lst_t *lst)
void * fr_lst_iter_init(fr_lst_t *lst, fr_lst_iter_t *iter)
Iterate over entries in LST.
#define fr_lst_talloc_alloc(_ctx, _cmp, _talloc_type, _field, _init)
Creates an LST that verifies elements are of a specific talloc type.
fr_lst_index_t fr_lst_iter_t
unsigned int fr_lst_index_t
static uint8_t fr_high_bit_pos(uint64_t num)
Find the highest order high bit in an unsigned 64 bit integer.
static size_t array[MY_ARRAY_SIZE]
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
#define fr_rb_inline_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black tree.
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Iterator structure for in-order traversal of an rbtree.
The main red black tree structure.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
An element in a lexicographically sorted array of name to num mappings.
int talloc_link_ctx(TALLOC_CTX *parent, TALLOC_CTX *child)
Link two different parent and child contexts, so the child is freed before the parent.
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
#define fr_time_delta_to_timespec(_delta)
Convert a delta to a timespec.
static int8_t fr_time_delta_cmp(fr_time_delta_t a, fr_time_delta_t b)
Compare two fr_time_delta_t values.
static int64_t fr_time_unwrap(fr_time_t time)
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
#define fr_time_delta_wrap(_time)
#define fr_time_wrap(_time)
#define fr_time_lteq(_a, _b)
#define fr_time_delta_ispos(_a)
static int64_t fr_time_to_usec(fr_time_t when)
Convert an fr_time_t (internal time) to number of usec since the unix epoch (wallclock time)
#define fr_time_add(_a, _b)
Add a time/time delta together.
#define fr_time_gt(_a, _b)
#define fr_time_sub(_a, _b)
Subtract one time from another.
static int8_t fr_time_cmp(fr_time_t a, fr_time_t b)
Compare two fr_time_t values.
A time delta, a difference in time measured in nanoseconds.
static fr_event_list_t * el
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
char const * fr_strerror(void)
Get the last library error.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
#define fr_strerror_const_push(_msg)
#define fr_strerror_const(_msg)
int format(printf, 5, 0))
static size_t char ** out