kore

a fork of the worlds most advanced web framework
Log | Files | Refs | README | LICENSE

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:
Minclude/kore/http.h | 17+++++++++++++++++
Msrc/http.c | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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;