Skip to content

Commit

Permalink
multi-tenant: fix loader dead lock
Browse files Browse the repository at this point in the history
A dead lock could occur at start up, where a loader thread would
get stuck on it's condition variable, while the main thread was
polling the loaders task results.

The vector to the dead lock is as follows:

main	                        loader
DetectEngineMultiTenantSetup
-DetectLoaderSetupLoadTenant
--DetectLoaderQueueTask
---lock loader
---add task
---unlock loader
	                        lock loader
	                        check/exec tasks
	                        unlock loader
---wake up threads
	                        lock ctrl mutx
	                        cond wait ctrl
	                        unlock ctrl
-DetectLoadersSync
--lock loader
--check tasks
--unlock loader

Between the main thread unlocking the loader and waking up the
threads, it is possible that the loader has already moved ahead
but not yet entered its conditional wait. The main thread sends
its condition signal, but since the loader isn't yet waiting on
it the signal is ignored. Then when the loader does enter its
conditional wait, the signal is not sent again.

This patch updates the logic to send signals much more often.
It also makes sure that the signal is sent under lock, as the
API requires.

Bug: #6766.
  • Loading branch information
victorjulien committed Feb 12, 2024
1 parent 9fe00ff commit 7956fa5
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/detect-engine-loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,12 @@ int DetectLoadersSync(void)
done = true;
}
SCMutexUnlock(&loader->m);
if (!done) {
/* nudge thread in case it's sleeping */
SCCtrlMutexLock(loader->tv->ctrl_mutex);
pthread_cond_broadcast(loader->tv->ctrl_cond);
SCCtrlMutexUnlock(loader->tv->ctrl_mutex);
}
}
SCMutexLock(&loader->m);
if (loader->result != 0) {
Expand Down Expand Up @@ -524,7 +530,9 @@ static void TmThreadWakeupDetectLoaderThreads(void)
while (tv != NULL) {
if (strncmp(tv->name,"DL#",3) == 0) {
BUG_ON(tv->ctrl_cond == NULL);
SCCtrlMutexLock(tv->ctrl_mutex);
pthread_cond_broadcast(tv->ctrl_cond);
SCCtrlMutexUnlock(tv->ctrl_mutex);
}
tv = tv->next;
}
Expand Down Expand Up @@ -568,6 +576,11 @@ static TmEcode DetectLoaderThreadInit(ThreadVars *t, const void *initdata, void
/* pass thread data back to caller */
*data = ftd;

DetectLoaderControl *loader = &loaders[ftd->instance];
SCMutexLock(&loader->m);
loader->tv = t;
SCMutexUnlock(&loader->m);

return TM_ECODE_OK;
}

Expand Down
1 change: 1 addition & 0 deletions src/detect-engine-loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ typedef struct DetectLoaderTask_ {
typedef struct DetectLoaderControl_ {
int id;
int result; /* 0 for ok, error otherwise */
ThreadVars *tv; /* loader threads threadvars - for waking them up */
SCMutex m;
TAILQ_HEAD(, DetectLoaderTask_) task_list;
} DetectLoaderControl;
Expand Down

0 comments on commit 7956fa5

Please sign in to comment.