30 RCSID(
"$Id: 085eba311957ede61b99cd5f829ae90d9596c731 $")
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;
492 int fflags = entry->
fflags;
501 fflags &= ~(1 << pos);
526 #define GET_FUNC(_ef, _offset) *((fr_event_fd_cb_t const *)((uint8_t const *)&(_ef)->active + _offset))
537 if (!*filter)
return NULL;
547 int our_fflags = *fflags;
550 if (!pos)
return NULL;
553 *fflags = our_fflags & ~(1 << pos);
672 #ifndef WITH_EVENT_DEBUG
680 struct kevent *
out = out_kev, *end =
out + outlen;
682 struct kevent add[10], *add_p = add;
685 EVENT_DEBUG(
"%p - Building new evset for FD %i (new %p, prev %p)",
el, ef->
fd,
new, prev);
692 bool has_current_func =
false;
693 bool has_prev_func =
false;
708 prev_fflags |= map->
fflags;
709 has_prev_func =
true;
717 current_fflags |= map->
fflags;
718 has_current_func =
true;
729 map->
type,
"<INVALID>"));
748 if (!(map + 1)->coalesce)
break;
760 if (has_current_func &&
761 (!has_prev_func || (current_fflags != prev_fflags))) {
766 EVENT_DEBUG(
"\tEV_SET EV_ADD filter %s (%i), flags %i, fflags %i",
769 EV_SET(add_p++, ef->
fd, map->
filter, map->
flags, current_fflags, 0, ef);
774 }
else if (!has_current_func && has_prev_func) {
775 EVENT_DEBUG(
"\tEV_SET EV_DELETE filter %s (%i), flags %i, fflags %i",
777 map->
filter, EV_DELETE, 0);
778 EV_SET(
out++, ef->
fd, map->
filter, EV_DELETE, 0, 0, ef);
788 for (i = 0; i < (
size_t)(add_p - add); i++) memcpy(
out++, &add[i],
sizeof(*
out));
790 return out - out_kev;
806 socklen_t opt_len =
sizeof(ef->
sock_type);
811 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &ef->
sock_type, &opt_len) == 0) {
814 if (
unlikely(getsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, NULL, &opt_len) < 0)) {
832 if (errno != ENOTSOCK) {
837 if (fstat(fd, &buf) < 0) {
842 if (S_ISDIR(buf.st_mode)) {
863 struct kevent evset[10];
873 memset(&funcs, 0,
sizeof(funcs));
888 ret = kevent(
el->
kq, evset,
count, NULL, 0, NULL);
890 "FD %i was closed without being removed from the KQ: %s",
965 if (ret < 0)
return -1;
999 struct kevent evset[10];
1017 memcpy(&curr_active, &ef->
active,
sizeof(curr_active));
1018 memcpy(&curr_stored, &ef->
stored,
sizeof(curr_stored));
1023 for (i = 0; updates[i].
op; i++) {
1024 switch (updates[i].op) {
1042 ef, &ef->
active, &curr_active);
1045 memcpy(&ef->
active, &curr_active,
sizeof(curr_active));
1046 memcpy(&ef->
stored, &curr_stored,
sizeof(curr_stored));
1080 struct kevent evset[10];
1097 if (!ef_out || !*ef_out) {
1207 if (ef_out) *ef_out = ef;
1235 if (
unlikely(!read_fn && !write_fn)) {
1398 char const *err_file;
1402 err_file = ev->
file;
1403 err_line = ev->
line;
1405 err_file =
"not-available";
1414 "Event %p, lst_id %i, allocd %s[%u], was not found in the event lst or "
1415 "insertion list when freed: %s", ev, ev->
lst_id, err_file, err_line,
1517 char const *err_file;
1523 err_file = ev->
file;
1524 err_line = ev->
line;
1526 err_file =
"not-available";
1534 "Event %p, lst_id %i, allocd %s[%u], was not found in the event "
1535 "lst or insertion list when freed: %s", ev, ev->
lst_id,
1560 talloc_set_destructor(ev, NULL);
1618 if (likely(ret == 0)) *ev_p = NULL;
1638 struct kevent evset;
1643 EVENT_DEBUG(
"%p - Disabling event for PID %u - %p was freed", ev->
el, (
unsigned int)ev->
pid, ev);
1645 EV_SET(&evset, ev->
pid, EVFILT_PROC, EV_DELETE, NOTE_EXIT, 0, ev);
1647 (void) kevent(ev->
el->
kq, &evset, 1, NULL, 0, NULL);
1655 static inline CC_HINT(always_inline)
1664 el, (
unsigned int)kev->ident, (
unsigned int)kev->data);
1669 fr_assert((kev->fflags & NOTE_EXIT) != 0);
1692 if (callback) callback(
el, pid, (
int) kev->data, uctx);
1707 EVENT_DEBUG(
"%p - PID %ld exited early, triggered through user event",
el, (
long)ev->
pid);
1739 struct kevent evset;
1749 .callback = callback,
1763 #ifndef NOTE_EXITSTATUS
1764 #define NOTE_EXITSTATUS (0)
1767 EVENT_DEBUG(
"%p - Adding exit waiter for PID %u",
el, (
unsigned int)pid);
1769 EV_SET(&evset, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT |
NOTE_EXITSTATUS, 0, ev);
1781 if (
unlikely(kevent(
el->
kq, &evset, 1, NULL, 0, NULL) < 0)) {
1816 ret = waitid(P_PID, pid, &info, WEXITED | WNOHANG | WNOWAIT);
1819 {
L(
"exited"), CLD_EXITED },
1820 {
L(
"killed"), CLD_KILLED },
1821 {
L(
"dumped"), CLD_DUMPED },
1822 {
L(
"trapped"), CLD_TRAPPED },
1823 {
L(
"stopped"), CLD_STOPPED },
1824 {
L(
"continued"), CLD_CONTINUED }
1828 switch (info.si_code) {
1832 EVENT_DEBUG(
"%p - PID %ld early exit - code %s (%i), status %i",
1834 info.si_code, info.si_status);
1859 "backup user event", (
long) pid);
1869 info.si_code, (
long) pid);
1883 }
else if (ret == 0) {
1901 if (ev_p) *ev_p = ev;
1909 static inline CC_HINT(always_inline)
1912 if (reap->callback) reap->callback(reap->el, pid, status, reap->uctx);
1922 waitpid(pid, &status, WNOHANG);
1924 EVENT_DEBUG(
"%s - Reaper reaped PID %u, status %u - %p", __FUNCTION__, pid, status, reap);
1938 EVENT_DEBUG(
"%s - Removing entry from pid_to_reap %i - %p", __FUNCTION__,
1983 EVENT_DEBUG(
"%s - Adding reaper for PID %u - %p", __FUNCTION__, pid, reap);
2009 struct kevent evset;
2018 EVENT_DEBUG(
"%p - %s - Reaper already called (logic error)... - %p",
2019 el, __FUNCTION__, i);
2029 if (
waitpid(i->pid_ev->pid, &status, WNOHANG) == i->pid_ev->pid) {
2030 EVENT_DEBUG(
"%p - %s - Reaper PID %u already exited - %p",
2031 el, __FUNCTION__, i->pid_ev->pid, i);
2040 EV_SET(&evset, i->pid_ev->pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, i);
2041 if (kevent(
kq, &evset, 1, NULL, 0, NULL) < 0) {
2042 EVENT_DEBUG(
"%p - %s - Failed adding reaper PID %u to tmp event loop - %p",
2043 el, __FUNCTION__, i->pid_ev->pid, i);
2061 EVENT_DEBUG(
"%p - %s - Reaper tmp loop error %s, forcing process reaping",
2067 EVENT_DEBUG(
"%p - %s - Reaper timeout waiting for process exit, forcing process reaping",
2075 EVENT_DEBUG(
"%p - %s - Reaper reaped PID %u, status %u - %p",
2076 el, __FUNCTION__, (
unsigned int)kev.ident, (
unsigned int)kev.data, reap);
2096 EVENT_DEBUG(
"%s - Reaper forcefully reaping PID %u - %p", __FUNCTION__, reap->pid_ev->pid, reap);
2098 if (kill(reap->pid_ev->pid, signal) < 0) {
2108 waitpid(reap->pid_ev->pid, &status, WNOHANG);
2137 struct kevent evset;
2139 EV_SET(&evset, (uintptr_t)ev, EVFILT_USER, EV_DELETE, 0, 0, 0);
2141 if (
unlikely(kevent(ev->el->kq, &evset, 1, NULL, 0, NULL) < 0)) {
2145 ev->is_registered =
false;
2151 static inline CC_HINT(always_inline)
2160 if (kev->ident == 0)
return;
2185 struct kevent evset;
2194 .callback = callback,
2202 EV_SET(&evset, (uintptr_t)ev,
2203 EVFILT_USER, EV_ADD | EV_DISPATCH, (trigger * NOTE_TRIGGER), 0, ev);
2205 if (
unlikely(kevent(
el->
kq, &evset, 1, NULL, 0, NULL) < 0)) {
2213 if (ev_p) *ev_p = ev;
2228 struct kevent evset;
2230 EV_SET(&evset, (uintptr_t)ev, EVFILT_USER, EV_ENABLE, NOTE_TRIGGER, 0, NULL);
2232 if (
unlikely(kevent(
el->
kq, &evset, 1, NULL, 0, NULL) < 0)) {
2284 (pre->
uctx == uctx)) {
2337 if ((post->
callback == callback) &&
2338 (post->
uctx == uctx)) {
2384 memcpy(&uctx, &ev->
uctx,
sizeof(uctx));
2393 callback(
el, *when, uctx);
2410 struct timespec ts_when, *ts_wake;
2413 bool timer_event_ready =
false;
2441 timer_event_ready =
true;
2498 if (errno == EINTR) {
2513 if (!num_fd_events) {
2515 if (wait) timer_event_ready =
true;
2525 return num_fd_events + timer_event_ready;
2528 static inline CC_HINT(always_inline)
2534 fd_cb(
el, ef->fd, flags, ef->uctx);
2605 if (flags & EV_EOF) {
2611 #if defined(__linux__) && defined(SO_GET_FILTER)
2795 talloc_free_children(
el);
2821 #ifdef EVFILT_LIBKQUEUE
2826 void _event_kqueue_log(
char const *
fmt, ...)
2839 static int _event_kqueue_logging(
UNUSED void *uctx)
2841 struct kevent kev, receipt;
2843 log_conf_kq = kqueue();
2849 EV_SET(&kev, 0, EVFILT_LIBKQUEUE, EV_ADD, NOTE_DEBUG_FUNC, (intptr_t)_event_kqueue_log, NULL);
2850 if (kevent(log_conf_kq, &kev, 1, &receipt, 1, &(
struct timespec){}) != 1) {
2857 EV_SET(&kev, 0, EVFILT_LIBKQUEUE, EV_ADD, NOTE_DEBUG, 1, NULL);
2858 if (kevent(log_conf_kq, &kev, 1, &receipt, 1, &(
struct timespec){}) != 1) {
2869 static int _event_kqueue_logging_stop(
UNUSED void *uctx)
2871 struct kevent kev, receipt;
2873 EV_SET(&kev, 0, EVFILT_LIBKQUEUE, EV_ADD, NOTE_DEBUG_FUNC, 0, NULL);
2874 (void)kevent(log_conf_kq, &kev, 1, &receipt, 1, &(
struct timespec){});
2903 #ifdef EVFILT_LIBKQUEUE
2904 fr_atexit_global_once_ret(&ret, _event_kqueue_logging, _event_kqueue_logging_stop, NULL);
2946 EV_SET(&kev, 0, EVFILT_USER, EV_ADD | EV_CLEAR, NOTE_FFNOP, 0, NULL);
2947 if (kevent(
el->
kq, &kev, 1, NULL, 0, NULL) < 0) {
2952 #ifdef WITH_EVENT_DEBUG
2977 #ifdef WITH_EVENT_DEBUG
2979 { 1 }, { 10 }, { 100 },
2980 { 1000 }, { 10000 }, { 100000 },
2981 { 1000000 }, { 10000000 }, { 100000000 },
2982 { 1000000000 }, { 10000000000 }, { 100000000000 },
2983 { 1000000000000 }, { 10000000000000 }, { 100000000000000 },
2984 { 1000000000000000 }, { 10000000000000000 }, { 100000000000000000 },
2987 static const char *decade_names[18] = {
2988 "1ns",
"10ns",
"100ns",
2989 "1us",
"10us",
"100us",
2990 "1ms",
"10ms",
"100ms",
2991 "1s",
"10s",
"100s",
2992 "1Ks",
"10Ks",
"100Ks",
2993 "1Ms",
"10Ms",
"100Ms",
3001 } fr_event_counter_t;
3003 static int8_t event_timer_location_cmp(
void const *one,
void const *two)
3005 fr_event_counter_t
const *a = one;
3006 fr_event_counter_t
const *b = two;
3010 return CMP(a->line, b->line);
3025 TALLOC_CTX *tmp_ctx;
3037 locations[i] =
fr_rb_inline_alloc(tmp_ctx, fr_event_counter_t, node, event_timer_location_cmp, NULL);
3038 if (!locations[i])
goto oom;
3052 fr_event_counter_t find = { .file = ev->
file, .line = ev->
line };
3053 fr_event_counter_t *counter;
3057 counter = talloc(locations[i], fr_event_counter_t);
3058 if (!counter)
goto oom;
3059 counter->file = ev->
file;
3060 counter->line = ev->
line;
3073 pthread_mutex_lock(&print_lock);
3083 if (!
array[i])
continue;
3090 EVENT_DEBUG(
" events %5s - %5s : %zu", decade_names[i - 1], decade_names[i],
array[i]);
3096 fr_event_counter_t *counter = talloc_get_type_abort(node, fr_event_counter_t);
3099 counter->count, counter->file, counter->line);
3102 pthread_mutex_unlock(&print_lock);
3123 EVENT_DEBUG(
"%s[%u]: %p time=%" PRId64
" (%c), callback=%p",
3148 static void print_time(
void *ctx)
3156 printf(
"%d.%06d\n", usec /
USEC, usec %
USEC);
3167 if (rand_pool.
randcnt == 256) {
3177 int main(
int argc,
char **argv)
3187 memset(&rand_pool, 0,
sizeof(rand_pool));
3188 rand_pool.
randrsl[1] = time(NULL);
3194 for (i = 1; i < MAX; i++) {
3196 array[i] += event_rand() & 0xffff;
3205 int delay = (when - now) / 1000;
3207 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 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.
#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.
struct fr_event_pid::@120 early_exit
Fields that are only used if we're being triggered by a user event.
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.
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]
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
#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.
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