#include #include "lnm/log.h" #include "lnm/loop.h" lnm_err lnm_loop_queue_init(lnm_loop_queue **out, size_t cap) { lnm_loop_conn **arr = calloc(cap, sizeof(lnm_loop_conn *)); if (arr == NULL) { return lnm_err_failed_alloc; } lnm_loop_queue *q = calloc(1, sizeof(lnm_loop_queue)); if (q == NULL) { free(arr); return lnm_err_failed_alloc; } q->buf.arr = arr; q->buf.len = cap; q->tail = 0; q->head = 0; q->empty = true; pthread_mutex_init(&q->mutex, NULL); pthread_cond_init(&q->cond, NULL); *out = q; return lnm_err_ok; } void lnm_loop_queue_push(lnm_loop_queue *q, lnm_loop_conn *conn) { pthread_mutex_lock(&q->mutex); while (q->head == q->tail && !q->empty) { pthread_cond_wait(&q->cond, &q->mutex); } q->buf.arr[q->head] = conn; // Make sure the index wraps around q->head = (q->head + 1) % q->buf.len; q->empty = false; // Unlock mutex and signal to waiting threads pthread_mutex_unlock(&q->mutex); pthread_cond_signal(&q->cond); } lnm_loop_conn *lnm_loop_queue_pop(lnm_loop_queue *q) { pthread_mutex_lock(&q->mutex); while (q->empty) { pthread_cond_wait(&q->cond, &q->mutex); } lnm_loop_conn *out = q->buf.arr[q->tail]; q->tail = (q->tail + 1) % q->buf.len; q->empty = q->tail == q->head; // Unlock mutex and signal to waiting threads pthread_mutex_unlock(&q->mutex); pthread_cond_signal(&q->cond); return out; } void lnm_loop_worker_run(void *arg) { lnm_loop *l = arg; lnm_loop_queue *q = l->wq; // Get thread ID by incrementing counter pthread_mutex_lock(&l->threads.mutex); int thread_id = l->threads.worker_count; l->threads.worker_count++; pthread_mutex_unlock(&l->threads.mutex); while (1) { lnm_loop_conn *conn = lnm_loop_queue_pop(q); lnm_ldebug("loop", "worker %i processing fd %i", thread_id, conn->fd); lnm_loop_conn_advance(l, conn); lnm_loop_conn_schedule(l, conn); } }