This file contains the context of the dap_worker_t handlers.

Each event socket is assigned to a context, and the assignment method depends on the operating system in which the work is performed. This file provides a cross-platform implementation for the following types of system I/O functions: poll, epoll, kqueue and IOCP.

Our wrappers over system threads are designed in such a way that they allow us to achieve high performance and minimal latency when switching between threads of handlers. This is necessary for the operation of highly loaded systems.

At the moment, there are two types of context listed in dap_context_type: worker and proc-thread, one for each processor core. Regular “light” requests are processed by workers, but if a request comes in to process something that will require serious calculations, the thread switches to the context of the proc-thread.

Structures:

  • [[dap_context#Context]|dap_context_t|]] - context structure
  • dap_context_type - types of the context

Functions:

STRUCTURES

Context

typedef struct dap_context {
 
    uint32_t id;  
    int cpu_id;     
    pthread_t thread_id; 
    int type; 
    pthread_cond_t started_cond; 
    pthread_mutex_t started_mutex; 
    bool started;
    bool signal_exit;
    bool is_running; 
    uint32_t running_flags; 
    void * _inheritor;  
    ssize_t esocket_current; 
    ssize_t esockets_selected; 
    atomic_uint event_sockets_count;
    dap_events_socket_t *esockets; 
    dap_events_socket_t *event_exit;
    
} dap_context_t;

The dap_context structure represents a context related to task execution in a multithreaded environment, which can work with events and sockets.

Fields:

  1. uint32_t id: Context identifier. This is a unique number used to distinguish contexts within the system.
  2. int cpu_id: Identifier of the processor core to which the context is bound (if any). This field indicates the core on which the context will execute or to which it is assigned.
  3. pthread_t thread_id: Identifier of the thread associated with this context. This value is used for managing and identifying the thread in the multithreaded environment.
  4. int type: Type of the context. Worker or proxy-thread.
  5. pthread_cond_t started_cond: Condition variable for synchronization, used to determine when the context has been initialized or started.
  6. pthread_mutex_t started_mutex: Mutex for the started_cond variable.
  7. bool started: Flag indicating whether the context has started. If true, it means the context has been initialized and has started its work.
  8. bool signal_exit: Flag indicating that the context is finishing its work. This can be used for the proper shutdown or stop of the context.
  9. bool is_running: Flag indicating whether the context is currently running. If true, the context is actively executing.
  10. uint32_t running_flags: Flags belonging to the context during its operation. These could be a set of flags for configuring or controlling various aspects of the context’s work.
  11. void * _inheritor: Pointer to data indicating that the current context has inheritors. The type of inheritors is undefined; it could be a pointer to a structure or object associated with the context, but with an undefined type.
  12. ssize_t esocket_current: Index of the current socket event. This value can be used to track the current state or identifier of the processed socket.
  13. ssize_t esockets_selected: Number of selected event sockets. This field can be used to store the number of sockets selected for processing or monitoring.
  14. atomic_uint event_sockets_count: The number of event sockets associated with the context. This field uses an atomic data type to allow safe modifications in a multithreaded environment, which is important for synchronization between threads.
  15. dap_events_socket_t *esockets: Pointer to a structure containing event socket data. This field stores an array or list of sockets that the context is working with.
  16. dap_events_socket_t *event_exit: Pointer to the socket responsible for ending the context’s operation. This socket can be used to receive a signal to terminate the context.

Other fields in this structure are private, as the user does not need to interact with them.

Thus, the dap_context structure is used to manage the state and actions of a context in a multithreaded environment, using threads, synchronization, event sockets, and flags that determine when and how the context should start, run, and complete its work.

Context types

enum dap_context_type {
 
    DAP_CONTEXT_TYPE_WORKER,
    DAP_CONTEXT_TYPE_PROC_THREAD
    
};

This structure contains an enumeration of context types.

Fields:

  1. DAP_CONTEXT_TYPE_WORKER: Worker dap_worker_t.
  2. DAP_CONTEXT_TYPE_PROC_THREAD: Proc thread.

FUNCTIONS

Context initialization

int dap_context_init()
---
Return: int (0 is everything ok)

Arguments:

Function receives no arguments.

Description:

The function initializes the context module

Context deinitialization

void dap_context_deinit()
---
Return: void

Arguments:

Function receives no arguments.

Description:

Deinitialization of the context.

Getting current context

dap_context_t* dap_context_current()
---
Return: dap_context_t* (context)

Arguments:

Function receives no arguments.

Description:

The function gets the current context.

Creation of a new context

dap_context_t * dap_context_new(enum a_type)
---
Return: dap_context_t * (context)

Arguments:

  1. enum a_type: Type of a context (worker or proc-thread).

Description:

The function creates a new dap_context structure, writes the context type into it, and assigns a unique ID to this context.

Creation of the context thread and its start

int dap_context_run(dap_context_t * a_context,int a_cpu_id, int a_sched_policy, int a_priority, uint32_t a_flags, dap_context_callback_t a_callback_loop_before,  dap_context_callback_t a_callback_loop_after, void * a_callback_arg )
---
Return: int (0 if everything ok)

Arguments:

  1. dap_context_t *a_context: A pointer to a dap_context_t structure, which holds the context for the operation. This structure contains necessary information for the event loop or context management.
  2. int a_cpu_id: The ID of the CPU core to which the thread should be assigned. This allows the thread to bind a specific CPU core.
  3. int a_sched_policy: The scheduling policy for the thread. It defines how the operating system schedules the execution of threads. For now, there are 4 available:
#Usual policies:
DAP_CONTEXT_POLICY_DEFAULT         0
DAP_CONTEXT_POLICY_TIMESHARING     1
 
#Real-time policies:
DAP_CONTEXT_POLICY_FIFO            2
DAP_CONTEXT_POLICY_ROUND_ROBIN     3
  1. int a_priority: The priority of the thread. This parameter is used with the scheduling policy to assign a priority level to the thread, determining how it will be scheduled relative to other threads. There are 3 priority levels:
DAP_CONTEXT_PRIORITY_NORMAL -1
DAP_CONTEXT_PRIORITY_HIGH   -2
DAP_CONTEXT_PRIORITY_LOW    -3
  1. uint32_t a_flags: A set of flags that can modify the behavior of the context. These flags could be used to enable or disable certain features. Available flags:
DAP_CONTEXT_FLAG_WAIT_FOR_STARTED  0x00000001
DAP_CONTEXT_FLAG_EXIT_IF_ERROR     0x00000100
  1. dap_context_callback_t a_callback_loop_before: A function callback to be executed before the main loop starts. This callback is used for any initialization or setup tasks before the main event processing loop begins.
  2. dap_context_callback_t a_callback_loop_after: A function callback to be executed after the main loop finishes. This callback is used for cleanup or finalization tasks after the event processing loop has completed.
  3. void *a_callback_arg: A pointer to a memory area that will be passed as an argument to the a_callback_loop_before and a_callback_loop_after functions. It can hold any type of data that the callbacks need for processing.

Description:

The function creates a context thread and starts it, also at the beginning of the function the dap_context_msg_run_t structure is completely filled, if something goes wrong, the function will output a message in the logs that it cannot create a new thread for the context.

Types of errors that can be encountered during the function’s operation (the function returns an error code, not an identifier):

  • ENOMEM: Insufficient memory
  • EINVAL: Invalid arguments
  • EAGAIN: Insufficient resources (e.g., too many threads)
  • EPERM: Operation is not permitted
  • ETIMEDOUT: The waiting timed out
  • EINTR: The wait was interrupted by a signal

If everything is ok, the function returns 0.

Context work stop

void dap_context_stop_n_kill(dap_context_t * a_context)
---
Return:  void

Arguments:

  1. dap_context_t *a_context: A pointer to a dap_context_t structure, which holds the context of the thread.

Description:

The function stops the context’s operation for workers or proс-threads, depending on the type of context the thread has.

Event socket update

int dap_context_poll_update(dap_events_socket_t * a_esocket)
---
Return: int (0 if everything is ok)

Arguments:

  1. dap_events_socket_t * a_esocket: A pointer to the dap_events_socket_t structure which contains events socket, which flags are going to be updated.

Description:

The function replaces the current flags in the system functions poll(), epoll(), and kqueue() with the flags set on the given event socket (DAP_SOCK_READY_TO_READ, DAP_SOCK_READY_TO_WRITE, DAP_SOCK_CONNECTING).

The function will return one of the following errors if the update fails:

  • EINVAL: Invalid argument. For example, an incorrect file descriptor, operation type, or event structure is specified
  • EBADF: Invalid file descriptor provided
  • EEXIST: Attempt to add an already existing file descriptor to the event list
  • ENOENT: Attempt to remove a non-existent file descriptor from the event list
  • EPERM: Insufficient privileges to perform the operation.
  • EBUSY: The specified file descriptor is already in use by another epoll instance
  • "-666" - Wrong poll index when removing from context
  • ”Esocket is not assigned with anything

Add event socket to the context

int dap_context_add(dap_context_t * a_context, dap_events_socket_t * a_es )
---
Return: int (error code, 0 if everything is ok)

Arguments:

  1. dap_context_t *a_context: A pointer to a dap_context_t structure, which represents the thread context to which the event socket will be added.
  2. dap_events_socket_t *a_es: A pointer to a dap_events_socket_t structure, which represents the event socket to be added to the context.

Description:

The function adds an event socket to the context, and in the event socket structure, a pointer to this context is set as the parent context.

Returned error types:

  • -1 - “Can’t add NULL esocket to the context” if a null event socket is passed
  • -2 - “Can’t add esocket to the bad context” if the context type is not a worker
  • The function will also return an error if it is not supported for the given socket format or platform

Socket delete context

int dap_context_remove( dap_events_socket_t * a_es)
---
Return: int (error code, 0 if everything is ok)

Arguments:

  1. dap_events_socket_t * a_es: A pointer to a dap_events_socket_t structure, which contains the events socket is going to be deleted from the context.

Description:

The function removes the event socket from the context.

Returned error types:

  • -1 - “No context assigned to esocket"
  • "Try to remove nonexistent socket”

Socket find by UUID

dap_events_socket_t *dap_context_find(dap_context_t * a_context, dap_events_socket_uuid_t a_es_uuid )
---
Return: dap_events_socket_t * (event socket)

Arguments:

  1. dap_context_t *a_context: A pointer to a dap_context_t structure, which represents the context in which the event socket is being searched.
  2. dap_events_socket_uuid_t a_es_uuid: The unique identifier (UUID) of the event socket that is being used for searching.

Description:

The function searches for the events socket in the context using UUID.

Create context queue

dap_events_socket_t * dap_context_create_queue(dap_context_t * a_context, dap_events_socket_callback_queue_ptr_t a_callback)
---
Return: dap_events_socket_t * (event socket)

Arguments:

  1. dap_context_t *a_context: A pointer to a dap_context_t structure, which represents the context in which the event socket will be created.
  2. dap_events_socket_callback_queue_ptr_t a_callback: A callback function that defines how events in the queue associated with the event socket will be handled. This callback function will be executed whenever there are events to process in the event socket’s queue.

Description:

The function creates a new event socket with the descriptor DESCRIPTOR_TYPE_QUEUE and with the flag DAP_SOCK_QUEUE_PTR allowing it to interact with other threads through queues, enabling them to write/add to the event sockets of this worker via these queues.

In case the descriptor assignment fails, the error Not defined s_create_type_queue_ptr() for your platform will be raised.

Next, the event socket is added to the context, and in case of failure, the following errors may occur:

  • -1 - “Can’t add NULL esocket to the context”
  • -2 - “Can’t add esocket to the bad context”
  • The function will also return an error if it is not supported for the given socket format or platform

Create context event

dap_events_socket_t * dap_context_create_event(dap_context_t * a_context, dap_events_socket_callback_event_t a_callback)
---
Return: dap_events_socket_t * (event socket)

Arguments:

  1. dap_context_t *a_context: A pointer to a dap_context_t structure, which represents the context in which the event socket will be created.
  2. dap_events_socket_callback_event_t a_callback: A callback function that will be used to handle individual events for the event socket. The callback function will be called when an event occurs on the socket, allowing the worker to process those events.

Description:

The function creates a new event socket with the descriptor DESCRIPTOR_TYPE_EVENT. This allows the event socket to signal the worker (dap_worker_t) about various events.

Next, the event socket is added to the context, and in case of failure, the following errors may occur:

  • -1 - “Can’t add NULL esocket to the context” if a null event socket is passed
  • -2 - “Can’t add esocket to the bad context” if the context type is not a worker
  • The function will also return an error if it is not supported for the given socket format or platform