diff --git a/configure b/configure index 7c86be3c3d..a1d6081b96 100755 --- a/configure +++ b/configure @@ -12892,7 +12892,7 @@ fi LIBS_including_readline="$LIBS" LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` -for ac_func in cbrt clock_gettime dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l +for ac_func in cbrt clock_gettime dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pselect pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/configure.in b/configure.in index e92494e12d..83e53618e6 100644 --- a/configure.in +++ b/configure.in @@ -1429,7 +1429,7 @@ PGAC_FUNC_WCSTOMBS_L LIBS_including_readline="$LIBS" LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` -AC_CHECK_FUNCS([cbrt clock_gettime dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l]) +AC_CHECK_FUNCS([cbrt clock_gettime dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pselect pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l]) AC_REPLACE_FUNCS(fseeko) case $host_os in diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 2bb4380533..7b9f444dc1 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -614,9 +614,9 @@ PostmasterMain(int argc, char *argv[]) * In the postmaster, we want to install non-ignored handlers *without* * SA_RESTART. This is because they'll be blocked at all times except * when ServerLoop is waiting for something to happen, and during that - * window, we want signals to exit the select(2) wait so that ServerLoop + * window, we want signals to exit the pselect(2) wait so that ServerLoop * can respond if anything interesting happened. On some platforms, - * signals marked SA_RESTART would not cause the select() wait to end. + * signals marked SA_RESTART would not cause the pselect() wait to end. * Child processes will generally want SA_RESTART, but we expect them to * set up their own handlers before unblocking signals. * @@ -1670,6 +1670,8 @@ ServerLoop(void) for (;;) { fd_set rmask; + fd_set *rmask_p; + struct timeval timeout; int selres; time_t now; @@ -1679,37 +1681,64 @@ ServerLoop(void) * We block all signals except while sleeping. That makes it safe for * signal handlers, which again block all signals while executing, to * do nontrivial work. - * - * If we are in PM_WAIT_DEAD_END state, then we don't want to accept - * any new connections, so we don't call select(), and just sleep. */ - memcpy((char *) &rmask, (char *) &readmask, sizeof(fd_set)); - if (pmState == PM_WAIT_DEAD_END) { - PG_SETMASK(&UnBlockSig); - - pg_usleep(100000L); /* 100 msec seems reasonable */ - selres = 0; - - PG_SETMASK(&BlockSig); + /* + * If we are in PM_WAIT_DEAD_END state, then we don't want to + * accept any new connections, so pass a null rmask. + */ + rmask_p = NULL; + timeout.tv_sec = 0; + timeout.tv_usec = 100000; /* 100 msec seems reasonable */ } else { - /* must set timeout each time; some OSes change it! */ - struct timeval timeout; + /* Normal case: check sockets, and compute a suitable timeout */ + memcpy(&rmask, &readmask, sizeof(fd_set)); + rmask_p = &rmask; /* Needs to run with blocked signals! */ DetermineSleepTime(&timeout); - - PG_SETMASK(&UnBlockSig); - - selres = select(nSockets, &rmask, NULL, NULL, &timeout); - - PG_SETMASK(&BlockSig); } - /* Now check the select() result */ + /* + * We prefer to wait with pselect(2) if available, as using that, + * together with *not* using SA_RESTART for signals, guarantees that + * we will get kicked off the wait if a signal occurs. + * + * If we lack pselect(2), fake it with select(2). This has a race + * condition: a signal that was already pending will be delivered + * before we reach the select(), and therefore the select() will wait, + * even though we might wish to do something in response. Therefore, + * beware of putting any time-critical signal response logic into + * ServerLoop rather than into the signal handler itself. It will run + * eventually, but maybe not till after a timeout delay. + * + * Some implementations of pselect() are reportedly not atomic, making + * the first alternative here functionally equivalent to the second. + * Not much we can do about that though. + */ + { +#ifdef HAVE_PSELECT + /* pselect uses a randomly different timeout API, sigh */ + struct timespec ptimeout; + + ptimeout.tv_sec = timeout.tv_sec; + ptimeout.tv_nsec = timeout.tv_usec * 1000; + + selres = pselect(nSockets, rmask_p, NULL, NULL, + &ptimeout, &UnBlockSig); +#else + PG_SETMASK(&UnBlockSig); + + selres = select(nSockets, rmask_p, NULL, NULL, &timeout); + + PG_SETMASK(&BlockSig); +#endif + } + + /* Now check the select()/pselect() result */ if (selres < 0) { if (errno != EINTR && errno != EWOULDBLOCK) diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index 7a05c7e5b8..75e511cfb6 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -400,6 +400,9 @@ /* Define to 1 if the assembler supports PPC's LWARX mutex hint bit. */ #undef HAVE_PPC_LWARX_MUTEX_HINT +/* Define to 1 if you have the `pselect' function. */ +#undef HAVE_PSELECT + /* Define to 1 if you have the `pstat' function. */ #undef HAVE_PSTAT diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32 index 2a5fc1bab7..91d8f61edf 100644 --- a/src/include/pg_config.h.win32 +++ b/src/include/pg_config.h.win32 @@ -267,6 +267,9 @@ /* Define to 1 if you have the header file. */ /* #undef HAVE_POLL_H */ +/* Define to 1 if you have the `pselect' function. */ +/* #undef HAVE_PSELECT */ + /* Define to 1 if you have the `pstat' function. */ /* #undef HAVE_PSTAT */