*
* This code is released under the terms of the PostgreSQL License.
*
- * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* src/test/regress/pg_regress.c
*-------------------------------------------------------------------------
*/
-#include "pg_regress.h"
+#include "postgres_fe.h"
#include <ctype.h>
#include <sys/stat.h>
#include <sys/resource.h>
#endif
+#include "common/logging.h"
#include "common/restricted_token.h"
#include "common/username.h"
#include "getopt_long.h"
#include "libpq/pqcomm.h" /* needed for UNIXSOCK_PATH() */
#include "pg_config_paths.h"
+#include "pg_regress.h"
+#include "portability/instr_time.h"
/* for resultmap we need a list of pairs of strings */
typedef struct _resultmap
*/
#ifndef WIN32
const char *basic_diff_opts = "";
-const char *pretty_diff_opts = "-C3";
+const char *pretty_diff_opts = "-U3";
#else
const char *basic_diff_opts = "-w";
-const char *pretty_diff_opts = "-w -C3";
+const char *pretty_diff_opts = "-w -U3";
#endif
/* options settable from command line */
static _stringlist *loadlanguage = NULL;
static _stringlist *loadextension = NULL;
static int max_connections = 0;
+static int max_concurrent_tests = 0;
static char *encoding = NULL;
static _stringlist *schedulelist = NULL;
static _stringlist *extra_tests = NULL;
fflush(stderr);
snprintf(buf, sizeof(buf),
- "\"%s%spg_ctl\" stop -D \"%s/data\" -s -m fast",
+ "\"%s%spg_ctl\" stop -D \"%s/data\" -s",
bindir ? bindir : "",
bindir ? "/" : "",
temp_instance);
return temp_sockdir;
}
-#endif /* HAVE_UNIX_SOCKETS */
+#endif /* HAVE_UNIX_SOCKETS */
/*
* Check whether string matches pattern
* NOTE: Assumes there is enough room in the target buffer!
*/
void
-replace_string(char *string, char *replace, char *replacement)
+replace_string(char *string, const char *replace, const char *replacement)
{
char *ptr;
* the given suffix.
*/
static void
-convert_sourcefiles_in(char *source_subdir, char *dest_dir, char *dest_subdir, char *suffix)
+convert_sourcefiles_in(const char *source_subdir, const char *dest_dir, const char *dest_subdir, const char *suffix)
{
char testtablespace[MAXPGPATH];
char indir[MAXPGPATH];
static void
initialize_environment(void)
{
+ /*
+ * Set default application_name. (The test_function may choose to
+ * override this, but if it doesn't, we have something useful in place.)
+ */
putenv("PGAPPNAME=pg_regress");
if (nolocale)
if (user != NULL)
doputenv("PGUSER", user);
+ /*
+ * However, we *don't* honor PGDATABASE, since we certainly don't wish
+ * to connect to whatever database the user might like as default.
+ * (Most tests override PGDATABASE anyway, but there are some ECPG
+ * test cases that don't.)
+ */
+ unsetenv("PGDATABASE");
+
/*
* Report what we're connecting to
*/
load_resultmap();
}
-pg_attribute_unused()
+#ifdef ENABLE_SSPI
+
+/* support for config_sspi_auth() */
static const char *
fmtHba(const char *raw)
{
return ret;
}
-#ifdef ENABLE_SSPI
/*
* Get account and domain/realm names for the current user. This is based on
* pg_SSPI_recvauth(). The returned strings use static storage.
* Rewrite pg_hba.conf and pg_ident.conf to use SSPI authentication. Permit
* the current OS user to authenticate as the bootstrap superuser and as any
* user named in a --create-role option.
+ *
+ * In --config-auth mode, the --user switch can be used to specify the
+ * bootstrap superuser's name, otherwise we assume it is the default.
*/
static void
-config_sspi_auth(const char *pgdata)
+config_sspi_auth(const char *pgdata, const char *superuser_name)
{
const char *accountname,
*domainname;
- const char *username;
char *errstr;
bool have_ipv6;
char fname[MAXPGPATH];
*ident;
_stringlist *sl;
- /*
- * "username", the initdb-chosen bootstrap superuser name, may always
- * match "accountname", the value SSPI authentication discovers. The
- * underlying system functions do not clearly guarantee that.
- */
+ /* Find out the name of the current OS user */
current_windows_user(&accountname, &domainname);
- username = get_user_name(&errstr);
- if (username == NULL)
+
+ /* Determine the bootstrap superuser's name */
+ if (superuser_name == NULL)
{
- fprintf(stderr, "%s: %s\n", progname, errstr);
- exit(2);
+ /*
+ * Compute the default superuser name the same way initdb does.
+ *
+ * It's possible that this result always matches "accountname", the
+ * value SSPI authentication discovers. But the underlying system
+ * functions do not clearly guarantee that.
+ */
+ superuser_name = get_user_name(&errstr);
+ if (superuser_name == NULL)
+ {
+ fprintf(stderr, "%s: %s\n", progname, errstr);
+ exit(2);
+ }
}
/*
} while (0)
res = snprintf(fname, sizeof(fname), "%s/pg_hba.conf", pgdata);
- if (res < 0 || res >= sizeof(fname) - 1)
+ if (res < 0 || res >= sizeof(fname))
{
/*
* Truncating this name is a fatal error, because we must not fail to
* bother escaping embedded double-quote characters.
*/
CW(fprintf(ident, "regress \"%s@%s\" %s\n",
- accountname, domainname, fmtHba(username)) >= 0);
+ accountname, domainname, fmtHba(superuser_name)) >= 0);
for (sl = extraroles; sl; sl = sl->next)
CW(fprintf(ident, "regress \"%s@%s\" %s\n",
accountname, domainname, fmtHba(sl->str)) >= 0);
CW(fclose(ident) == 0);
}
-#endif
+
+#endif /* ENABLE_SSPI */
/*
* Issue a command via psql, connecting to the specified database
cmdline2 = psprintf("cmd /c \"%s\"", cmdline);
if ((restrictedToken =
- CreateRestrictedProcess(cmdline2, &pi, progname)) == 0)
+ CreateRestrictedProcess(cmdline2, &pi)) == 0)
exit(2);
CloseHandle(pi.hThread);
* Use the best comparison file to generate the "pretty" diff, which we
* append to the diffs summary file.
*/
- snprintf(cmd, sizeof(cmd),
- "diff %s \"%s\" \"%s\" >> \"%s\"",
- pretty_diff_opts, best_expect_file, resultsfile, difffilename);
- run_diff(cmd, difffilename);
- /* And append a separator */
+ /* Write diff header */
difffile = fopen(difffilename, "a");
if (difffile)
{
fprintf(difffile,
- "\n======================================================================\n\n");
+ "diff %s %s %s\n",
+ pretty_diff_opts, best_expect_file, resultsfile);
fclose(difffile);
}
+ /* Run diff */
+ snprintf(cmd, sizeof(cmd),
+ "diff %s \"%s\" \"%s\" >> \"%s\"",
+ pretty_diff_opts, best_expect_file, resultsfile, difffilename);
+ run_diff(cmd, difffilename);
+
unlink(diff);
return true;
}
/*
* Wait for specified subprocesses to finish, and return their exit
- * statuses into statuses[]
+ * statuses into statuses[] and stop times into stoptimes[]
*
* If names isn't NULL, print each subprocess's name as it finishes
*
* Note: it's OK to scribble on the pids array, but not on the names array
*/
static void
-wait_for_tests(PID_TYPE * pids, int *statuses, char **names, int num_tests)
+wait_for_tests(PID_TYPE * pids, int *statuses, instr_time *stoptimes,
+ char **names, int num_tests)
{
int tests_left;
int i;
p = active_pids[r - WAIT_OBJECT_0];
/* compact the active_pids array */
active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1];
-#endif /* WIN32 */
+#endif /* WIN32 */
for (i = 0; i < num_tests; i++)
{
#endif
pids[i] = INVALID_PID;
statuses[i] = (int) exit_status;
+ INSTR_TIME_SET_CURRENT(stoptimes[i]);
if (names)
status(" %s", names[i]);
tests_left--;
#if defined(WIN32)
status(_(" (test process was terminated by exception 0x%X)"),
WTERMSIG(exitstatus));
-#elif defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST
- status(_(" (test process was terminated by signal %d: %s)"),
- WTERMSIG(exitstatus),
- WTERMSIG(exitstatus) < NSIG ?
- sys_siglist[WTERMSIG(exitstatus)] : "(unknown))");
#else
- status(_(" (test process was terminated by signal %d)"),
- WTERMSIG(exitstatus));
+ status(_(" (test process was terminated by signal %d: %s)"),
+ WTERMSIG(exitstatus), pg_strsignal(WTERMSIG(exitstatus)));
#endif
}
else
_stringlist *expectfiles[MAX_PARALLEL_TESTS];
_stringlist *tags[MAX_PARALLEL_TESTS];
PID_TYPE pids[MAX_PARALLEL_TESTS];
+ instr_time starttimes[MAX_PARALLEL_TESTS];
+ instr_time stoptimes[MAX_PARALLEL_TESTS];
int statuses[MAX_PARALLEL_TESTS];
_stringlist *ignorelist = NULL;
char scbuf[1024];
FILE *scf;
int line_num = 0;
- memset(resultfiles, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
- memset(expectfiles, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
- memset(tags, 0, sizeof(_stringlist *) * MAX_PARALLEL_TESTS);
+ memset(tests, 0, sizeof(tests));
+ memset(resultfiles, 0, sizeof(resultfiles));
+ memset(expectfiles, 0, sizeof(expectfiles));
+ memset(tags, 0, sizeof(tags));
scf = fopen(schedule, "r");
if (!scf)
line_num++;
- for (i = 0; i < MAX_PARALLEL_TESTS; i++)
- {
- if (resultfiles[i] == NULL)
- break;
- free_stringlist(&resultfiles[i]);
- free_stringlist(&expectfiles[i]);
- free_stringlist(&tags[i]);
- }
-
/* strip trailing whitespace, especially the newline */
i = strlen(scbuf);
while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
num_tests = 0;
inword = false;
- for (c = test; *c; c++)
+ for (c = test;; c++)
{
- if (isspace((unsigned char) *c))
+ if (*c == '\0' || isspace((unsigned char) *c))
{
- *c = '\0';
- inword = false;
+ if (inword)
+ {
+ /* Reached end of a test name */
+ char sav;
+
+ if (num_tests >= MAX_PARALLEL_TESTS)
+ {
+ fprintf(stderr, _("too many parallel tests (more than %d) in schedule file \"%s\" line %d: %s\n"),
+ MAX_PARALLEL_TESTS, schedule, line_num, scbuf);
+ exit(2);
+ }
+ sav = *c;
+ *c = '\0';
+ tests[num_tests] = pg_strdup(test);
+ num_tests++;
+ *c = sav;
+ inword = false;
+ }
+ if (*c == '\0')
+ break; /* loop exit is here */
}
else if (!inword)
{
- if (num_tests >= MAX_PARALLEL_TESTS)
- {
- /* can't print scbuf here, it's already been trashed */
- fprintf(stderr, _("too many parallel tests in schedule file \"%s\", line %d\n"),
- schedule, line_num);
- exit(2);
- }
- tests[num_tests] = c;
- num_tests++;
+ /* Start of a test name */
+ test = c;
inword = true;
}
}
if (num_tests == 1)
{
- status(_("test %-24s ... "), tests[0]);
+ status(_("test %-28s ... "), tests[0]);
pids[0] = (tfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]);
- wait_for_tests(pids, statuses, NULL, 1);
+ INSTR_TIME_SET_CURRENT(starttimes[0]);
+ wait_for_tests(pids, statuses, stoptimes, NULL, 1);
/* status line is finished below */
}
+ else if (max_concurrent_tests > 0 && max_concurrent_tests < num_tests)
+ {
+ fprintf(stderr, _("too many parallel tests (more than %d) in schedule file \"%s\" line %d: %s\n"),
+ max_concurrent_tests, schedule, line_num, scbuf);
+ exit(2);
+ }
else if (max_connections > 0 && max_connections < num_tests)
{
int oldest = 0;
if (i - oldest >= max_connections)
{
wait_for_tests(pids + oldest, statuses + oldest,
+ stoptimes + oldest,
tests + oldest, i - oldest);
oldest = i;
}
pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
+ INSTR_TIME_SET_CURRENT(starttimes[i]);
}
wait_for_tests(pids + oldest, statuses + oldest,
+ stoptimes + oldest,
tests + oldest, i - oldest);
status_end();
}
for (i = 0; i < num_tests; i++)
{
pids[i] = (tfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
+ INSTR_TIME_SET_CURRENT(starttimes[i]);
}
- wait_for_tests(pids, statuses, tests, num_tests);
+ wait_for_tests(pids, statuses, stoptimes, tests, num_tests);
status_end();
}
bool differ = false;
if (num_tests > 1)
- status(_(" %-24s ... "), tests[i]);
+ status(_(" %-28s ... "), tests[i]);
/*
* Advance over all three lists simultaneously.
*/
for (rl = resultfiles[i], el = expectfiles[i], tl = tags[i];
rl != NULL; /* rl and el have the same length */
- rl = rl->next, el = el->next)
+ rl = rl->next, el = el->next,
+ tl = tl ? tl->next : NULL)
{
bool newdiff;
- if (tl)
- tl = tl->next; /* tl has the same length as rl and el
- * if it exists */
-
newdiff = results_differ(tests[i], rl->str, el->str);
if (newdiff && tl)
{
}
else
{
- status(_("ok"));
+ status(_("ok ")); /* align with FAILED */
success_count++;
}
if (statuses[i] != 0)
log_child_failure(statuses[i]);
+ INSTR_TIME_SUBTRACT(stoptimes[i], starttimes[i]);
+ status(_(" %8.0f ms"), INSTR_TIME_GET_MILLISEC(stoptimes[i]));
+
status_end();
}
+
+ for (i = 0; i < num_tests; i++)
+ {
+ pg_free(tests[i]);
+ tests[i] = NULL;
+ free_stringlist(&resultfiles[i]);
+ free_stringlist(&expectfiles[i]);
+ free_stringlist(&tags[i]);
+ }
}
free_stringlist(&ignorelist);
run_single_test(const char *test, test_function tfunc)
{
PID_TYPE pid;
+ instr_time starttime;
+ instr_time stoptime;
int exit_status;
_stringlist *resultfiles = NULL;
_stringlist *expectfiles = NULL;
*tl;
bool differ = false;
- status(_("test %-24s ... "), test);
+ status(_("test %-28s ... "), test);
pid = (tfunc) (test, &resultfiles, &expectfiles, &tags);
- wait_for_tests(&pid, &exit_status, NULL, 1);
+ INSTR_TIME_SET_CURRENT(starttime);
+ wait_for_tests(&pid, &exit_status, &stoptime, NULL, 1);
/*
* Advance over all three lists simultaneously.
*/
for (rl = resultfiles, el = expectfiles, tl = tags;
rl != NULL; /* rl and el have the same length */
- rl = rl->next, el = el->next)
+ rl = rl->next, el = el->next,
+ tl = tl ? tl->next : NULL)
{
bool newdiff;
- if (tl)
- tl = tl->next; /* tl has the same length as rl and el if it
- * exists */
-
newdiff = results_differ(test, rl->str, el->str);
if (newdiff && tl)
{
}
else
{
- status(_("ok"));
+ status(_("ok ")); /* align with FAILED */
success_count++;
}
if (exit_status != 0)
log_child_failure(exit_status);
+ INSTR_TIME_SUBTRACT(stoptime, starttime);
+ status(_(" %8.0f ms"), INSTR_TIME_GET_MILLISEC(stoptime));
+
status_end();
}
char file[MAXPGPATH];
FILE *difffile;
+ /* create outputdir directory if not present */
+ if (!directory_exists(outputdir))
+ make_directory(outputdir);
+
/* create the log file (copy of running status output) */
snprintf(file, sizeof(file), "%s/regression.out", outputdir);
logfilename = pg_strdup(file);
/* we don't keep the diffs file open continuously */
fclose(difffile);
- /* also create the output directory if not present */
+ /* also create the results directory if not present */
snprintf(file, sizeof(file), "%s/results", outputdir);
if (!directory_exists(file))
make_directory(file);
"ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
"ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
"ALTER DATABASE \"%s\" SET lc_time TO 'C';"
- "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
- dbname, dbname, dbname, dbname, dbname);
+ "ALTER DATABASE \"%s\" SET bytea_output TO 'hex';"
+ "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
+ dbname, dbname, dbname, dbname, dbname, dbname);
/*
* Install any requested procedural languages. We use CREATE OR REPLACE
printf(_("Usage:\n %s [OPTION]... [EXTRA-TEST]...\n"), progname);
printf(_("\n"));
printf(_("Options:\n"));
- printf(_(" --config-auth=DATADIR update authentication settings for DATADIR\n"));
- printf(_(" --create-role=ROLE create the specified role before testing\n"));
- printf(_(" --dbname=DB use database DB (default \"regression\")\n"));
- printf(_(" --debug turn on debug mode in programs that are run\n"));
- printf(_(" --dlpath=DIR look for dynamic libraries in DIR\n"));
- printf(_(" --encoding=ENCODING use ENCODING as the encoding\n"));
- printf(_(" --inputdir=DIR take input files from DIR (default \".\")\n"));
- printf(_(" --launcher=CMD use CMD as launcher of psql\n"));
- printf(_(" --load-extension=EXT load the named extension before running the\n"));
- printf(_(" tests; can appear multiple times\n"));
- printf(_(" --load-language=LANG load the named language before running the\n"));
- printf(_(" tests; can appear multiple times\n"));
- printf(_(" --max-connections=N maximum number of concurrent connections\n"));
- printf(_(" (default is 0, meaning unlimited)\n"));
- printf(_(" --outputdir=DIR place output files in DIR (default \".\")\n"));
- printf(_(" --schedule=FILE use test ordering schedule from FILE\n"));
- printf(_(" (can be used multiple times to concatenate)\n"));
- printf(_(" --temp-instance=DIR create a temporary instance in DIR\n"));
- printf(_(" --use-existing use an existing installation\n"));
+ printf(_(" --bindir=BINPATH use BINPATH for programs that are run;\n"));
+ printf(_(" if empty, use PATH from the environment\n"));
+ printf(_(" --config-auth=DATADIR update authentication settings for DATADIR\n"));
+ printf(_(" --create-role=ROLE create the specified role before testing\n"));
+ printf(_(" --dbname=DB use database DB (default \"regression\")\n"));
+ printf(_(" --debug turn on debug mode in programs that are run\n"));
+ printf(_(" --dlpath=DIR look for dynamic libraries in DIR\n"));
+ printf(_(" --encoding=ENCODING use ENCODING as the encoding\n"));
+ printf(_(" -h, --help show this help, then exit\n"));
+ printf(_(" --inputdir=DIR take input files from DIR (default \".\")\n"));
+ printf(_(" --launcher=CMD use CMD as launcher of psql\n"));
+ printf(_(" --load-extension=EXT load the named extension before running the\n"));
+ printf(_(" tests; can appear multiple times\n"));
+ printf(_(" --load-language=LANG load the named language before running the\n"));
+ printf(_(" tests; can appear multiple times\n"));
+ printf(_(" --max-connections=N maximum number of concurrent connections\n"));
+ printf(_(" (default is 0, meaning unlimited)\n"));
+ printf(_(" --max-concurrent-tests=N maximum number of concurrent tests in schedule\n"));
+ printf(_(" (default is 0, meaning unlimited)\n"));
+ printf(_(" --outputdir=DIR place output files in DIR (default \".\")\n"));
+ printf(_(" --schedule=FILE use test ordering schedule from FILE\n"));
+ printf(_(" (can be used multiple times to concatenate)\n"));
+ printf(_(" --temp-instance=DIR create a temporary instance in DIR\n"));
+ printf(_(" --use-existing use an existing installation\n"));
+ printf(_(" -V, --version output version information, then exit\n"));
printf(_("\n"));
printf(_("Options for \"temp-instance\" mode:\n"));
- printf(_(" --no-locale use C locale\n"));
- printf(_(" --port=PORT start postmaster on PORT\n"));
- printf(_(" --temp-config=FILE append contents of FILE to temporary config\n"));
+ printf(_(" --no-locale use C locale\n"));
+ printf(_(" --port=PORT start postmaster on PORT\n"));
+ printf(_(" --temp-config=FILE append contents of FILE to temporary config\n"));
printf(_("\n"));
printf(_("Options for using an existing installation:\n"));
- printf(_(" --host=HOST use postmaster running on HOST\n"));
- printf(_(" --port=PORT use postmaster running at PORT\n"));
- printf(_(" --user=USER connect as USER\n"));
+ printf(_(" --host=HOST use postmaster running on HOST\n"));
+ printf(_(" --port=PORT use postmaster running at PORT\n"));
+ printf(_(" --user=USER connect as USER\n"));
printf(_("\n"));
printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
printf(_("if the tests could not be run for some reason.\n"));
printf(_("\n"));
- printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
+ printf(_("Report bugs to <pgsql-bugs@lists.postgresql.org>.\n"));
}
int
{"launcher", required_argument, NULL, 21},
{"load-extension", required_argument, NULL, 22},
{"config-auth", required_argument, NULL, 24},
+ {"max-concurrent-tests", required_argument, NULL, 25},
{NULL, 0, NULL, 0}
};
char buf[MAXPGPATH * 4];
char buf2[MAXPGPATH * 4];
+ pg_logging_init(argv[0]);
progname = get_progname(argv[0]);
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_regress"));
+ get_restricted_token();
+
atexit(stop_postmaster);
#ifndef HAVE_UNIX_SOCKETS
case 24:
config_auth_datadir = pg_strdup(optarg);
break;
+ case 25:
+ max_concurrent_tests = atoi(optarg);
+ break;
default:
/* getopt_long already emitted a complaint */
fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
if (config_auth_datadir)
{
#ifdef ENABLE_SSPI
- config_sspi_auth(config_auth_datadir);
+ config_sspi_auth(config_auth_datadir, user);
#endif
exit(0);
}
/* initdb */
header(_("initializing database system"));
snprintf(buf, sizeof(buf),
- "\"%s%sinitdb\" -D \"%s/data\" --noclean --nosync%s%s > \"%s/log/initdb.log\" 2>&1",
+ "\"%s%sinitdb\" -D \"%s/data\" --no-clean --no-sync%s%s > \"%s/log/initdb.log\" 2>&1",
bindir ? bindir : "",
bindir ? "/" : "",
temp_instance,
fputs("\n# Configuration added by pg_regress\n\n", pg_conf);
fputs("log_autovacuum_min_duration = 0\n", pg_conf);
fputs("log_checkpoints = on\n", pg_conf);
+ fputs("log_line_prefix = '%m [%p] %q%a '\n", pg_conf);
fputs("log_lock_waits = on\n", pg_conf);
fputs("log_temp_files = 128kB\n", pg_conf);
fputs("max_prepared_transactions = 2\n", pg_conf);
* "initdb" command, this can't truncate.
*/
snprintf(buf, sizeof(buf), "%s/data", temp_instance);
- config_sspi_auth(buf);
+ config_sspi_auth(buf, NULL);
#elif !defined(HAVE_UNIX_SOCKETS)
#error Platform has no means to secure the test installation.
#endif
* Fail immediately if postmaster has exited
*/
#ifndef WIN32
- if (kill(postmaster_pid, 0) != 0)
+ if (waitpid(postmaster_pid, NULL, WNOHANG) == postmaster_pid)
#else
if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
#endif