#define THREAD_JOIN(handle) \
(WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0 ? \
GETERRNO() : CloseHandle(handle) ? 0 : GETERRNO())
+#define THREAD_BARRIER_T SYNCHRONIZATION_BARRIER
+#define THREAD_BARRIER_INIT(barrier, n) \
+ (InitializeSynchronizationBarrier((barrier), (n), 0) ? 0 : GETERRNO())
+#define THREAD_BARRIER_WAIT(barrier) \
+ EnterSynchronizationBarrier((barrier), \
+ SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY)
+#define THREAD_BARRIER_DESTROY(barrier)
#elif defined(ENABLE_THREAD_SAFETY)
/* Use POSIX threads */
+#include "port/pg_pthread.h"
#define THREAD_T pthread_t
#define THREAD_FUNC_RETURN_TYPE void *
#define THREAD_FUNC_RETURN return NULL
pthread_create((handle), NULL, (function), (arg))
#define THREAD_JOIN(handle) \
pthread_join((handle), NULL)
+#define THREAD_BARRIER_T pthread_barrier_t
+#define THREAD_BARRIER_INIT(barrier, n) \
+ pthread_barrier_init((barrier), NULL, (n))
+#define THREAD_BARRIER_WAIT(barrier) pthread_barrier_wait((barrier))
+#define THREAD_BARRIER_DESTROY(barrier) pthread_barrier_destroy((barrier))
#else
/* No threads implementation, use none (-j 1) */
#define THREAD_T void *
#define THREAD_FUNC_RETURN_TYPE void *
#define THREAD_FUNC_RETURN return NULL
+#define THREAD_BARRIER_T int
+#define THREAD_BARRIER_INIT(barrier, n) (*(barrier) = 0)
+#define THREAD_BARRIER_WAIT(barrier)
+#define THREAD_BARRIER_DESTROY(barrier)
#endif
/* Various random sequences are initialized from this one. */
static RandomState base_random_sequence;
+/* Synchronization barrier for start and connection */
+static THREAD_BARRIER_T barrier;
+
/*
* Connection state machine states.
*/
if (duration > 0)
setalarm(duration);
+ errno = THREAD_BARRIER_INIT(&barrier, nthreads);
+ if (errno != 0)
+ pg_log_fatal("could not initialize barrier: %m");
+
#ifdef ENABLE_THREAD_SAFETY
/* start all threads but thread 0 which is executed directly later */
for (i = 1; i < nthreads; i++)
printResults(&stats, pg_time_now() - bench_start, conn_total_duration,
bench_start - start_time, latency_late);
+ THREAD_BARRIER_DESTROY(&barrier);
+
if (exit_code != 0)
pg_log_fatal("Run was aborted; the above results are incomplete.");
state[i].state = CSTATE_CHOOSE_SCRIPT;
/* READY */
+ THREAD_BARRIER_WAIT(&barrier);
+
thread_start = pg_time_now();
thread->started_time = thread_start;
last_report = thread_start;
for (int i = 0; i < nstate; i++)
{
if ((state[i].con = doConnect()) == NULL)
+ {
+ /*
+ * On connection failure, we meet the barrier here in place of
+ * GO before proceeding to the "done" path which will cleanup,
+ * so as to avoid locking the process.
+ *
+ * It is unclear whether it is worth doing anything rather than
+ * coldly exiting with an error message.
+ */
+ THREAD_BARRIER_WAIT(&barrier);
goto done;
+ }
}
/* compute connection delay */
thread->conn_duration = 0;
}
+ /* GO */
+ THREAD_BARRIER_WAIT(&barrier);
start = pg_time_now();
thread->bench_start = start;