threads: add unit tests for TmThreadsWaitForUnpause

Covers the killed-during-initial-pause case (mgmt thread returns so the
main loop runs once; non-mgmt returns false and skips it, THV_PAUSED
cleared on both paths) and the unpause-while-spinning path, driven from
a helper thread.

Ticket: #9168.
(cherry picked from commit 8998fbacc5)
pull/16412/head
Victor Julien 3 weeks ago
parent d8b23bbbc7
commit 97eef73df2

@ -44,6 +44,7 @@
#include "flow-manager.h"
#include "flow-var.h"
#include "flow-bit.h"
#include "tm-threads.h"
#include "pkt-var.h"
#include "host.h"
@ -201,6 +202,7 @@ static void RegisterUnittests(void)
MagicRegisterTests();
UtilMiscRegisterTests();
ThreadingAffinityRegisterTests();
TmThreadsRegisterTests();
DetectAddressTests();
DetectProtoTests();
DetectPortTests();

@ -2452,3 +2452,73 @@ void TmThreadsInjectFlowById(Flow *f, const int id)
}
BUG_ON(1);
}
#ifdef UNITTESTS
#include "util-unittest-helper.h"
#include <pthread.h>
static void *UnpauseHelper(void *arg)
{
ThreadVars *tv = (ThreadVars *)arg;
/* only unpause once the caller is in the pause wait: THV_PAUSED is
* set by the caller on entry, so the fixed-delay race where the
* caller is descheduled past the unpause window cannot happen */
while (!TmThreadsCheckFlag(tv, THV_PAUSED)) {
SleepUsec(100);
}
TmThreadsUnsetFlag(tv, THV_PAUSE);
return NULL;
}
static int TmThreadsTestWaitForUnpause01(void)
{
ThreadVars th_v;
memset(&th_v, 0, sizeof(th_v));
th_v.type = TVT_MGMT;
/* killed while still in the initial pause: mgmt threads must still
* run their main loop once to do final work */
TmThreadsSetFlag(&th_v, THV_PAUSE);
TmThreadsSetFlag(&th_v, THV_KILL);
FAIL_IF(!TmThreadsWaitForUnpause(&th_v));
FAIL_IF(TmThreadsCheckFlag(&th_v, THV_PAUSED));
memset(&th_v, 0, sizeof(th_v));
th_v.type = TVT_PPT;
/* non-mgmt threads keep skipping the main loop */
TmThreadsSetFlag(&th_v, THV_PAUSE);
TmThreadsSetFlag(&th_v, THV_KILL);
FAIL_IF(TmThreadsWaitForUnpause(&th_v));
FAIL_IF(TmThreadsCheckFlag(&th_v, THV_PAUSED));
PASS;
}
static int TmThreadsTestWaitForUnpause02(void)
{
/* unpause arrives while the thread spins in the pause wait */
ThreadVars th_v;
memset(&th_v, 0, sizeof(th_v));
TmThreadsSetFlag(&th_v, THV_PAUSE);
pthread_t th;
/* a failed create would leave THV_PAUSE set forever: fail the test
* instead of spinning in the pause wait */
int rc = pthread_create(&th, NULL, UnpauseHelper, &th_v);
FAIL_IF(rc != 0);
FAIL_IF(!TmThreadsWaitForUnpause(&th_v));
pthread_join(th, NULL);
FAIL_IF(TmThreadsCheckFlag(&th_v, THV_PAUSED));
PASS;
}
void TmThreadsRegisterTests(void)
{
UtRegisterTest("TmThreadsTestWaitForUnpause01", TmThreadsTestWaitForUnpause01);
UtRegisterTest("TmThreadsTestWaitForUnpause02", TmThreadsTestWaitForUnpause02);
}
#endif /* UNITTESTS */

Loading…
Cancel
Save