LeOS-Genesis/external/badvpn/system/BReactor_badvpn.h

573 lines
18 KiB
C
Raw Normal View History

2020-10-05 13:12:00 +02:00
/**
* @file BReactor_badvpn.h
* @author Ambroz Bizjak <ambrop7@gmail.com>
*
* @section LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @section DESCRIPTION
*
* Event loop that supports file desciptor (Linux) or HANDLE (Windows) events
* and timers.
*/
#ifndef BADVPN_SYSTEM_BREACTOR_H
#define BADVPN_SYSTEM_BREACTOR_H
#if (defined(BADVPN_USE_WINAPI) + defined(BADVPN_USE_EPOLL) + defined(BADVPN_USE_KEVENT) + defined(BADVPN_USE_POLL)) != 1
#error Unknown event backend or too many event backends
#endif
#ifdef BADVPN_USE_WINAPI
#include <windows.h>
#endif
#ifdef BADVPN_USE_EPOLL
#include <sys/epoll.h>
#endif
#ifdef BADVPN_USE_KEVENT
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#endif
#ifdef BADVPN_USE_POLL
#include <poll.h>
#endif
#include <stdint.h>
#include <misc/debug.h>
#include <misc/debugcounter.h>
#include <base/DebugObject.h>
#include <structure/LinkedList1.h>
#include <structure/CAvl.h>
#include <system/BTime.h>
#include <base/BPending.h>
struct BSmallTimer_t;
typedef struct BSmallTimer_t *BReactor_timerstree_link;
#include "BReactor_badvpn_timerstree.h"
#include <structure/CAvl_decl.h>
#define BTIMER_SET_ABSOLUTE 1
#define BTIMER_SET_RELATIVE 2
/**
* Handler function invoked when the timer expires.
* The timer was in running state.
* The timer enters not running state before this function is invoked.
* This function is being called from within the timer's previosly
* associated reactor.
*
* @param timer pointer to the timer. Use the {@link UPPER_OBJECT} macro
* to obtain the pointer to the containing structure.
*/
typedef void (*BSmallTimer_handler) (struct BSmallTimer_t *timer);
/**
* Handler function invoked when the timer expires.
* The timer was in running state.
* The timer enters not running state before this function is invoked.
* This function is being called from within the timer's previosly
* associated reactor.
*
* @param user value passed to {@link BTimer_Init}
*/
typedef void (*BTimer_handler) (void *user);
/**
* Timer object used with {@link BReactor}.
*/
typedef struct BSmallTimer_t {
union {
BSmallTimer_handler smalll; // MSVC doesn't like "small"
BTimer_handler heavy;
} handler;
union {
LinkedList1Node list_node;
struct BSmallTimer_t *tree_child[2];
} u;
struct BSmallTimer_t *tree_parent;
btime_t absTime;
int8_t tree_balance;
uint8_t state;
uint8_t is_small;
} BSmallTimer;
/**
* Initializes the timer object.
* The timer object is initialized in not running state.
*
* @param bt the object
* @param handler handler function invoked when the timer expires
*/
void BSmallTimer_Init (BSmallTimer *bt, BSmallTimer_handler handler);
/**
* Checks if the timer is running.
*
* @param bt the object
* @return 1 if running, 0 if not running
*/
int BSmallTimer_IsRunning (BSmallTimer *bt);
/**
* Timer object used with {@link BReactor}. This is a legacy wrapper
* around {@link BSmallTimer} with an extra field for the default time.
*/
typedef struct {
BSmallTimer base;
void *user;
btime_t msTime;
} BTimer;
/**
* Initializes the timer object.
* The timer object is initialized in not running state.
*
* @param bt the object
* @param msTime default timeout in milliseconds
* @param handler handler function invoked when the timer expires
* @param user value to pass to the handler function
*/
void BTimer_Init (BTimer *bt, btime_t msTime, BTimer_handler handler, void *user);
/**
* Checks if the timer is running.
*
* @param bt the object
* @return 1 if running, 0 if not running
*/
int BTimer_IsRunning (BTimer *bt);
#ifndef BADVPN_USE_WINAPI
struct BFileDescriptor_t;
#define BREACTOR_READ (1 << 0)
#define BREACTOR_WRITE (1 << 1)
#define BREACTOR_ERROR (1 << 2)
#define BREACTOR_HUP (1 << 3)
/**
* Handler function invoked by the reactor when one or more events are detected.
* The events argument will contain a subset of the monitored events (BREACTOR_READ, BREACTOR_WRITE),
* plus possibly the error event (BREACTOR_ERROR).
* The file descriptor object is in active state, being called from within
* the associated reactor.
*
* @param user value passed to {@link BFileDescriptor_Init}
* @param events bitmask composed of a subset of monitored events (BREACTOR_READ, BREACTOR_WRITE),
* and possibly the error event BREACTOR_ERROR and the hang-up event BREACTOR_HUP.
* Will be nonzero.
*/
typedef void (*BFileDescriptor_handler) (void *user, int events);
/**
* File descriptor object used with {@link BReactor}.
*/
typedef struct BFileDescriptor_t {
int fd;
BFileDescriptor_handler handler;
void *user;
int active;
int waitEvents;
#ifdef BADVPN_USE_EPOLL
struct BFileDescriptor_t **epoll_returned_ptr;
#endif
#ifdef BADVPN_USE_KEVENT
int kevent_tag;
int **kevent_returned_ptr;
#endif
#ifdef BADVPN_USE_POLL
LinkedList1Node poll_enabled_fds_list_node;
int poll_returned_index;
#endif
} BFileDescriptor;
/**
* Intializes the file descriptor object.
* The object is initialized in not active state.
*
* @param bs file descriptor object to initialize
* @param fb file descriptor to represent
* @param handler handler function invoked by the reactor when a monitored event is detected
* @param user value passed to the handler functuon
*/
void BFileDescriptor_Init (BFileDescriptor *bs, int fd, BFileDescriptor_handler handler, void *user);
#endif
// BReactor
#define BSYSTEM_MAX_RESULTS 64
#define BSYSTEM_MAX_HANDLES 64
#define BSYSTEM_MAX_POLL_FDS 4096
/**
* Event loop that supports file desciptor (Linux) or HANDLE (Windows) events
* and timers.
*/
typedef struct {
int exiting;
int exit_code;
// jobs
BPendingGroup pending_jobs;
// timers
BReactor__TimersTree timers_tree;
LinkedList1 timers_expired_list;
// limits
LinkedList1 active_limits_list;
#ifdef BADVPN_USE_WINAPI
LinkedList1 iocp_list;
HANDLE iocp_handle;
LinkedList1 iocp_ready_list;
#endif
#ifdef BADVPN_USE_EPOLL
int efd; // epoll fd
struct epoll_event epoll_results[BSYSTEM_MAX_RESULTS]; // epoll returned events buffer
int epoll_results_num; // number of events in the array
int epoll_results_pos; // number of events processed so far
#endif
#ifdef BADVPN_USE_KEVENT
int kqueue_fd;
struct kevent kevent_results[BSYSTEM_MAX_RESULTS];
int kevent_results_num;
int kevent_results_pos;
#endif
#ifdef BADVPN_USE_POLL
LinkedList1 poll_enabled_fds_list;
int poll_num_enabled_fds;
int poll_results_num;
int poll_results_pos;
struct pollfd *poll_results_pollfds;
BFileDescriptor **poll_results_bfds;
#endif
DebugObject d_obj;
#ifndef BADVPN_USE_WINAPI
DebugCounter d_fds_counter;
#endif
#ifdef BADVPN_USE_KEVENT
DebugCounter d_kevent_ctr;
#endif
DebugCounter d_limits_ctr;
} BReactor;
/**
* Initializes the reactor.
* {@link BLog_Init} must have been done.
* {@link BTime_Init} must have been done.
*
* @param bsys the object
* @return 1 on success, 0 on failure
*/
int BReactor_Init (BReactor *bsys) WARN_UNUSED;
/**
* Frees the reactor.
* Must not be called from within the event loop ({@link BReactor_Exec}).
* There must be no {@link BPending} or {@link BSmallPending} objects using the
* pending group returned by {@link BReactor_PendingGroup}.
* There must be no running timers in this reactor.
* There must be no limit objects in this reactor.
* There must be no file descriptors or handles registered
* with this reactor.
* There must be no {@link BReactorKEvent} objects in this reactor.
*
* @param bsys the object
*/
void BReactor_Free (BReactor *bsys);
/**
* Runs the event loop.
*
* @param bsys the object
* @return value passed to {@link BReactor_Quit}
*/
int BReactor_Exec (BReactor *bsys);
/**
* Causes the event loop ({@link BReactor_Exec}) to cease
* dispatching events and return.
* Any further calls of {@link BReactor_Exec} will return immediately.
*
* @param bsys the object
* @param code value {@link BReactor_Exec} should return. If this is
* called more than once, it will return the last code.
*/
void BReactor_Quit (BReactor *bsys, int code);
/**
* Starts a timer to expire at the specified time.
* The timer must have been initialized with {@link BSmallTimer_Init}.
* If the timer is in running state, it must be associated with this reactor.
* The timer enters running state, associated with this reactor.
*
* @param bsys the object
* @param bt timer to start
* @param mode interpretation of time (BTIMER_SET_ABSOLUTE or BTIMER_SET_RELATIVE)
* @param time absolute or relative expiration time
*/
void BReactor_SetSmallTimer (BReactor *bsys, BSmallTimer *bt, int mode, btime_t time);
/**
* Stops a timer.
* If the timer is in running state, it must be associated with this reactor.
* The timer enters not running state.
*
* @param bsys the object
* @param bt timer to stop
*/
void BReactor_RemoveSmallTimer (BReactor *bsys, BSmallTimer *bt);
/**
* Starts a timer to expire after its default time.
* The timer must have been initialized with {@link BTimer_Init}.
* If the timer is in running state, it must be associated with this reactor.
* The timer enters running state, associated with this reactor.
*
* @param bsys the object
* @param bt timer to start
*/
void BReactor_SetTimer (BReactor *bsys, BTimer *bt);
/**
* Starts a timer to expire after a given time.
* The timer must have been initialized with {@link BTimer_Init}.
* If the timer is in running state, it must be associated with this reactor.
* The timer enters running state, associated with this reactor.
*
* @param bsys the object
* @param bt timer to start
* @param after relative expiration time
*/
void BReactor_SetTimerAfter (BReactor *bsys, BTimer *bt, btime_t after);
/**
* Starts a timer to expire at the specified time.
* The timer must have been initialized with {@link BTimer_Init}.
* If the timer is in running state, it must be associated with this reactor.
* The timer enters running state, associated with this reactor.
* The timer's expiration time is set to the time argument.
*
* @param bsys the object
* @param bt timer to start
* @param time absolute expiration time (according to {@link btime_gettime})
*/
void BReactor_SetTimerAbsolute (BReactor *bsys, BTimer *bt, btime_t time);
/**
* Stops a timer.
* If the timer is in running state, it must be associated with this reactor.
* The timer enters not running state.
*
* @param bsys the object
* @param bt timer to stop
*/
void BReactor_RemoveTimer (BReactor *bsys, BTimer *bt);
/**
* Returns a {@link BPendingGroup} object that can be used to schedule jobs for
* the reactor to execute. These jobs have complete priority over other events
* (timers, file descriptors and Windows handles).
* The returned pending group may only be used as an argument to {@link BPending_Init},
* and must not be accessed by other means.
* All {@link BPending} and {@link BSmallPending} objects using this group must be
* freed before freeing the reactor.
*
* @param bsys the object
* @return pending group for scheduling jobs for the reactor to execute
*/
BPendingGroup * BReactor_PendingGroup (BReactor *bsys);
/**
* Executes pending jobs until either:
* - the reference job is reached, or
* - {@link BReactor_Quit} is called.
* The reference job must be reached before the job list empties.
* The reference job will not be executed.
*
* WARNING: Use with care. This should only be used to to work around third-party software
* that does not integrade into the jobs system. In particular, you should think about:
* - the effects the jobs to be executed may have, and
* - the environment those jobs expect to be executed in.
*
* @param bsys the object
* @param ref reference job. It is not accessed in any way, only its address is compared to
* pending jobs before they are executed.
* @return 1 if the reference job was reached,
* 0 if {@link BReactor_Quit} was called (either while executing a job, or before)
*/
int BReactor_Synchronize (BReactor *bsys, BSmallPending *ref);
#ifndef BADVPN_USE_WINAPI
/**
* Starts monitoring a file descriptor.
*
* @param bsys the object
* @param bs file descriptor object. Must have been initialized with
* {@link BFileDescriptor_Init} Must be in not active state.
* On success, the file descriptor object enters active state,
* associated with this reactor.
* @return 1 on success, 0 on failure
*/
int BReactor_AddFileDescriptor (BReactor *bsys, BFileDescriptor *bs) WARN_UNUSED;
/**
* Stops monitoring a file descriptor.
*
* @param bsys the object
* @param bs {@link BFileDescriptor} object. Must be in active state,
* associated with this reactor. The file descriptor object
* enters not active state.
*/
void BReactor_RemoveFileDescriptor (BReactor *bsys, BFileDescriptor *bs);
/**
* Sets monitored file descriptor events.
*
* @param bsys the object
* @param bs {@link BFileDescriptor} object. Must be in active state,
* associated with this reactor.
* @param events events to watch for. Must not have any bits other than
* BREACTOR_READ and BREACTOR_WRITE.
* This overrides previosly monitored events.
*/
void BReactor_SetFileDescriptorEvents (BReactor *bsys, BFileDescriptor *bs, int events);
#endif
typedef struct {
BReactor *reactor;
int limit;
int count;
LinkedList1Node active_limits_list_node;
DebugObject d_obj;
} BReactorLimit;
/**
* Initializes a limit object.
* A limit object consists of a counter integer, which is initialized to
* zero, is incremented by {@link BReactorLimit_Increment} up to \a limit,
* and is reset to zero every time the event loop performs a wait.
* If the event loop has processed all detected events, and before performing
* a wait, it determines that timers have expired, the counter will not be reset.
*
* @param o the object
* @param reactor reactor the object is tied to
* @param limit maximum counter value. Must be >0.
*/
void BReactorLimit_Init (BReactorLimit *o, BReactor *reactor, int limit);
/**
* Frees a limit object.
*
* @param o the object
*/
void BReactorLimit_Free (BReactorLimit *o);
/**
* Attempts to increment the counter of a limit object.
*
* @param o the object
* @return 1 if the counter was lesser than the limit and was incremented,
* 0 if the counter was greater or equal to the limit and could not be
* incremented
*/
int BReactorLimit_Increment (BReactorLimit *o);
/**
* Sets the limit of a limit object.
*
* @param o the object
* @param limit new limit. Must be >0.
*/
void BReactorLimit_SetLimit (BReactorLimit *o, int limit);
#ifdef BADVPN_USE_KEVENT
typedef void (*BReactorKEvent_handler) (void *user, u_int fflags, intptr_t data);
typedef struct {
BReactor *reactor;
BReactorKEvent_handler handler;
void *user;
uintptr_t ident;
short filter;
int kevent_tag;
int **kevent_returned_ptr;
DebugObject d_obj;
} BReactorKEvent;
int BReactorKEvent_Init (BReactorKEvent *o, BReactor *reactor, BReactorKEvent_handler handler, void *user, uintptr_t ident, short filter, u_int fflags, intptr_t data);
void BReactorKEvent_Free (BReactorKEvent *o);
#endif
#ifdef BADVPN_USE_WINAPI
#define BREACTOR_IOCP_EVENT_SUCCEEDED 1
#define BREACTOR_IOCP_EVENT_FAILED 2
#define BREACTOR_IOCP_EVENT_EXITING 3
typedef void (*BReactorIOCPOverlapped_handler) (void *user, int event, DWORD bytes);
typedef struct {
OVERLAPPED olap;
BReactor *reactor;
void *user;
BReactorIOCPOverlapped_handler handler;
LinkedList1Node iocp_list_node;
int is_ready;
LinkedList1Node ready_list_node;
int ready_succeeded;
DWORD ready_bytes;
DebugObject d_obj;
} BReactorIOCPOverlapped;
HANDLE BReactor_GetIOCPHandle (BReactor *reactor);
void BReactorIOCPOverlapped_Init (BReactorIOCPOverlapped *o, BReactor *reactor, void *user, BReactorIOCPOverlapped_handler handler);
void BReactorIOCPOverlapped_Free (BReactorIOCPOverlapped *o);
void BReactorIOCPOverlapped_Wait (BReactorIOCPOverlapped *o, int *out_succeeded, DWORD *out_bytes);
#endif
#endif