lnm/include/lnm/loop.h

104 lines
2.4 KiB
C

#ifndef LNM_LOOP
#define LNM_LOOP
#include <pthread.h>
#include <stdatomic.h>
#include <stdint.h>
#include <stdlib.h>
#include "lnm/common.h"
#define LNM_LOOP_BUF_SIZE 2048
typedef enum lnm_loop_state {
lnm_loop_state_req = 0,
lnm_loop_state_res,
lnm_loop_state_end,
lnm_loop_state_req_blocking,
lnm_loop_state_res_blocking,
} lnm_loop_state;
/**
* State for a currently active connection
*/
typedef struct lnm_loop_conn {
int fd;
lnm_loop_state state;
void *ctx;
struct {
char buf[LNM_LOOP_BUF_SIZE];
size_t size;
size_t read;
} r;
struct {
char buf[LNM_LOOP_BUF_SIZE];
size_t size;
} w;
} lnm_loop_conn;
/**
* Concurrent fixed-size queue used to distribute work among worker threads
*/
typedef struct lnm_loop_queue {
struct {
lnm_loop_conn **arr;
size_t len;
} buf;
size_t head;
size_t tail;
pthread_mutex_t mutex;
pthread_cond_t cond;
} lnm_loop_queue;
/**
* Initialize a new queue with the specified fixed capacity
*/
lnm_err lnm_loop_queue_init(lnm_loop_queue **out, size_t cap);
/**
* Queue the given connection. If the queue is currently full, this action
* blocks until there is space available.
*/
void lnm_loop_queue_push(lnm_loop_queue *q, lnm_loop_conn *conn);
/**
* Pop a connection from the queue. This action blocks until a connection is
* available.
*/
lnm_loop_conn *lnm_loop_queue_pop(lnm_loop_queue *q);
typedef struct lnm_loop {
int listen_fd;
int epoll_fd;
atomic_int open;
void *gctx;
lnm_err (*ctx_init)(void **out, void *gctx);
void (*ctx_free)(void *ctx);
void (*data_read)(lnm_loop_conn *conn);
void (*data_write)(lnm_loop_conn *conn);
lnm_loop_queue *wq;
} lnm_loop;
lnm_err lnm_loop_init(lnm_loop **out, void *gctx,
lnm_err (*ctx_init)(void **out, void *gctx),
void (*ctx_free)(void *ctx),
void (*data_read)(lnm_loop_conn *conn),
void (*data_write)(lnm_loop_conn *conn));
lnm_err lnm_loop_setup(lnm_loop *l, uint16_t port);
lnm_err lnm_loop_run(lnm_loop *l, int thread_count);
/**
* Reschedule the given connection, either on the event loop for network IO or
* on a worker thread for blocking work. Connections are terminated as needed.
*/
void lnm_loop_conn_schedule(lnm_loop *l, lnm_loop_conn *conn);
/**
* Main loop executed on the worker threads.
*/
void lnm_loop_worker_run(void *arg);
#endif