This file contains the working logic of the events. It starts the work of the input-output reactor (IO module), as well as the binding of processor cores to the processing threads ([[dap_worker#Worker|dap_worker_t]]). ## FUNCTIONS - [[dap_events#Worker initialization checkage|dap_events_workers_init_status]] - worker initialization checkage - [[dap_events#Counting CPU cores|dap_get_cpu_count]] - counting CPU cores - [[dap_events#Threads to cores assigning|dap_cpu_assign_thread_on]] - threads to cores assigning - [[dap_events#Events initialization|dap_events_init]] - events initialization - [[dap_events#Events deinitialization|dap_events_deinit]] - events deinitialization - [[dap_events#Events start (main loop of the server)|dap_events_start]] - events start (main loop of the server) - [[dap_events#Waiting for events end|dap_events_wait]] - waiting for events end - [[dap_events#Events stop|dap_events_stop_all]] - events stop - [[dap_events#Getting index of the worker with minimal loading|dap_events_worker_get_index_min]] - getting index of the worker with minimal loading - [[dap_events#Counting threads|dap_events_thread_get_count]] - counting threads - [[dap_events#Getting worker with minimal quantity of connected sockets|dap_events_worker_get_auto]] - getting worker with minimal quantity of connected sockets - [[dap_events#Getting worker by index|dap_event_worker_get]] - getting worker by index - [[dap_events#Printing workers|dap_worker_print_all]] - printing workers ### Worker initialization checkage ```c bool dap_events_workers_init_status() --- Return: boolean ``` **Arguments:** Function receives no arguments. **Description:** Returns `true` if the workers are initialized, `false` otherwise. ### Counting CPU cores ```c uint32_t dap_get_cpu_count( ) --- Return: uint32_t (number of cores) ``` **Arguments:** Function receives no arguments. **Description:** Uses system tools to count the number of processor cores. For each system, the count is made according to the system features. ### Threads to cores assigning ```c void dap_cpu_assign_thread_on(uint32_t a_cpu_id) --- Return: uint32_t a_cpu_id (number of cores, counted previously) ``` **Arguments:** 1. **`uint32_t a_cpu_id`**: This is the ID of the CPU core to which the thread should be assigned. The core numbers are typically counted from 0 and represent the available CPU cores in the system. **Description:** The function assigns threads to individual cores. The function body also provides a handler for errors that may occur during the function's operation: - **`EFAULT`**: Invalid memory address. - **`EINVAL`**: Invalid affinity mask. - **`ESRCH`**: Thread not found. - **`EPFNOSUPPORT`**: System doesn't support thread affinity. - **`default`**: Unknown error. The constructed error message is logged using the `log_it` function, providing information about the error code, message, and the affected CPU ID (`a_cpu_id`). ### Events initialization ```c int dap_events_init( uint32_t a_threads_count, size_t a_conn_timeout ) --- Return: int (0 if everything is ok, others if not) ``` **Arguments:** 1. **`uint32_t a_threads_count`**: This parameter specifies the number of threads to be created for event handling. It determines how many worker threads will be used to process events concurrently. 2. **`size_t a_conn_timeout`**: This parameter defines the connection timeout, in seconds. It sets the maximum amount of time to wait for a connection before considering it as timed out. **Description:** The function initializes event handlers using a pointer to a [[dap_worker#Worker|dap_worker_t]] structure, and as a result prints a message that the event reactor for a certain number of threads has been initialized. Initialization of event handlers also leads to the initialization of the [[dap_context]] and [[dap_events_socket]] modules. In case of an error, the handlers are deinitialized using the [[dap_events#Events deinitialization|dap_events_deinit()]] function. The function also checks the number of threads; if there are more than cores, the number of threads is limited by the number of cores. ### Events deinitialization ```c void dap_events_deinit( ) --- Return: void ``` **Arguments:** Function receives no arguments. **Description:** During the function's operation, proc threads, event sockets, and workers are deinitialized using the dap_proc_thread_deinit, [[dap_events_socket#Events socket deinitialization|dap_events_socket_deinit()]], and dap_worker_deinit functions, respectively. The [[dap_events#Waiting for events end|dap_event_wait()]] function is also called, which terminates the use of threads one by one, sequentially waiting for each of them to complete before moving on to the next. ### Events start (main loop of the server) ```c int dap_events_start() --- Return: int (0 if everyhting is ok, others if not) ``` **Arguments:** Function receives no arguments. **Description:** This function is responsible for starting the server event loop. 1. First, it checks whether the [[dap_events#Events initialization|dap_events_init()]] event reactor is running; if not, it returns an error with the code `-1`. 2. Then, for all workers (the number of workers = the number of threads), a [[dap_worker#Worker|dap_worker_t]] structure is created; if the pointer to the structure is empty, the function returns the error `-6: memory allocation error`. 3. After memory allocation, the context creation functions are launched for each worker: [[dap_context#Creation of a new context|dap_context_new()]], [[dap_context#Creation of the context thread and its start|dap_context_run()]], [[dap_worker#Callback that assigns a context to the worker|dap_worker_context_callback_started()]] and [[dap_worker#Callback that stops worker's context|dap_worker_context_callback_stopped()]]. If any of the functions does not work as expected, the system will notify that the handler could not be started. Then, for all OS except Windows, intercontextual queues are created that control the input/output sequence: 1. For each worker, memory is allocated in pointer structures to [[dap_events_socket#Структура событийного сокета|dap_events_socket_t]], which represent different types of queues. If the pointer to the structure is empty, the function will return the error `-6: memory allocation error`. 2. After initialization and memory allocation, event sockets of these queues are created for each handler using the functions [[dap_events_socket#Creation of the queue-type socket|dap_events_socket_queue_ptr_create_input()]] and [[dap_worker#Add event sockets to the worker (straight)|dap_worker_add_events_socket_unsafe()]]. After all the above actions, the proc threads are initialized; if for some reason initialization is impossible, the system will return the error `-4`. At the end of the function, an error handler is provided that checks which of the workers has not been initialized. When this worker is found, the structure that contains it is completely deleted. Moreover, for all operating systems except Windows, all structures created for the implementation of queues are also deleted. ### Waiting for events end ```c int dap_events_wait( ) --- Return: int (always 0) ``` **Arguments:** Function receives no arguments. **Description:** This function waits for the end of the worker threads. Only after all workers have completed their work, they can be disabled. ### Events stop ```c void dap_events_stop_all( ) --- Return: void ``` **Arguments:** Function receives no arguments. **Description:** At the beginning, the function checks whether the event reactor [[dap_events#Events initialization|dap_events_init()]] is initialized, if it is running, then in the loop each thread is turned off in turn (event_exit). ### Getting index of the worker with minimal loading ```c uint32_t dap_events_worker_get_index_min() --- Return: uint32_t (worker index with the minimum index, at the beginning of the function is 0) ``` **Arguments:** Function receives no arguments. **Description:** At the beginning, the function checks whether the [[dap_events#Events initialization|dap_events_init()]] event reactor is initialized; if it is not running, the error `-1` is returned. Then, in the loop, the threads of handlers are sorted out, and the handler with the fewest sockets connected is found. ### Counting threads ```c uint32_t dap_events_thread_get_count() --- Return: uint32_t (number of threads) ``` **Arguments:** Function receives no arguments. **Description:** This function counts active threads. ### Getting worker with minimal quantity of connected sockets ```c dap_worker_t *dap_events_worker_get_auto( ) --- Return: dap_worker_t* (worker) ``` **Arguments:** Function receives no arguments. **Description:** The function first checks whether the [[dap_events#Events initialization|dap_events_init()]] event reactor is running, if not, an error is displayed. The function returns a worker thread (a pointer to a [[dap_worker#Поток-обработчик|dap_worker_t]] structure) with a minimum load calculated using the [[dap_events#Getting index of the worker with minimal loading|dap_events_worker_get_index_min function()]]. ### Getting worker by index ```c dap_worker_t * dap_events_worker_get(uint8_t a_index) --- Return: dap_worker_t * (worker, returns NULL if index is incorrect) ``` **Arguments:** 1. **`uint8_t a_index`**: Index of the worker. **Description:** The function first checks whether the [[dap_events#Events initialization|dap_events_init()]] event reactor is running, if not, an error is displayed. The function returns a worker thread (a pointer to a [[dap_worker#Поток-обработчик|dap_worker_t]] structure) with specified index. ### Printing workers ```c void dap_worker_print_all( ) --- Return: void ``` **Arguments:** Function receives no arguments. **Description:** The function first checks whether the [[dap_events#Events initialization|dap_events_init()]] event reactor is running, if not, an error is displayed. The function prints the number of event sockets for each handler thread.