haproxy/include/haproxy/event_hdl-t.h
Aurelien DARRAGON cb3ec978fd MINOR: event_hdl: add global tunables
The local variable "event_hdl_async_max_notif_at_once" which was
introduced with the event_hdl API was left as is but with a TODO note
telling that we should make it a global tunable.

Well, we're doing this now. To prepare for upcoming tunables related to
event_hdl API, we add a dedicated struct named event_hdl_tune which is
globally exposed through the event_hdl header file so that it may be used
from everywhere. The struct is automatically initialized in
event_hdl_init() according to defaults.h.

"event_hdl_async_max_notif_at_once" now becomes
"event_hdl_tune.max_events_at_once" with it's dedicated
configuation keyword: "tune.events.max-events-at-once".

We're also taking this opportunity to raise the default value from 10
to 100 since it's seems quite reasonnable given existing async event_hdl
users.

The documentation was updated accordingly.
2023-11-29 08:59:27 +01:00

296 lines
10 KiB
C

/*
* include/haproxy/event_hdl-t.h
* event handlers management definitions
*
* Copyright 2022 HAProxy Technologies
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, version 2.1
* exclusively.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _HAPROXY_EVENT_HDL_T_H
# define _HAPROXY_EVENT_HDL_T_H
#include <stdint.h>
#include <sys/time.h>
#include <haproxy/api-t.h>
/* event data struct are defined as followed */
struct event_hdl_cb_data_template {
struct {
/* safe data can be safely used from both
* sync and async handlers
* data consistency is guaranteed
*/
} safe;
struct {
/* unsafe data may only be used from sync handlers:
* in async mode, data consistency cannot be guaranteed
* and unsafe data may already be stale, thus using
* it is highly discouraged because it
* could lead to undefined behavior (UAF, null dereference...)
*/
} unsafe;
};
/* event_hdl tunables */
struct event_hdl_tune {
unsigned int max_events_at_once;
};
/* FIXME: adjust if needed! Should be large enough
* to support every struct event_hdl_cb_data_x types
* BUG_ON check in publish/async_mode and static assert
* in EVENT_HDL_CB_DATA will ensure this
*/
#define EVENT_HDL_ASYNC_EVENT_DATA (768)
/* used internally to store a single copy of event data when dealing with
* async handlers.
* The same copy can be provided to multiple handlers to prevent memory waste:
* refcount is used to keep track of references so that
* data can be freed when not used anymore
*/
typedef void (*event_hdl_data_free)(const void *data);
struct event_hdl_async_event_data
{
/* internal storage */
char data[EVENT_HDL_ASYNC_EVENT_DATA];
/* user-provided free function if event data relies on
* dynamic members that require specific cleanup
*/
event_hdl_data_free mfree;
uint32_t refcount;
};
/* type for storing event subscription type */
struct event_hdl_sub_type
{
/* up to 256 families, non cumulative, adjust if needed */
uint8_t family;
/* up to 16 sub types using bitmasks, adjust if needed */
uint16_t subtype;
};
struct event_hdl_sub_list_head {
struct mt_list head;
struct mt_list known; /* api uses this to track known subscription lists */
};
/* event_hdl_sub_list is an alias (please use this for portability) */
typedef struct event_hdl_sub_list_head event_hdl_sub_list;
struct event_hdl_async_equeue_head {
struct mt_list head;
uint32_t size; /* near realtime size, not fully synced with head (to be used as a hint) */
};
/* event_hdl_async_equeue is an alias to mt_list (please use this for portability) */
typedef struct event_hdl_async_equeue_head event_hdl_async_equeue;
/* subscription mgmt from event */
struct event_hdl_sub_mgmt
{
/* manage subscriptions from event
* this must not be used directly because locking might be required
*/
struct event_hdl_sub *this;
/* safe functions than can be used from event context (sync and async mode) */
struct event_hdl_sub_type (*getsub)(const struct event_hdl_sub_mgmt *);
int (*resub)(const struct event_hdl_sub_mgmt *, struct event_hdl_sub_type);
void (*unsub)(const struct event_hdl_sub_mgmt *);
};
/* single event structure pushed into async event queue
* used by tasks async handlers
*/
struct event_hdl_async_event
{
struct mt_list mt_list;
struct event_hdl_sub_type type;
/* data wrapper - should not be used directly */
struct event_hdl_async_event_data *_data;
/* for easy data access,
* points to _data->data if data is available
*/
void *data;
void *private;
struct timeval when;
struct event_hdl_sub_mgmt sub_mgmt;
};
/* internal structure provided to function event_hdl_publish()
* It contains ptr to data relevant to the event
*/
struct event_hdl_cb_data {
/* internal use: ptr to struct event_hdl_cb_data_type */
void *_ptr;
/* internal use: holds actual data size*/
size_t _size;
/* user specified freeing function for event_hdl_cb_data_type
* struct members
*/
event_hdl_data_free _mfree;
};
/* struct provided to event_hdl_cb_* handlers
* contains data related to the event
* that triggered the handler
*/
struct event_hdl_cb
{
/* event type */
struct event_hdl_sub_type e_type;
/* event data */
void *e_data;
/* manage the subscription responsible for handing the event to us */
const struct event_hdl_sub_mgmt *sub_mgmt;
/* may be used by sync event handler to ensure
* it runs in sync mode, and thus is eligible to access unsafe data.
* This could save the day when users are copy-pasting function
* logic from a sync handler to an async handler without
* taking appropriate precautions and unsafe accesses are performed.
* (See EVENT_HDL_ASSERT_SYNC macro API helper)
*/
uint8_t _sync;
};
/* prototype for event_hdl_cb_sync function pointer */
typedef void (*event_hdl_cb_sync)(const struct event_hdl_cb *cb, void *private);
/* prototype for event_hdl_cb async function pointer */
typedef void (*event_hdl_cb_async)(const struct event_hdl_cb *cb, void *private);
/* prototype for event_hdl_private_free function pointer */
typedef void (*event_hdl_private_free)(void *private);
/* tasklet forward declaration */
struct tasklet;
/* enum for sync mode */
enum event_hdl_async_mode
{
EVENT_HDL_ASYNC_MODE_NORMAL = 1,
EVENT_HDL_ASYNC_MODE_ADVANCED = 2
};
/* event hdl, used when subscribing (and then associated with a subscription) */
struct event_hdl {
/* optional unique id (hash) for lookup */
uint64_t id;
/* handler debug: origin (initial event subscription calling place) */
const char *dorigin;
/* handler requires async mode:
* EVENT_HDL_ASYNC_MODE_NORMAL = normal
* EVENT_HDL_ASYNC_MODE_ADVANCED = advanced, single task wakeup
*/
uint8_t async;
union {
event_hdl_cb_sync sync_ptr; /* if !async */
event_hdl_cb_async async_ptr; /* only used if async==1 (normal) */
};
/* ptr to async task responsible for consuming events */
struct tasklet *async_task;
/* used by async tasks to consume pending events */
event_hdl_async_equeue *async_equeue;
/* function ptr automatically called by:
* async task when hdl is unregistered and private is no longer referenced
* sync context when unregistering is performed
*/
event_hdl_private_free private_free;
/* it is not safe to assume that private will not
* be used anymore once hdl is unregistered:
* with async handlers, private could still be referenced
* in pending events to be consumed later by the task (by design).
* If freeing private is needed, you must provide async_private_free
* function pointer when registering.
* It will be called when private is no longer used
* after unregistering hdl to perform private cleanup.
* (please use this even in sync mode so that subscription
* can easily be turned into async mode later without breaking stuff)
*/
void *private;
};
/* flags for event_hdl_sub struct (32 bits) */
#define EHDL_SUB_F_PAUSED 0x0001 /* subscription will temporarily ignore events */
/* list elem: subscription (handler subscribed to specific events)
*/
struct event_hdl_sub {
struct mt_list mt_list;
/* event type subscription */
struct event_hdl_sub_type sub;
uint32_t flags;
/* event handler */
struct event_hdl hdl;
/* used to guarantee that END event will be delivered
* (memory is allocated when registering, no memory failure can occur at runtime)
*/
struct event_hdl_async_event *async_end;
/* > 0 : subscription is referenced, don't free yet
* use atomic OPS to write and read from it
*/
uint32_t refcount;
/* TODO: atomic_call_counter for stats?! */
};
#define ESUB_INDEX(n) (1 << (n - 1))
#define EVENT_HDL_SUB_TYPE(_family, _type) ((struct event_hdl_sub_type){ .family = _family, .subtype = ESUB_INDEX(_type) })
#define EVENT_HDL_SUB_FAMILY(_family) ((struct event_hdl_sub_type){ .family = _family, .subtype = ~0 })
#define EVENT_HDL_SUB_NONE ((struct event_hdl_sub_type){ .family = 0, .subtype = 0})
/* for async tasks: subscription is ending */
#define EVENT_HDL_SUB_END ((struct event_hdl_sub_type){ .family = 0, .subtype = 1})
/* --------------------------------------- */
/* user defined event types are listed here
* please reflect any change in these macros in the subtype map
* defined below that is used to perform string to event type and
* event type to string conversions
*/
/* TODO */
/* SERVER FAMILY, provides event_hdl_cb_data_server struct
* (will be defined in haproxy/server-t.h)
*/
#define EVENT_HDL_SUB_SERVER EVENT_HDL_SUB_FAMILY(1)
#define EVENT_HDL_SUB_SERVER_ADD EVENT_HDL_SUB_TYPE(1,1)
#define EVENT_HDL_SUB_SERVER_DEL EVENT_HDL_SUB_TYPE(1,2)
#define EVENT_HDL_SUB_SERVER_UP EVENT_HDL_SUB_TYPE(1,3)
#define EVENT_HDL_SUB_SERVER_DOWN EVENT_HDL_SUB_TYPE(1,4)
/* server state change */
#define EVENT_HDL_SUB_SERVER_STATE EVENT_HDL_SUB_TYPE(1,5)
/* server admin change */
#define EVENT_HDL_SUB_SERVER_ADMIN EVENT_HDL_SUB_TYPE(1,6)
/* server check-related (agent or health) event */
#define EVENT_HDL_SUB_SERVER_CHECK EVENT_HDL_SUB_TYPE(1,7)
/* server inet addr (addr:svc_port tuple) change event */
#define EVENT_HDL_SUB_SERVER_INETADDR EVENT_HDL_SUB_TYPE(1,8)
/* --------------------------------------- */
/* Please reflect changes above in event_hdl_sub_type_map defined
* in event_hdl.c file
*/
struct event_hdl_sub_type_map {
const char *name;
struct event_hdl_sub_type type;
};
#endif /* _HAPROXY_EVENT_HDL_T_H */