Use atomics to protect libovni process state

Multiple threads may attempt to initialize or finalize the process, so
we keep the state stored in an atomic integer to protect against bad
usage.
This commit is contained in:
Rodrigo Arias 2024-09-13 08:35:33 +02:00
parent ceaac3bcf0
commit f6fc166a38

View File

@ -5,6 +5,8 @@
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
#include <limits.h> #include <limits.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -19,6 +21,13 @@
#include "version.h" #include "version.h"
#include "utlist.h" #include "utlist.h"
enum {
ST_UNINIT = 0,
ST_INIT,
ST_READY,
ST_GONE,
};
struct ovni_rcpu { struct ovni_rcpu {
int index; int index;
int phyid; int phyid;
@ -73,8 +82,7 @@ struct ovni_rproc {
int rank; int rank;
int nranks; int nranks;
int ready; atomic_int st;
int finished;
JSON_Value *meta; JSON_Value *meta;
}; };
@ -171,8 +179,8 @@ ovni_add_cpu(int index, int phyid)
if (phyid < 0) if (phyid < 0)
die("cannot use negative CPU id %d", phyid); die("cannot use negative CPU id %d", phyid);
if (!rproc.ready) if (rproc.st != ST_READY)
die("process not yet initialized"); die("process not ready");
if (!rthread.ready) if (!rthread.ready)
die("thread not yet initialized"); die("thread not yet initialized");
@ -190,8 +198,8 @@ ovni_add_cpu(int index, int phyid)
void void
ovni_proc_set_rank(int rank, int nranks) ovni_proc_set_rank(int rank, int nranks)
{ {
if (!rproc.ready) if (rproc.st != ST_READY)
die("process not yet initialized"); die("process not ready");
rproc.rank_set = 1; rproc.rank_set = 1;
rproc.rank = rank; rproc.rank = rank;
@ -237,13 +245,19 @@ create_proc_dir(const char *loom, int pid)
void void
ovni_proc_init(int app, const char *loom, int pid) ovni_proc_init(int app, const char *loom, int pid)
{ {
if (rproc.ready) /* Protect against two threads calling at the same time */
int st = ST_UNINIT;
bool was_uninit = atomic_compare_exchange_strong(&rproc.st,
&st, ST_INIT);
if (!was_uninit) {
if (st == ST_INIT)
die("pid %d already being initialized", pid);
else if (st == ST_READY)
die("pid %d already initialized", pid); die("pid %d already initialized", pid);
else if (st == ST_GONE)
if (rproc.finished)
die("pid %d has finished, cannot init again", pid); die("pid %d has finished, cannot init again", pid);
}
memset(&rproc, 0, sizeof(rproc));
if (strlen(loom) >= OVNI_MAX_HOSTNAME) if (strlen(loom) >= OVNI_MAX_HOSTNAME)
die("loom name too long: %s", loom); die("loom name too long: %s", loom);
@ -255,7 +269,7 @@ ovni_proc_init(int app, const char *loom, int pid)
create_proc_dir(loom, pid); create_proc_dir(loom, pid);
rproc.ready = 1; rproc.st = ST_READY;
} }
static int static int
@ -353,18 +367,19 @@ try_clean_dir(const char *dir)
void void
ovni_proc_fini(void) ovni_proc_fini(void)
{ {
if (!rproc.ready) /* Protect against two threads calling at the same time */
die("process not initialized"); int st = ST_READY;
bool was_ready = atomic_compare_exchange_strong(&rproc.st,
&st, ST_GONE);
if (!was_ready)
die("process not ready");
if (rproc.move_to_final) { if (rproc.move_to_final) {
try_clean_dir(rproc.procdir); try_clean_dir(rproc.procdir);
try_clean_dir(rproc.loomdir); try_clean_dir(rproc.loomdir);
try_clean_dir(rproc.tmpdir); try_clean_dir(rproc.tmpdir);
} }
/* Mark the process no longer ready */
rproc.finished = 1;
rproc.ready = 0;
} }
static void static void
@ -516,8 +531,8 @@ ovni_thread_init(pid_t tid)
if (tid == 0) if (tid == 0)
die("cannot use tid=%d", tid); die("cannot use tid=%d", tid);
if (!rproc.ready) if (rproc.st != ST_READY)
die("process not yet initialized"); die("process not ready");
memset(&rthread, 0, sizeof(rthread)); memset(&rthread, 0, sizeof(rthread));
@ -751,8 +766,8 @@ ovni_flush(void)
if (!rthread.ready) if (!rthread.ready)
die("thread is not initialized"); die("thread is not initialized");
if (!rproc.ready) if (rproc.st != ST_READY)
die("process is not initialized"); die("process not ready");
ovni_ev_set_clock(&pre, ovni_clock_now()); ovni_ev_set_clock(&pre, ovni_clock_now());
ovni_ev_set_mcv(&pre, "OF["); ovni_ev_set_mcv(&pre, "OF[");