Skip to content
Snippets Groups Projects
Commit db5d1b34 authored by Florian Fischer's avatar Florian Fischer
Browse files

prevent data races when initializing the workers PRNG seeds

Each worker currently calls uniformIntDistribution(randomEngine)
which modifies the randomEngine internally and thus produces data races
when the threads run in parallel.

This change calls uniformIntDistribution(randomEngine) on the main thread
for each worker and passes the resulting seeds to the workerLoop.

The data race was found by gcc's tsan.
parent f6d67a88
No related branches found
No related tags found
No related merge requests found
......@@ -53,7 +53,7 @@ Runtime::Runtime(workerid_t workerCount, RuntimeStrategy& strategy, unsigned int
randomEngine(seed),
atLeastOneWorkerIsSleeping(false) {
threads = new pthread_t[workerCount];
workerIds = new workerid_t[workerCount];
workerArgs = new struct WorkerArgs[workerCount];
const int nprocs = get_nprocs();
......@@ -79,17 +79,22 @@ Runtime::Runtime(workerid_t workerCount, RuntimeStrategy& strategy, unsigned int
if (errno) DIE_MSG_ERRNO("pthread_attr_setaffinity_np() failed");
// End non portable.
// Load the worker ID into the worker ID map.
workerIds[i] = i;
// Load the worker ID into the worker Argument array.
workerArgs[i].id = i;
// Load the worker PRNG seed into the Argument array.
// This is not done by each thread individually because the randomEngine is
// mutated and therefore produces data races.
workerArgs[i].seed = uniformIntDistribution(randomEngine);
auto thread_function = [](void* voidWorkerId) -> void* {
auto thread_function = [](void* voidWorkerArgs) -> void* {
#ifdef EMPER_LIBURCU
rcu_register_thread();
#endif
return currentRuntime->workerLoop(voidWorkerId);
struct WorkerArgs* workerArgs = reinterpret_cast<struct WorkerArgs*>(voidWorkerArgs);
return currentRuntime->workerLoop(workerArgs);
};
errno = pthread_create(&threads[i], &attr, thread_function, &workerIds[i]);
errno = pthread_create(&threads[i], &attr, thread_function, &workerArgs[i]);
if (errno) DIE_MSG_ERRNO("pthread_create() failed");
}
......@@ -124,8 +129,10 @@ Runtime::~Runtime() {
DBG("Runtime " << this << " terminated");
}
auto Runtime::workerLoop(void* voidWorkerId) -> void* {
workerId = *(workerid_t*)voidWorkerId;
auto Runtime::workerLoop(struct WorkerArgs* workerArgs) -> void* {
workerId = workerArgs->id;
seed = workerArgs->seed;
LOGD("Worker loop started by thread " << syscall(SYS_gettid));
int oldType;
......@@ -134,9 +141,6 @@ auto Runtime::workerLoop(void* voidWorkerId) -> void* {
DIE_MSG_ERRNO("pthread_setcanceltype() failed");
}
// Initialze the workers PRNG seed.
seed = uniformIntDistribution(randomEngine);
for (const auto& f : newWorkerHooks) f();
workerLatch.count_down_and_wait();
......
......@@ -44,12 +44,18 @@ class Runtime : public Logger<LogSubsystem::RUNTI> {
Dispatcher& dispatcher;
ContextManager& contextManager;
pthread_t* threads;
workerid_t* workerIds;
// Arguments passed to a new worker thread
struct WorkerArgs {
workerid_t id;
unsigned int seed;
};
struct WorkerArgs* workerArgs;
std::default_random_engine randomEngine;
std::uniform_int_distribution<unsigned int> uniformIntDistribution;
auto workerLoop(void* workerId) -> void*;
auto workerLoop(struct WorkerArgs* workerArgs) -> void*;
std::mutex workerSleepMutex;
std::condition_variable workerSleepConditionVariable;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment