30RCSID(
"$Id: e4a2c3bb589a2bcda1b3b19ff8679cff574e1eb3 $")
32#define _EVENT_LIST_PRIVATE 1
35#include <freeradius-devel/util/dlist.h>
36#include <freeradius-devel/util/event.h>
37#include <freeradius-devel/util/timer.h>
38#include <freeradius-devel/util/log.h>
39#include <freeradius-devel/util/rb.h>
40#include <freeradius-devel/util/strerror.h>
41#include <freeradius-devel/util/syserror.h>
42#include <freeradius-devel/util/table.h>
43#include <freeradius-devel/util/token.h>
44#include <freeradius-devel/util/atexit.h>
60#define FR_EV_BATCH_FDS (256)
63#define fr_time() static_assert(0, "Use el->time for event loop timing")
66#if !defined(SO_GET_FILTER) && defined(SO_ATTACH_FILTER)
67# define SO_GET_FILTER SO_ATTACH_FILTER
72 {
L(
"EVFILT_AIO"), EVFILT_AIO },
75 {
L(
"EVFILT_EXCEPT"), EVFILT_EXCEPT },
78 {
L(
"EVFILT_MACHPORT"), EVFILT_MACHPORT },
80 {
L(
"EVFILT_PROC"), EVFILT_PROC },
81 {
L(
"EVFILT_READ"), EVFILT_READ },
82 {
L(
"EVFILT_SIGNAL"), EVFILT_SIGNAL },
83 {
L(
"EVFILT_TIMER"), EVFILT_TIMER },
84 {
L(
"EVFILT_VNODE"), EVFILT_VNODE },
85 {
L(
"EVFILT_WRITE"), EVFILT_WRITE }
89#ifdef EVFILT_LIBKQUEUE
90static int log_conf_kq;
114# define FR_EVENT_FD_PCAP 0
148 .filter = EVFILT_READ,
149 .flags = EV_ADD | EV_ENABLE,
160 .filter = EVFILT_WRITE,
161 .flags = EV_ADD | EV_ENABLE,
174 .filter = EVFILT_VNODE,
175 .flags = EV_ADD | EV_ENABLE | EV_CLEAR,
176 .fflags = NOTE_DELETE,
183 .filter = EVFILT_VNODE,
184 .flags = EV_ADD | EV_ENABLE | EV_CLEAR,
185 .fflags = NOTE_WRITE,
192 .filter = EVFILT_VNODE,
193 .flags = EV_ADD | EV_ENABLE | EV_CLEAR,
194 .fflags = NOTE_EXTEND,
201 .filter = EVFILT_VNODE,
202 .flags = EV_ADD | EV_ENABLE | EV_CLEAR,
203 .fflags = NOTE_ATTRIB,
210 .filter = EVFILT_VNODE,
211 .flags = EV_ADD | EV_ENABLE | EV_CLEAR,
219 .filter = EVFILT_VNODE,
220 .flags = EV_ADD | EV_ENABLE | EV_CLEAR,
221 .fflags = NOTE_RENAME,
229 .filter = EVFILT_VNODE,
230 .flags = EV_ADD | EV_ENABLE | EV_CLEAR,
231 .fflags = NOTE_REVOKE,
240 .filter = EVFILT_VNODE,
241 .flags = EV_ADD | EV_ENABLE | EV_CLEAR,
242 .fflags = NOTE_FUNLOCK,
408#ifdef WITH_EVENT_DEBUG
451 if (pos > high) high = pos;
474 fflags &= ~(1 << pos);
499#define GET_FUNC(_ef, _offset) *((fr_event_fd_cb_t const *)((uint8_t const *)&(_ef)->active + _offset))
510 if (!*filter)
return NULL;
520 int our_fflags = *fflags;
523 if (!pos)
return NULL;
526 *fflags = our_fflags & ~(1 << pos);
625#ifndef WITH_EVENT_DEBUG
633 struct kevent *
out = out_kev, *end =
out + outlen;
635 struct kevent add[10], *add_p = add;
638 EVENT_DEBUG(
"%p - Building new evset for FD %i (new %p, prev %p)",
el, ef->
fd,
new, prev);
645 bool has_current_func =
false;
646 bool has_prev_func =
false;
661 prev_fflags |= map->
fflags;
662 has_prev_func =
true;
670 current_fflags |= map->
fflags;
671 has_current_func =
true;
682 map->
type,
"<INVALID>"));
701 if (!(map + 1)->coalesce)
break;
713 if (has_current_func &&
714 (!has_prev_func || (current_fflags != prev_fflags))) {
719 EVENT_DEBUG(
"\tEV_SET EV_ADD filter %s (%i), flags %i, fflags %i",
722 EV_SET(add_p++, ef->
fd, map->
filter, map->
flags, current_fflags, 0, ef);
727 }
else if (!has_current_func && has_prev_func) {
728 EVENT_DEBUG(
"\tEV_SET EV_DELETE filter %s (%i), flags %i, fflags %i",
730 map->
filter, EV_DELETE, 0);
731 EV_SET(
out++, ef->
fd, map->
filter, EV_DELETE, 0, 0, ef);
741 for (i = 0; i < (
size_t)(add_p - add); i++) memcpy(
out++, &add[i],
sizeof(*
out));
743 return out - out_kev;
759 socklen_t opt_len =
sizeof(ef->
sock_type);
764 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &ef->
sock_type, &opt_len) == 0) {
767 if (
unlikely(getsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, NULL, &opt_len) < 0)) {
785 if (errno != ENOTSOCK) {
790 if (fstat(fd, &buf) < 0) {
795 if (S_ISDIR(buf.st_mode)) {
816 struct kevent evset[10];
826 memset(&funcs, 0,
sizeof(funcs));
841 ret = kevent(
el->
kq, evset,
count, NULL, 0, NULL);
843 "FD %i was closed without being removed from the KQ: %s",
918 if (ret < 0)
return -1;
952 struct kevent evset[10];
970 memcpy(&curr_active, &ef->
active,
sizeof(curr_active));
971 memcpy(&curr_stored, &ef->
stored,
sizeof(curr_stored));
976 for (i = 0; updates[i].
op; i++) {
977 switch (updates[i].op) {
995 ef, &ef->
active, &curr_active);
998 memcpy(&ef->
active, &curr_active,
sizeof(curr_active));
999 memcpy(&ef->
stored, &curr_stored,
sizeof(curr_stored));
1033 struct kevent evset[10];
1050 if (!ef_out || !*ef_out) {
1160 if (ef_out) *ef_out = ef;
1188 if (
unlikely(!read_fn && !write_fn)) {
1342 struct kevent evset;
1347 EVENT_DEBUG(
"%p - Disabling event for PID %u - %p was freed", ev->
el, (
unsigned int)ev->
pid, ev);
1349 EV_SET(&evset, ev->
pid, EVFILT_PROC, EV_DELETE, NOTE_EXIT, 0, ev);
1351 (void) kevent(ev->
el->
kq, &evset, 1, NULL, 0, NULL);
1360static inline CC_HINT(always_inline)
1369 el, (
unsigned int)kev->ident, (
unsigned int)kev->data);
1374 fr_assert((kev->fflags & NOTE_EXIT) != 0);
1397 if (callback) callback(
el, pid, (
int) kev->data, uctx);
1412 EVENT_DEBUG(
"%p - PID %ld exited early, triggered through user event",
el, (
long)ev->
pid);
1444 struct kevent evset;
1454 .callback = callback,
1468#ifndef NOTE_EXITSTATUS
1469#define NOTE_EXITSTATUS (0)
1472 EVENT_DEBUG(
"%p - Adding exit waiter for PID %u",
el, (
unsigned int)pid);
1474 EV_SET(&evset, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT |
NOTE_EXITSTATUS, 0, ev);
1486 if (
unlikely(kevent(
el->
kq, &evset, 1, NULL, 0, NULL) < 0)) {
1521 ret = waitid(P_PID, pid, &info, WEXITED | WNOHANG | WNOWAIT);
1524 {
L(
"exited"), CLD_EXITED },
1525 {
L(
"killed"), CLD_KILLED },
1526 {
L(
"dumped"), CLD_DUMPED },
1527 {
L(
"trapped"), CLD_TRAPPED },
1528 {
L(
"stopped"), CLD_STOPPED },
1529 {
L(
"continued"), CLD_CONTINUED }
1533 switch (info.si_code) {
1537 EVENT_DEBUG(
"%p - PID %ld early exit - code %s (%d), status %d",
1539 info.si_code, info.si_status);
1564 "backup user event", (
long) pid);
1574 info.si_code, (
long) pid);
1588 }
else if (ret == 0) {
1606 if (ev_p) *ev_p = ev;
1614static inline CC_HINT(always_inline)
1617 if (reap->callback) reap->
callback(reap->el, pid, status, reap->uctx);
1627 waitpid(pid, &status, WNOHANG);
1629 EVENT_DEBUG(
"%s - Reaper reaped PID %u, status %u - %p", __FUNCTION__, pid, status, reap);
1643 EVENT_DEBUG(
"%s - Removing entry from pid_to_reap %i - %p", __FUNCTION__,
1688 EVENT_DEBUG(
"%s - Adding reaper for PID %u - %p", __FUNCTION__, pid, reap);
1714 struct kevent evset;
1723 EVENT_DEBUG(
"%p - %s - Reaper already called (logic error)... - %p",
1724 el, __FUNCTION__, i);
1734 if (
waitpid(i->pid_ev->pid, &status, WNOHANG) == i->pid_ev->pid) {
1735 EVENT_DEBUG(
"%p - %s - Reaper PID %u already exited - %p",
1736 el, __FUNCTION__, i->pid_ev->pid, i);
1745 EV_SET(&evset, i->pid_ev->pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, i);
1746 if (kevent(
kq, &evset, 1, NULL, 0, NULL) < 0) {
1747 EVENT_DEBUG(
"%p - %s - Failed adding reaper PID %u to tmp event loop - %p",
1748 el, __FUNCTION__, i->pid_ev->pid, i);
1766 EVENT_DEBUG(
"%p - %s - Reaper tmp loop error %s, forcing process reaping",
1772 EVENT_DEBUG(
"%p - %s - Reaper timeout waiting for process exit, forcing process reaping",
1780 EVENT_DEBUG(
"%p - %s - Reaper reaped PID %u, status %u - %p",
1781 el, __FUNCTION__, (
unsigned int)kev.ident, (
unsigned int)kev.data, reap);
1801 EVENT_DEBUG(
"%s - Reaper forcefully reaping PID %u - %p", __FUNCTION__, reap->pid_ev->pid, reap);
1803 if (kill(reap->pid_ev->pid, signal) < 0) {
1813 waitpid(reap->pid_ev->pid, &status, WNOHANG);
1842 struct kevent evset;
1844 EV_SET(&evset, (uintptr_t)ev, EVFILT_USER, EV_DELETE, 0, 0, 0);
1846 if (
unlikely(kevent(ev->el->kq, &evset, 1, NULL, 0, NULL) < 0)) {
1850 ev->is_registered =
false;
1856static inline CC_HINT(always_inline)
1865 if (kev->ident == 0)
return;
1890 struct kevent evset;
1899 .callback = callback,
1907 EV_SET(&evset, (uintptr_t)ev,
1908 EVFILT_USER, EV_ADD | EV_DISPATCH, (trigger * NOTE_TRIGGER), 0, ev);
1910 if (
unlikely(kevent(
el->
kq, &evset, 1, NULL, 0, NULL) < 0)) {
1918 if (ev_p) *ev_p = ev;
1933 struct kevent evset;
1935 EV_SET(&evset, (uintptr_t)ev, EVFILT_USER, EV_ENABLE, NOTE_TRIGGER, 0, NULL);
1937 if (
unlikely(kevent(
el->
kq, &evset, 1, NULL, 0, NULL) < 0)) {
1989 (pre->
uctx == uctx)) {
2042 if ((post->
callback == callback) &&
2043 (post->
uctx == uctx)) {
2065 struct timespec ts_when, *ts_wake;
2068 bool timer_event_ready =
false;
2095 timer_event_ready =
true;
2152 if (errno == EINTR) {
2167 if (!num_fd_events) {
2168 if (wait) timer_event_ready =
true;
2178 return num_fd_events + timer_event_ready;
2182static inline CC_HINT(always_inline)
2188 fd_cb(
el, ef->fd, flags, ef->uctx);
2260 if (flags & EV_EOF) {
2266#if defined(__linux__) && defined(SO_GET_FILTER)
2353 EVENT_DEBUG(
"%p - %s - Serviced %u timer(s)",
el, __FUNCTION__, (
unsigned int)ret);
2429 talloc_free_children(
el);
2455#ifdef EVFILT_LIBKQUEUE
2459static CC_HINT(format (printf, 1, 2)) CC_HINT(
nonnull)
2460void _event_kqueue_log(
char const *
fmt, ...)
2473static int _event_kqueue_logging(
UNUSED void *uctx)
2475 struct kevent kev, receipt;
2477 log_conf_kq = kqueue();
2483 EV_SET(&kev, 0, EVFILT_LIBKQUEUE, EV_ADD, NOTE_DEBUG_FUNC, (intptr_t)_event_kqueue_log, NULL);
2484 if (kevent(log_conf_kq, &kev, 1, &receipt, 1, &(
struct timespec){}) != 1) {
2491 EV_SET(&kev, 0, EVFILT_LIBKQUEUE, EV_ADD, NOTE_DEBUG, 1, NULL);
2492 if (kevent(log_conf_kq, &kev, 1, &receipt, 1, &(
struct timespec){}) != 1) {
2503static int _event_kqueue_logging_stop(
UNUSED void *uctx)
2505 struct kevent kev, receipt;
2507 EV_SET(&kev, 0, EVFILT_LIBKQUEUE, EV_ADD, NOTE_DEBUG_FUNC, 0, NULL);
2508 (void)kevent(log_conf_kq, &kev, 1, &receipt, 1, &(
struct timespec){});
2537#ifdef EVFILT_LIBKQUEUE
2538 fr_atexit_global_once_ret(&ret, _event_kqueue_logging, _event_kqueue_logging_stop, NULL);
2578 EV_SET(&kev, 0, EVFILT_USER, EV_ADD | EV_CLEAR, NOTE_FFNOP, 0, NULL);
2579 if (kevent(
el->
kq, &kev, 1, NULL, 0, NULL) < 0) {
2610static void print_time(
void *ctx)
2618 printf(
"%d.%06d\n", usec /
USEC, usec %
USEC);
2629 if (rand_pool.
randcnt == 256) {
2639int main(
int argc,
char **argv)
2649 memset(&rand_pool, 0,
sizeof(rand_pool));
2650 rand_pool.
randrsl[1] = time(NULL);
2655 array[0] =
el->time();
2656 for (i = 1; i < MAX; i++) {
2657 array[i] = array[i - 1];
2658 array[i] += event_rand() & 0xffff;
2660 fr_timer_at(NULL,
el, array[i],
false, print_time, array[i]);
2666 if (!fr_timer_run(
el, &when)) {
2667 int delay = (when - now) / 1000;
2669 printf(
"\tsleep %d microseconds\n", delay);
static int const char * fmt
#define DIAG_UNKNOWN_PRAGMAS
#define L(_str)
Helper for initialising arrays of string literals.
#define typeof_field(_type, _field)
Typeof field.
#define CC_NO_UBSAN(_sanitize)
#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_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 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 void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the 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 int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
#define fr_dlist_foreach_safe(_list_head, _type, _iter)
Iterate over the contents of a list allowing for removals.
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
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.
struct fr_event_user_s fr_event_user_t
An opaque 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.
fr_timer_list_t * tl
The timer list associated with this event loop.
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.
int(* fr_event_status_cb_t)(fr_time_t now, fr_time_delta_t wake, void *uctx)
Called after each event loop cycle.
void(* fr_event_post_cb_t)(fr_event_list_t *el, fr_time_t now, void *uctx)
Called when a post event fires.
fr_event_op_t op
Operation to perform on function/filter.
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.
Public event list structure.
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)
fr_dlist_head_t pre_callbacks
callbacks when we may be idle...
void fr_event_service(fr_event_list_t *el)
Service any outstanding timer or file descriptor events.
fr_dlist_head_t post_callbacks
post-processing callbacks
static fr_event_func_map_t filter_maps[]
static int fr_event_fd_type_set(fr_event_fd_t *ef, int fd)
Discover the type of a file descriptor.
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_rb_tree_t * fds
Tree used to track FDs with filters in kqueue.
bool is_registered
Whether this fr_event_fd_t's FD has been registered with kevent.
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_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.
void * uctx
Context pointer to pass to each file descriptor callback.
fr_event_status_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.
static size_t kevent_filter_table_len
struct fr_event_list_pub_s pub
Next event list in the chain.
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
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 dispatch
Whether the event list is currently dispatching events.
fr_dlist_head_t fd_to_free
File descriptor events pending deletion.
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.
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.
fr_event_post_cb_t callback
The callback to call.
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.
int line
Line this event was last updated on.
uintptr_t armour
protection flag from being deleted.
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...
struct fr_event_pid::@130 early_exit
Fields that are only used if we're being triggered by a user event.
fr_dlist_head_t pid_to_reap
A list of all orphaned child processes we're waiting to reap.
uint64_t fr_event_list_num_fds(fr_event_list_t *el)
Return the number of file descriptors is_registered with this event loop.
int fr_event_post_delete(fr_event_list_t *el, fr_event_post_cb_t callback, void *uctx)
Delete a post-event callback from the event list.
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.
#define GET_FUNC(_ef, _offset)
void * fr_event_fd_uctx(fr_event_fd_t *ef)
Returns the uctx associated with an fr_event_fd_t handle.
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)
int kq
instance associated with this event list.
pid_t pid
child to wait for
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.
void * uctx
Context for the callback.
bool is_registered
Whether this user event has been registered with the event loop.
fr_event_list_t * el
Event list this event belongs to.
int will_exit
Will exit on next call to fr_event_corral.
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)
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.
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 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 num_fd_events
Number of events in this event list.
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.
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)
int exit
If non-zero event loop will prevent the addition of new events, and will return immediately from the ...
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 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.
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_rb_node_t node
Entry in the tree of file descriptor handles.
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.
int fr_event_post_insert(fr_event_list_t *el, fr_event_post_cb_t callback, void *uctx)
Add a post-event callback to the event list.
fr_event_pid_t const ** parent
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.
struct kevent events[FR_EV_BATCH_FDS]
@ 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.
bool in_handler
Deletes should be deferred until after the handlers complete.
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.
static uint8_t fr_high_bit_pos(uint64_t num)
Find the highest order high bit in an unsigned 64 bit integer.
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
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.
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)
#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.
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.
#define fr_time_delta_to_timespec(_delta)
Convert a delta to a timespec.
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)
#define fr_time_eq(_a, _b)
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.
#define fr_time_neq(_a, _b)
A time delta, a difference in time measured in nanoseconds.
int fr_timer_list_run(fr_timer_list_t *tl, fr_time_t *when)
Execute any pending events in the event loop.
uint64_t fr_timer_list_num_events(fr_timer_list_t *tl)
Return number of pending events.
fr_time_t fr_timer_list_when(fr_timer_list_t *tl)
Return the time of the next event.
fr_timer_list_t * fr_timer_list_lst_alloc(TALLOC_CTX *ctx, fr_timer_list_t *parent)
Allocate a new lst based timer list.
static fr_event_list_t * el
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
#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(_msg)
static size_t char ** out