commit a4d18ca2760437195bace2194fc2aa12089e0b0c
parent 1686ec22e61a3ef8de7fd3260b7ea0940a995c03
Author: Joris Vink <joris@coders.se>
Date: Sun, 2 Jun 2019 16:29:54 +0200
Add HTTP runlocks.
A way to serialize access to HTTP page handlers in case you are
using some asynchronous api such as pgsql or libcurl stuff.
Diffstat:
2 files changed, 75 insertions(+), 0 deletions(-)
diff --git a/include/kore/http.h b/include/kore/http.h
@@ -71,6 +71,16 @@ extern "C" {
#define HTTP_STATE_COMPLETE 2
#define HTTP_STATE_RETRY 3
+struct http_runlock_queue {
+ struct http_request *req;
+ LIST_ENTRY(http_runlock_queue) list;
+};
+
+struct http_runlock {
+ struct http_request *owner;
+ LIST_HEAD(, http_runlock_queue) queue;
+};
+
struct http_header {
char *header;
char *value;
@@ -249,6 +259,7 @@ struct http_request {
size_t state_len;
char *query_string;
struct kore_module_handle *hdlr;
+ struct http_runlock_queue *runlock;
void (*onfree)(struct http_request *);
#if defined(KORE_USE_PYTHON)
@@ -345,6 +356,12 @@ void http_response_cookie(struct http_request *, const char *,
const char *, const char *, time_t, u_int32_t,
struct http_cookie **);
+void http_runlock_init(struct http_runlock *);
+void http_runlock_release(struct http_runlock *,
+ struct http_request *);
+int http_runlock_acquire(struct http_runlock *,
+ struct http_request *);
+
const char *http_media_type(const char *);
void *http_state_get(struct http_request *);
int http_state_exists(struct http_request *);
diff --git a/src/http.c b/src/http.c
@@ -149,6 +149,7 @@ static LIST_HEAD(, http_media_type) http_media_types;
static struct kore_pool http_request_pool;
static struct kore_pool http_cookie_pool;
static struct kore_pool http_body_path;
+static struct kore_pool http_rlq_pool;
struct kore_pool http_header_pool;
@@ -196,6 +197,8 @@ http_init(void)
sizeof(struct http_header), prealloc * HTTP_REQ_HEADER_MAX);
kore_pool_init(&http_cookie_pool, "http_cookie_pool",
sizeof(struct http_cookie), prealloc * HTTP_MAX_COOKIES);
+ kore_pool_init(&http_rlq_pool, "http_rlq_pool",
+ sizeof(struct http_runlock_queue), http_request_limit);
kore_pool_init(&http_body_path,
"http_body_path", HTTP_BODY_PATH_MAX, prealloc);
@@ -412,6 +415,11 @@ http_request_free(struct http_request *req)
if (req->onfree != NULL)
req->onfree(req);
+ if (req->runlock != NULL) {
+ LIST_REMOVE(req->runlock, list);
+ req->runlock = NULL;
+ }
+
#if defined(KORE_USE_TASKS)
pending_tasks = 0;
for (t = LIST_FIRST(&(req->tasks)); t != NULL; t = nt) {
@@ -1420,6 +1428,55 @@ http_start_recv(struct connection *c)
(void)net_recv_flush(c);
}
+void
+http_runlock_init(struct http_runlock *lock)
+{
+ lock->owner = NULL;
+ LIST_INIT(&lock->queue);
+}
+
+int
+http_runlock_acquire(struct http_runlock *lock, struct http_request *req)
+{
+ if (lock->owner != NULL) {
+ if (req->runlock != NULL)
+ fatal("%s: request already waiting on lock", __func__);
+
+ req->runlock = kore_pool_get(&http_rlq_pool);
+ req->runlock->req = req;
+ LIST_INSERT_HEAD(&lock->queue, req->runlock, list);
+
+ http_request_sleep(req);
+ return (KORE_RESULT_ERROR);
+ }
+
+ lock->owner = req;
+
+ return (KORE_RESULT_OK);
+}
+
+void
+http_runlock_release(struct http_runlock *lock, struct http_request *req)
+{
+ struct http_runlock_queue *next;
+ struct http_request *nextreq;
+
+ if (lock->owner != req)
+ fatal("%s: calling request != owner of runlock", __func__);
+
+ lock->owner = NULL;
+
+ if ((next = LIST_FIRST(&lock->queue)) != NULL) {
+ LIST_REMOVE(next, list);
+
+ nextreq = next->req;
+ nextreq->runlock = NULL;
+
+ http_request_wakeup(nextreq);
+ kore_pool_put(&http_rlq_pool, next);
+ }
+}
+
static struct http_request *
http_request_new(struct connection *c, const char *host,
const char *method, char *path, const char *version)
@@ -1549,6 +1606,7 @@ http_request_new(struct connection *c, const char *host,
req->agent = NULL;
req->onfree = NULL;
req->referer = NULL;
+ req->runlock = NULL;
req->flags = flags;
req->fsm_state = 0;
req->http_body = NULL;