commit 7f4b3def67ffaecbfafe85e47f53c0a2af4939c1 Author: Thomas Munro Date: Sun Aug 14 10:48:58 2016 +1200 Barriers! diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f13f9c1..0f375c4 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -41,6 +41,7 @@ #include "commands/tablespace.h" #include "miscadmin.h" #include "pgstat.h" +#include "port/atomics.h" #include "postmaster/bgwriter.h" #include "postmaster/walwriter.h" #include "postmaster/startup.h" @@ -51,7 +52,6 @@ #include "replication/snapbuild.h" #include "replication/walreceiver.h" #include "replication/walsender.h" -#include "storage/barrier.h" #include "storage/bufmgr.h" #include "storage/fd.h" #include "storage/ipc.h" diff --git a/src/backend/main/main.c b/src/backend/main/main.c index c018c90..3707998 100644 --- a/src/backend/main/main.c +++ b/src/backend/main/main.c @@ -33,8 +33,8 @@ #include "bootstrap/bootstrap.h" #include "common/username.h" +#include "port/atomics.h" #include "postmaster/postmaster.h" -#include "storage/barrier.h" #include "storage/s_lock.h" #include "storage/spin.h" #include "tcop/tcopprot.h" diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index 699c934..857a47e 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -16,9 +16,9 @@ #include "miscadmin.h" #include "libpq/pqsignal.h" +#include "port/atomics.h" #include "postmaster/bgworker_internals.h" #include "postmaster/postmaster.h" -#include "storage/barrier.h" #include "storage/dsm.h" #include "storage/ipc.h" #include "storage/latch.h" diff --git a/src/backend/storage/ipc/Makefile b/src/backend/storage/ipc/Makefile index 8a55392..9dbdc26 100644 --- a/src/backend/storage/ipc/Makefile +++ b/src/backend/storage/ipc/Makefile @@ -8,7 +8,7 @@ subdir = src/backend/storage/ipc top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global -OBJS = dsm_impl.o dsm.o ipc.o ipci.o latch.o pmsignal.o procarray.o \ +OBJS = barrier.o dsm_impl.o dsm.o ipc.o ipci.o latch.o pmsignal.o procarray.o \ procsignal.o shmem.o shmqueue.o shm_mq.o shm_toc.o sinval.o \ sinvaladt.o standby.o diff --git a/src/backend/storage/ipc/barrier.c b/src/backend/storage/ipc/barrier.c new file mode 100644 index 0000000..8ea5aff --- /dev/null +++ b/src/backend/storage/ipc/barrier.c @@ -0,0 +1,92 @@ +/*------------------------------------------------------------------------- + * + * barrier.c + * Barriers for synchronizing workers. + * + * Portions Copyright (c) 2016, PostgreSQL Global Development Group + * + * This simple mechanism allows for simple cases of phase-based + * fork/join-style cooperation by a static set of workers. + * + * IDENTIFICATION + * src/backend/storage/ipc/barrier.c + * + *------------------------------------------------------------------------- + */ + +#include "storage/barrier.h" + +/* + * Initialize this barrier, setting the number of workers that we will wait + * for at each computation phase. + */ +void +BarrierInit(Barrier *barrier, int num_workers) +{ + SpinLockInit(&barrier->mutex); + barrier->num_workers = num_workers; + barrier->num_arrived = 0; + barrier->sense = false; + ConditionVariableInit(&barrier->condition_variable); +} + +/* + * Wait for all workers to arrive at this barrier, and then return in all + * workers. + * + * Returns true in one arbitrarily selected worker (currently the last one to + * arrive). Returns false in all others. The differing return code can be + * used to coordinate a phase of work that must be done in only one worker + * while the others wait. + * + * TODO: When Michael Paquier's patch at + * https://commitfest.postgresql.org/10/629/ lands, then this function should + * take an event ID and it should be passed through the conditional variable + * wait and thence to the WaitLatch so that we can see joinpoint names show up + * in all their glory in pg_stat_activity! + * + * TODO: How should conditions like postmaster death, or being killed by the a + * parallel context owner/leader (if there is one), be handled? Should this + * component be usable in contexts other than parallel workers? + */ +bool +BarrierWait(Barrier *barrier) +{ + bool sense; + bool release; + + SpinLockAcquire(&barrier->mutex); + ++barrier->num_arrived; + if (barrier->num_arrived == barrier->num_workers) + { + release = true; + barrier->num_arrived = 0; + barrier->sense = !barrier->sense; + } + else + { + release = false; + sense = barrier->sense; + } + SpinLockRelease(&barrier->mutex); + + if (release) + { + ConditionVariableBroadcast(&barrier->condition_variable); + return true; + } + + for (;;) + { + ConditionVariablePrepareToSleep(&barrier->condition_variable); + SpinLockAcquire(&barrier->mutex); + release = barrier->sense != sense; + SpinLockRelease(&barrier->mutex); + if (release) + break; + ConditionVariableSleep(); + } + ConditionVariableCancelSleep(); + + return false; +} diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c index 9def8a1..0268d35 100644 --- a/src/backend/storage/ipc/latch.c +++ b/src/backend/storage/ipc/latch.c @@ -55,9 +55,9 @@ #endif #include "miscadmin.h" +#include "port/atomics.h" #include "portability/instr_time.h" #include "postmaster/postmaster.h" -#include "storage/barrier.h" #include "storage/latch.h" #include "storage/pmsignal.h" #include "storage/shmem.h" diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c index 55248c2..a065212 100644 --- a/src/backend/storage/ipc/shm_toc.c +++ b/src/backend/storage/ipc/shm_toc.c @@ -13,7 +13,7 @@ #include "postgres.h" -#include "storage/barrier.h" +#include "port/atomics.h" #include "storage/shm_toc.h" #include "storage/spin.h" diff --git a/src/backend/storage/lmgr/s_lock.c b/src/backend/storage/lmgr/s_lock.c index 599940c..6f81838 100644 --- a/src/backend/storage/lmgr/s_lock.c +++ b/src/backend/storage/lmgr/s_lock.c @@ -51,7 +51,7 @@ #include #include "storage/s_lock.h" -#include "storage/barrier.h" +#include "port/atomics.h" #define MIN_SPINS_PER_DELAY 10 diff --git a/src/include/pgstat.h b/src/include/pgstat.h index dc3320d..1f899a8 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -14,9 +14,9 @@ #include "datatype/timestamp.h" #include "fmgr.h" #include "libpq/pqcomm.h" +#include "port/atomics.h" #include "portability/instr_time.h" #include "postmaster/pgarch.h" -#include "storage/barrier.h" #include "storage/proc.h" #include "utils/hsearch.h" #include "utils/relcache.h" diff --git a/src/include/storage/barrier.h b/src/include/storage/barrier.h index 6202e57..b3ebd43 100644 --- a/src/include/storage/barrier.h +++ b/src/include/storage/barrier.h @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * * barrier.h - * Memory barrier operations. + * Barriers for synchronizing workers. * * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California @@ -14,10 +14,26 @@ #define BARRIER_H /* - * This used to be a separate file, full of compiler/architecture - * dependent defines, but it's not included in the atomics.h - * infrastructure and just kept for backward compatibility. + * For the header previously known as "barrier.h", please include + * "port/atomics.h", which deals with atomics, compiler barriers and memory + * barriers. */ -#include "port/atomics.h" + +#include "postgres.h" + +#include "storage/condition_variable.h" +#include "storage/spin.h" + +typedef struct Barrier +{ + slock_t mutex; + bool sense; + int num_workers; + int num_arrived; + ConditionVariable condition_variable; +} Barrier; + +extern void BarrierInit(Barrier *barrier, int num_workers); +extern bool BarrierWait(Barrier *barrier); #endif /* BARRIER_H */