From 44bf3d5083e151d772c5d6f656e3e162f573dced Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Wed, 10 Mar 2021 15:40:17 +1300 Subject: [PATCH] Add missing pthread_barrier_t. Supply a simple implementation of the missing pthread_barrier_t type and functions, for macOS. Discussion: https://postgr.es/m/20200227180100.zyvjwzcpiokfsqm2%40alap3.anarazel.de --- configure | 69 ++++++++++++++++++++++++++++ configure.ac | 2 + src/include/pg_config.h.in | 3 ++ src/include/port/pg_pthread.h | 41 +++++++++++++++++ src/port/pthread_barrier_wait.c | 79 ++++++++++++++++++++++++++++++++ src/tools/msvc/Solution.pm | 1 + src/tools/pgindent/typedefs.list | 1 + 7 files changed, 196 insertions(+) create mode 100644 src/include/port/pg_pthread.h create mode 100644 src/port/pthread_barrier_wait.c diff --git a/configure b/configure index ce9ea36999..fad817bb38 100755 --- a/configure +++ b/configure @@ -11635,6 +11635,62 @@ if test "$ac_res" != no; then : fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_barrier_wait" >&5 +$as_echo_n "checking for library containing pthread_barrier_wait... " >&6; } +if ${ac_cv_search_pthread_barrier_wait+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_barrier_wait (); +int +main () +{ +return pthread_barrier_wait (); + ; + return 0; +} +_ACEOF +for ac_lib in '' pthread; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_pthread_barrier_wait=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_pthread_barrier_wait+:} false; then : + break +fi +done +if ${ac_cv_search_pthread_barrier_wait+:} false; then : + +else + ac_cv_search_pthread_barrier_wait=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_barrier_wait" >&5 +$as_echo "$ac_cv_search_pthread_barrier_wait" >&6; } +ac_res=$ac_cv_search_pthread_barrier_wait +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + # Solaris: { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing fdatasync" >&5 $as_echo_n "checking for library containing fdatasync... " >&6; } @@ -15883,6 +15939,19 @@ esac fi +ac_fn_c_check_func "$LINENO" "pthread_barrier_wait" "ac_cv_func_pthread_barrier_wait" +if test "x$ac_cv_func_pthread_barrier_wait" = xyes; then : + $as_echo "#define HAVE_PTHREAD_BARRIER_WAIT 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" pthread_barrier_wait.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS pthread_barrier_wait.$ac_objext" + ;; +esac + +fi + ac_fn_c_check_func "$LINENO" "pwrite" "ac_cv_func_pwrite" if test "x$ac_cv_func_pwrite" = xyes; then : $as_echo "#define HAVE_PWRITE 1" >>confdefs.h diff --git a/configure.ac b/configure.ac index f54f65febe..0ed53571dd 100644 --- a/configure.ac +++ b/configure.ac @@ -1143,6 +1143,7 @@ AC_SEARCH_LIBS(getopt_long, [getopt gnugetopt]) AC_SEARCH_LIBS(shm_open, rt) AC_SEARCH_LIBS(shm_unlink, rt) AC_SEARCH_LIBS(clock_gettime, [rt posix4]) +AC_SEARCH_LIBS(pthread_barrier_wait, pthread) # Solaris: AC_SEARCH_LIBS(fdatasync, [rt posix4]) # Required for thread_test.c on Solaris @@ -1743,6 +1744,7 @@ AC_REPLACE_FUNCS(m4_normalize([ mkdtemp pread preadv + pthread_barrier_wait pwrite pwritev random diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index 04dc330119..7a7cc21d8d 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -424,6 +424,9 @@ /* Define if you have POSIX threads libraries and header files. */ #undef HAVE_PTHREAD +/* Define to 1 if you have the `pthread_barrier_wait' function. */ +#undef HAVE_PTHREAD_BARRIER_WAIT + /* Define to 1 if you have the `pthread_is_threaded_np' function. */ #undef HAVE_PTHREAD_IS_THREADED_NP diff --git a/src/include/port/pg_pthread.h b/src/include/port/pg_pthread.h new file mode 100644 index 0000000000..d102ce9d6f --- /dev/null +++ b/src/include/port/pg_pthread.h @@ -0,0 +1,41 @@ +/*------------------------------------------------------------------------- + * + * Declarations for missing POSIX thread components. + * + * Currently this supplies an implementation of pthread_barrier_t for the + * benefit of macOS, which lacks it. These declarations are not in port.h, + * because that'd require to be included by every translation + * unit. + * + *------------------------------------------------------------------------- + */ + +#ifndef PG_PTHREAD_H +#define PG_PTHREAD_H + +#include + +#ifndef HAVE_PTHREAD_BARRIER_WAIT + +#ifndef PTHREAD_BARRIER_SERIAL_THREAD +#define PTHREAD_BARRIER_SERIAL_THREAD (-1) +#endif + +typedef struct pg_pthread_barrier +{ + bool sense; /* we only need a one bit phase */ + int count; /* number of threads expected */ + int arrived; /* number of threads that have arrived */ + pthread_mutex_t mutex; + pthread_cond_t cond; +} pthread_barrier_t; + +extern int pthread_barrier_init(pthread_barrier_t *barrier, + const void *attr, + int count); +extern int pthread_barrier_wait(pthread_barrier_t *barrier); +extern int pthread_barrier_destroy(pthread_barrier_t *barrier); + +#endif + +#endif diff --git a/src/port/pthread_barrier_wait.c b/src/port/pthread_barrier_wait.c new file mode 100644 index 0000000000..7ca8e2ce0b --- /dev/null +++ b/src/port/pthread_barrier_wait.c @@ -0,0 +1,79 @@ +/*------------------------------------------------------------------------- + * + * pthread_barrier_wait.c + * Implementation of pthread_barrier_t support for platforms lacking it. + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/port/pthread_barrier_wait.c + * + *------------------------------------------------------------------------- + */ + +#include "c.h" + +#include "port/pg_pthread.h" + +int +pthread_barrier_init(pthread_barrier_t *barrier, const void *attr, int count) +{ + barrier->sense = false; + barrier->count = count; + barrier->arrived = 0; + if (pthread_cond_init(&barrier->cond, NULL) < 0) + return -1; + if (pthread_mutex_init(&barrier->mutex, NULL) < 0) + { + int save_errno = errno; + + pthread_cond_destroy(&barrier->cond); + errno = save_errno; + + return -1; + } + + return 0; +} + +int +pthread_barrier_wait(pthread_barrier_t *barrier) +{ + bool initial_sense; + + pthread_mutex_lock(&barrier->mutex); + + /* We have arrived at the barrier. */ + barrier->arrived++; + Assert(barrier->arrived <= barrier->count); + + /* If we were the last to arrive, release the others and return. */ + if (barrier->arrived == barrier->count) + { + barrier->arrived = 0; + barrier->sense = !barrier->sense; + pthread_mutex_unlock(&barrier->mutex); + pthread_cond_broadcast(&barrier->cond); + + return PTHREAD_BARRIER_SERIAL_THREAD; + } + + /* Wait for someone else to flip the sense. */ + initial_sense = barrier->sense; + do + { + pthread_cond_wait(&barrier->cond, &barrier->mutex); + } while (barrier->sense == initial_sense); + + pthread_mutex_unlock(&barrier->mutex); + + return 0; +} + +int +pthread_barrier_destroy(pthread_barrier_t *barrier) +{ + pthread_cond_destroy(&barrier->cond); + pthread_mutex_destroy(&barrier->mutex); + return 0; +} diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm index 69b08591cc..a4f5cc4bdb 100644 --- a/src/tools/msvc/Solution.pm +++ b/src/tools/msvc/Solution.pm @@ -333,6 +333,7 @@ sub GenerateFiles HAVE_PSTAT => undef, HAVE_PS_STRINGS => undef, HAVE_PTHREAD => undef, + HAVE_PTHREAD_BARRIER_WAIT => undef, HAVE_PTHREAD_IS_THREADED_NP => undef, HAVE_PTHREAD_PRIO_INHERIT => undef, HAVE_PWRITE => undef, diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index c85ab814d4..e4d2debb3c 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -3295,6 +3295,7 @@ proclist_mutable_iter proclist_node promptStatus_t pthread_attr_t +pthread_barrier_t pthread_key_t pthread_mutex_t pthread_once_t