diff options
Diffstat (limited to '')
-rw-r--r-- | lib/frrevent.h | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/lib/frrevent.h b/lib/frrevent.h new file mode 100644 index 0000000..3f74df3 --- /dev/null +++ b/lib/frrevent.h @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Event management routine header. + * Copyright (C) 1998 Kunihiro Ishiguro + */ + +#ifndef _ZEBRA_THREAD_H +#define _ZEBRA_THREAD_H + +#include <zebra.h> +#include <pthread.h> +#include <poll.h> +#include "monotime.h" +#include "frratomic.h" +#include "typesafe.h" +#include "xref.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CONSUMED_TIME_CHECK 5000000 + +extern bool cputime_enabled; +extern unsigned long cputime_threshold; +/* capturing wallclock time is always enabled since it is fast (reading + * hardware TSC w/o syscalls) + */ +extern unsigned long walltime_threshold; + +struct rusage_t { +#ifdef HAVE_CLOCK_THREAD_CPUTIME_ID + struct timespec cpu; +#else + struct rusage cpu; +#endif + struct timeval real; +}; +#define RUSAGE_T struct rusage_t + +#define GETRUSAGE(X) event_getrusage(X) + +PREDECL_LIST(event_list); +PREDECL_HEAP(event_timer_list); + +struct fd_handler { + /* number of pfd that fit in the allocated space of pfds. This is a + * constant and is the same for both pfds and copy. + */ + nfds_t pfdsize; + + /* file descriptors to monitor for i/o */ + struct pollfd *pfds; + /* number of pollfds stored in pfds */ + nfds_t pfdcount; + + /* chunk used for temp copy of pollfds */ + struct pollfd *copy; + /* number of pollfds stored in copy */ + nfds_t copycount; +}; + +struct xref_eventsched { + struct xref xref; + + const char *funcname; + const char *dest; + uint32_t event_type; +}; + +PREDECL_HASH(cpu_records); + +/* Master of the theads. */ +struct event_loop { + char *name; + + struct event **read; + struct event **write; + struct event_timer_list_head timer; + struct event_list_head event, ready, unuse; + struct list *cancel_req; + bool canceled; + pthread_cond_t cancel_cond; + struct cpu_records_head cpu_records[1]; + int io_pipe[2]; + int fd_limit; + struct fd_handler handler; + unsigned long alloc; + long selectpoll_timeout; + bool spin; + bool handle_signals; + pthread_mutex_t mtx; + pthread_t owner; + + bool ready_run_loop; + RUSAGE_T last_getrusage; +}; + +/* Event types. */ +enum event_types { + EVENT_READ, + EVENT_WRITE, + EVENT_TIMER, + EVENT_EVENT, + EVENT_READY, + EVENT_UNUSED, + EVENT_EXECUTE, +}; + +/* Event itself. */ +struct event { + enum event_types type; /* event type */ + enum event_types add_type; /* event type */ + struct event_list_item eventitem; + struct event_timer_list_item timeritem; + struct event **ref; /* external reference (if given) */ + struct event_loop *master; /* pointer to the struct event_loop */ + void (*func)(struct event *e); /* event function */ + void *arg; /* event argument */ + union { + int val; /* second argument of the event. */ + int fd; /* file descriptor in case of r/w */ + struct timeval sands; /* rest of time sands value. */ + } u; + struct timeval real; + struct cpu_event_history *hist; /* cache pointer to cpu_history */ + unsigned long yield; /* yield time in microseconds */ + const struct xref_eventsched *xref; /* origin location */ + pthread_mutex_t mtx; /* mutex for thread.c functions */ + bool ignore_timer_late; +}; + +#ifdef _FRR_ATTRIBUTE_PRINTFRR +#pragma FRR printfrr_ext "%pTH"(struct event *) +#endif + +struct cpu_event_history { + struct cpu_records_item item; + + void (*func)(struct event *e); + atomic_size_t total_cpu_warn; + atomic_size_t total_wall_warn; + atomic_size_t total_starv_warn; + atomic_size_t total_calls; + atomic_size_t total_active; + struct time_stats { + atomic_size_t total, max; + } real; + struct time_stats cpu; + atomic_uint_fast32_t types; + const char *funcname; +}; + +/* Struct timeval's tv_usec one second value. */ +#define TIMER_SECOND_MICRO 1000000L + +/* Event yield time. */ +#define EVENT_YIELD_TIME_SLOT 10 * 1000L /* 10ms */ + +#define EVENT_TIMER_STRLEN 12 + +/* Macros. */ +#define EVENT_ARG(X) ((X)->arg) +#define EVENT_FD(X) ((X)->u.fd) +#define EVENT_VAL(X) ((X)->u.val) + +/* + * Please consider this macro deprecated, and do not use it in new code. + */ +#define EVENT_OFF(thread) \ + do { \ + if ((thread)) \ + event_cancel(&(thread)); \ + } while (0) + +/* + * Macro wrappers to generate xrefs for all thread add calls. Includes + * file/line/function info for debugging/tracing. + */ +#include "lib/xref.h" + +#define _xref_t_a(addfn, type, m, f, a, v, t) \ + ({ \ + static const struct xref_eventsched _xref __attribute__( \ + (used)) = { \ + .xref = XREF_INIT(XREFT_EVENTSCHED, NULL, __func__), \ + .funcname = #f, \ + .dest = #t, \ + .event_type = EVENT_##type, \ + }; \ + XREF_LINK(_xref.xref); \ + _event_add_##addfn(&_xref, m, f, a, v, t); \ + }) /* end */ + +#define event_add_read(m, f, a, v, t) _xref_t_a(read_write, READ, m, f, a, v, t) +#define event_add_write(m, f, a, v, t) \ + _xref_t_a(read_write, WRITE, m, f, a, v, t) +#define event_add_timer(m, f, a, v, t) _xref_t_a(timer, TIMER, m, f, a, v, t) +#define event_add_timer_msec(m, f, a, v, t) \ + _xref_t_a(timer_msec, TIMER, m, f, a, v, t) +#define event_add_timer_tv(m, f, a, v, t) \ + _xref_t_a(timer_tv, TIMER, m, f, a, v, t) +#define event_add_event(m, f, a, v, t) _xref_t_a(event, EVENT, m, f, a, v, t) + +#define event_execute(m, f, a, v, p) \ + ({ \ + static const struct xref_eventsched _xref __attribute__( \ + (used)) = { \ + .xref = XREF_INIT(XREFT_EVENTSCHED, NULL, __func__), \ + .funcname = #f, \ + .dest = NULL, \ + .event_type = EVENT_EXECUTE, \ + }; \ + XREF_LINK(_xref.xref); \ + _event_execute(&_xref, m, f, a, v, p); \ + }) /* end */ + +/* Prototypes. */ +extern struct event_loop *event_master_create(const char *name); +void event_master_set_name(struct event_loop *master, const char *name); +extern void event_master_free(struct event_loop *m); +extern void event_master_free_unused(struct event_loop *m); + +extern void _event_add_read_write(const struct xref_eventsched *xref, + struct event_loop *master, + void (*fn)(struct event *), void *arg, int fd, + struct event **tref); + +extern void _event_add_timer(const struct xref_eventsched *xref, + struct event_loop *master, + void (*fn)(struct event *), void *arg, long t, + struct event **tref); + +extern void _event_add_timer_msec(const struct xref_eventsched *xref, + struct event_loop *master, + void (*fn)(struct event *), void *arg, long t, + struct event **tref); + +extern void _event_add_timer_tv(const struct xref_eventsched *xref, + struct event_loop *master, + void (*fn)(struct event *), void *arg, + struct timeval *tv, struct event **tref); + +extern void _event_add_event(const struct xref_eventsched *xref, + struct event_loop *master, + void (*fn)(struct event *), void *arg, int val, + struct event **tref); + +extern void _event_execute(const struct xref_eventsched *xref, + struct event_loop *master, + void (*fn)(struct event *), void *arg, int val, + struct event **eref); + +extern void event_cancel(struct event **event); +extern void event_cancel_async(struct event_loop *m, struct event **eptr, + void *data); +/* Cancel ready tasks with an arg matching 'arg' */ +extern void event_cancel_event_ready(struct event_loop *m, void *arg); +/* Cancel all tasks with an arg matching 'arg', including timers and io */ +extern void event_cancel_event(struct event_loop *m, void *arg); +extern struct event *event_fetch(struct event_loop *m, struct event *event); +extern void event_call(struct event *event); +extern unsigned long event_timer_remain_second(struct event *event); +extern struct timeval event_timer_remain(struct event *event); +extern unsigned long event_timer_remain_msec(struct event *event); +extern int event_should_yield(struct event *event); +/* set yield time for thread */ +extern void event_set_yield_time(struct event *event, unsigned long ytime); + +/* Internal libfrr exports */ +extern void event_getrusage(RUSAGE_T *r); +extern void event_cmd_init(void); + +/* Returns elapsed real (wall clock) time. */ +extern unsigned long event_consumed_time(RUSAGE_T *after, RUSAGE_T *before, + unsigned long *cpu_time_elapsed); + +/* only for use in logging functions! */ +extern pthread_key_t thread_current; +extern char *event_timer_to_hhmmss(char *buf, int buf_size, + struct event *t_timer); + +static inline bool event_is_scheduled(struct event *thread) +{ + if (thread) + return true; + + return false; +} + +/* Debug signal mask */ +void debug_signals(const sigset_t *sigs); + +static inline void event_ignore_late_timer(struct event *event) +{ + event->ignore_timer_late = true; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _ZEBRA_THREAD_H */ |