From 940d9b963644b835ec5d4f2b9cf627c2e3a6d915 Mon Sep 17 00:00:00 2001 From: Wilfried Goesgens Date: Fri, 7 Nov 2014 00:38:18 +0100 Subject: [PATCH] Instead of initiating the transition between DB & IO-Queue from within the application logic, we now only prepare the swap and let the control-logic handle the transition. By this we avoid possible race conditions. --- citadel/event_client.c | 45 +++++++++++++------ citadel/event_client.h | 4 +- .../modules/eventclient/serv_eventclient.c | 7 +++ 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/citadel/event_client.c b/citadel/event_client.c index c46429337..bdb33dd73 100644 --- a/citadel/event_client.c +++ b/citadel/event_client.c @@ -86,7 +86,7 @@ extern struct ev_loop *event_db; extern ev_async DBAddJob; extern ev_async DBExitEventLoop; -eNextState QueueDBOperation(AsyncIO *IO, IO_CallBack CB) +eNextState QueueAnDBOperation(AsyncIO *IO) { IOAddHandler *h; int i; @@ -94,7 +94,10 @@ eNextState QueueDBOperation(AsyncIO *IO, IO_CallBack CB) SetEVState(IO, eDBQ); h = (IOAddHandler*)malloc(sizeof(IOAddHandler)); h->IO = IO; - h->EvAttch = CB; + + assert(IO->ReAttachCB != NULL); + + h->EvAttch = IO->ReAttachCB; ev_cleanup_init(&IO->db_abort_by_shutdown, IO_abort_shutdown_callback); IO->db_abort_by_shutdown.data = IO; @@ -219,7 +222,7 @@ static void IO_abort_shutdown_callback(struct ev_loop *loop, } -eNextState QueueEventContext(AsyncIO *IO, IO_CallBack CB) +eNextState QueueAnEventContext(AsyncIO *IO) { IOAddHandler *h; int i; @@ -227,7 +230,11 @@ eNextState QueueEventContext(AsyncIO *IO, IO_CallBack CB) SetEVState(IO, eIOQ); h = (IOAddHandler*)malloc(sizeof(IOAddHandler)); h->IO = IO; - h->EvAttch = CB; + + assert(IO->ReAttachCB != NULL); + + h->EvAttch = IO->ReAttachCB; + ev_cleanup_init(&IO->abort_by_shutdown, IO_abort_shutdown_callback); IO->abort_by_shutdown.data = IO; @@ -260,12 +267,20 @@ eNextState QueueEventContext(AsyncIO *IO, IO_CallBack CB) eNextState EventQueueDBOperation(AsyncIO *IO, IO_CallBack CB, int CloseFDs) { StopClientWatchers(IO, CloseFDs); - return QueueDBOperation(IO, CB); + IO->ReAttachCB = CB; + return eDBQuery; } eNextState DBQueueEventContext(AsyncIO *IO, IO_CallBack CB) { StopDBWatchers(IO); - return QueueEventContext(IO, CB); + IO->ReAttachCB = CB; + return eSendReply; +} + +eNextState QueueEventContext(AsyncIO *IO, IO_CallBack CB) +{ + IO->ReAttachCB = CB; + return QueueAnEventContext(IO); } extern eNextState evcurl_handle_start(AsyncIO *IO); @@ -310,7 +325,8 @@ eNextState QueueCurlContext(AsyncIO *IO) eNextState CurlQueueDBOperation(AsyncIO *IO, IO_CallBack CB) { StopCurlWatchers(IO); - return QueueDBOperation(IO, CB); + IO->ReAttachCB = CB; + return eDBQuery; } @@ -497,13 +513,12 @@ eReadState HandleInbound(AsyncIO *IO) assert(IO->ReadDone); ev_io_stop(event_base, &IO->recv_event); rc = IO->ReadDone(IO); - if (rc != eDBQuery) { - IO->NextState = rc; - Finished = StrBufCheckBuffer(&IO->RecvBuf); + if (rc == eDBQuery) { + return QueueAnDBOperation(IO); } else { - return rc; - + IO->NextState = rc; + Finished = StrBufCheckBuffer(&IO->RecvBuf); } } } @@ -1239,10 +1254,12 @@ void KillAsyncIOContext(AsyncIO *IO) case eReadMore: case eReadPayload: case eReadFile: - QueueEventContext(&Ctx->IO, KillOtherContextNow); + IO->ReAttachCB = KillOtherContextNow; + QueueAnEventContext(&Ctx->IO); break; case eDBQuery: - QueueDBOperation(&Ctx->IO, KillOtherContextNow); + IO->ReAttachCB = KillOtherContextNow; + QueueAnDBOperation(&Ctx->IO); break; case eTerminateConnection: case eAbort: diff --git a/citadel/event_client.h b/citadel/event_client.h index 8777a3433..b21e2cc14 100644 --- a/citadel/event_client.h +++ b/citadel/event_client.h @@ -193,7 +193,8 @@ struct AsyncIO { Timeout, /* Timeout handler;may also be conn. timeout */ ConnFail, /* What to do when one connection failed? */ ShutdownAbort,/* we're going down. make your piece. */ - NextDBOperation; /* Perform Database IO */ + NextDBOperation, /* Perform Database IO */ + ReAttachCB; /* on the hop from one Q to the other, this is the next CB */ /* if we have linereaders, maybe we want to read more lines before * the real application logic is called? */ @@ -282,7 +283,6 @@ extern int DebugCAres; void FreeAsyncIOContents(AsyncIO *IO); eNextState NextDBOperation(AsyncIO *IO, IO_CallBack CB); -eNextState QueueDBOperation(AsyncIO *IO, IO_CallBack CB); eNextState EventQueueDBOperation(AsyncIO *IO, IO_CallBack CB, int CloseFDs); void StopDBWatchers(AsyncIO *IO); eNextState QueueEventContext(AsyncIO *IO, IO_CallBack CB); diff --git a/citadel/modules/eventclient/serv_eventclient.c b/citadel/modules/eventclient/serv_eventclient.c index 4a27c2482..942234afd 100644 --- a/citadel/modules/eventclient/serv_eventclient.c +++ b/citadel/modules/eventclient/serv_eventclient.c @@ -107,6 +107,8 @@ typedef struct _evcurl_global_data { ev_async WakeupCurl; evcurl_global_data global; +eNextState QueueAnDBOperation(AsyncIO *IO); + static void gotstatus(int nnrun) { @@ -200,6 +202,11 @@ gotstatus(int nnrun) switch(IO->SendDone(IO)) { case eDBQuery: + curl_easy_cleanup(IO->HttpReq.chnd); + IO->HttpReq.chnd = NULL; + FreeURL(&IO->ConnectMe); + QueueAnDBOperation(IO); + break; case eSendDNSQuery: case eReadDNSReply: case eConnect: -- 2.30.2