mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 07:37:02 +02:00
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.
296 lines
10 KiB
C
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 */
|