diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile index 6336edc65b..8dcc702c69 100644 --- a/src/bin/pg_dump/Makefile +++ b/src/bin/pg_dump/Makefile @@ -19,8 +19,8 @@ include $(top_builddir)/src/Makefile.global override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS) OBJS= pg_backup_archiver.o pg_backup_db.o pg_backup_custom.o \ - pg_backup_null.o pg_backup_tar.o parallel.o \ - pg_backup_directory.o dumputils.o compress_io.o $(WIN32RES) + pg_backup_null.o pg_backup_tar.o pg_backup_directory.o \ + pg_backup_utils.o parallel.o compress_io.o dumputils.o $(WIN32RES) KEYWRDOBJS = keywords.o kwlookup.o diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index b8832af250..ae52ac11ed 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -14,6 +14,7 @@ *------------------------------------------------------------------------- */ #include "pg_backup_archiver.h" +#include "pg_backup_utils.h" #include diff --git a/src/bin/pg_dump/compress_io.c b/src/bin/pg_dump/compress_io.c index 0308f66c49..1dd31fbe2c 100644 --- a/src/bin/pg_dump/compress_io.c +++ b/src/bin/pg_dump/compress_io.c @@ -53,7 +53,7 @@ */ #include "compress_io.h" -#include "dumputils.h" +#include "pg_backup_utils.h" #include "parallel.h" /*---------------------- diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c index 31e56ef7fb..9c55147c81 100644 --- a/src/bin/pg_dump/dumputils.c +++ b/src/bin/pg_dump/dumputils.c @@ -25,21 +25,6 @@ extern const ScanKeyword FEScanKeywords[]; extern const int NumFEScanKeywords; -/* Globals exported by this file */ -int quote_all_identifiers = 0; -const char *progname = NULL; - -#define MAX_ON_EXIT_NICELY 20 - -static struct -{ - on_exit_nicely_callback function; - void *arg; -} on_exit_nicely_list[MAX_ON_EXIT_NICELY]; - -static int on_exit_nicely_index; -void (*on_exit_msg_func) (const char *modulename, const char *fmt, va_list ap) = vwrite_msg; - #define supports_grant_options(version) ((version) >= 70400) static bool parseAclItem(const char *item, const char *type, @@ -49,68 +34,24 @@ static bool parseAclItem(const char *item, const char *type, static char *copyAclUserName(PQExpBuffer output, char *input); static void AddAcl(PQExpBuffer aclbuf, const char *keyword, const char *subname); -static PQExpBuffer getThreadLocalPQExpBuffer(void); +static PQExpBuffer defaultGetLocalPQExpBuffer(void); -#ifdef WIN32 -static void shutdown_parallel_dump_utils(int code, void *unused); -static bool parallel_init_done = false; -static DWORD tls_index; -static DWORD mainThreadId; - -static void -shutdown_parallel_dump_utils(int code, void *unused) -{ - /* Call the cleanup function only from the main thread */ - if (mainThreadId == GetCurrentThreadId()) - WSACleanup(); -} -#endif - -void -init_parallel_dump_utils(void) -{ -#ifdef WIN32 - if (!parallel_init_done) - { - WSADATA wsaData; - int err; - - tls_index = TlsAlloc(); - mainThreadId = GetCurrentThreadId(); - err = WSAStartup(MAKEWORD(2, 2), &wsaData); - if (err != 0) - { - fprintf(stderr, _("WSAStartup failed: %d\n"), err); - exit_nicely(1); - } - on_exit_nicely(shutdown_parallel_dump_utils, NULL); - parallel_init_done = true; - } -#endif -} +/* Globals exported by this file */ +int quote_all_identifiers = 0; +PQExpBuffer (*getLocalPQExpBuffer) (void) = defaultGetLocalPQExpBuffer; /* - * Non-reentrant but reduces memory leakage. (On Windows the memory leakage - * will be one buffer per thread, which is at least better than one per call). + * Returns a temporary PQExpBuffer, valid until the next call to the function. + * This is used by fmtId and fmtQualifiedId. + * + * Non-reentrant and non-thread-safe but reduces memory leakage. You can + * replace this with a custom version by setting the getLocalPQExpBuffer + * function pointer. */ static PQExpBuffer -getThreadLocalPQExpBuffer(void) +defaultGetLocalPQExpBuffer(void) { - /* - * The Tls code goes awry if we use a static var, so we provide for both - * static and auto, and omit any use of the static var when using Tls. - */ - static PQExpBuffer s_id_return = NULL; - PQExpBuffer id_return; - -#ifdef WIN32 - if (parallel_init_done) - id_return = (PQExpBuffer) TlsGetValue(tls_index); /* 0 when not set */ - else - id_return = s_id_return; -#else - id_return = s_id_return; -#endif + static PQExpBuffer id_return = NULL; if (id_return) /* first time through? */ { @@ -121,15 +62,6 @@ getThreadLocalPQExpBuffer(void) { /* new buffer */ id_return = createPQExpBuffer(); -#ifdef WIN32 - if (parallel_init_done) - TlsSetValue(tls_index, id_return); - else - s_id_return = id_return; -#else - s_id_return = id_return; -#endif - } return id_return; @@ -144,7 +76,7 @@ getThreadLocalPQExpBuffer(void) const char * fmtId(const char *rawid) { - PQExpBuffer id_return = getThreadLocalPQExpBuffer(); + PQExpBuffer id_return = getLocalPQExpBuffer(); const char *cp; bool need_quotes = false; @@ -238,7 +170,7 @@ fmtQualifiedId(int remoteVersion, const char *schema, const char *id) } appendPQExpBuffer(lcl_pqexp, "%s", fmtId(id)); - id_return = getThreadLocalPQExpBuffer(); + id_return = getLocalPQExpBuffer(); appendPQExpBuffer(id_return, "%s", lcl_pqexp->data); destroyPQExpBuffer(lcl_pqexp); @@ -1278,118 +1210,6 @@ emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer, } -/* - * Parse a --section=foo command line argument. - * - * Set or update the bitmask in *dumpSections according to arg. - * dumpSections is initialised as DUMP_UNSECTIONED by pg_dump and - * pg_restore so they can know if this has even been called. - */ -void -set_dump_section(const char *arg, int *dumpSections) -{ - /* if this is the first call, clear all the bits */ - if (*dumpSections == DUMP_UNSECTIONED) - *dumpSections = 0; - - if (strcmp(arg, "pre-data") == 0) - *dumpSections |= DUMP_PRE_DATA; - else if (strcmp(arg, "data") == 0) - *dumpSections |= DUMP_DATA; - else if (strcmp(arg, "post-data") == 0) - *dumpSections |= DUMP_POST_DATA; - else - { - fprintf(stderr, _("%s: unrecognized section name: \"%s\"\n"), - progname, arg); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), - progname); - exit_nicely(1); - } -} - - -/* - * Write a printf-style message to stderr. - * - * The program name is prepended, if "progname" has been set. - * Also, if modulename isn't NULL, that's included too. - * Note that we'll try to translate the modulename and the fmt string. - */ -void -write_msg(const char *modulename, const char *fmt,...) -{ - va_list ap; - - va_start(ap, fmt); - vwrite_msg(modulename, fmt, ap); - va_end(ap); -} - -/* - * As write_msg, but pass a va_list not variable arguments. - */ -void -vwrite_msg(const char *modulename, const char *fmt, va_list ap) -{ - if (progname) - { - if (modulename) - fprintf(stderr, "%s: [%s] ", progname, _(modulename)); - else - fprintf(stderr, "%s: ", progname); - } - vfprintf(stderr, _(fmt), ap); -} - - -/* - * Fail and die, with a message to stderr. Parameters as for write_msg. - */ -void -exit_horribly(const char *modulename, const char *fmt,...) -{ - va_list ap; - - va_start(ap, fmt); - on_exit_msg_func(modulename, fmt, ap); - va_end(ap); - - exit_nicely(1); -} - -/* Register a callback to be run when exit_nicely is invoked. */ -void -on_exit_nicely(on_exit_nicely_callback function, void *arg) -{ - if (on_exit_nicely_index >= MAX_ON_EXIT_NICELY) - exit_horribly(NULL, "out of on_exit_nicely slots\n"); - on_exit_nicely_list[on_exit_nicely_index].function = function; - on_exit_nicely_list[on_exit_nicely_index].arg = arg; - on_exit_nicely_index++; -} - -/* - * Run accumulated on_exit_nicely callbacks in reverse order and then exit - * quietly. This needs to be thread-safe. - */ -void -exit_nicely(int code) -{ - int i; - - for (i = on_exit_nicely_index - 1; i >= 0; i--) - (*on_exit_nicely_list[i].function) (code, - on_exit_nicely_list[i].arg); - -#ifdef WIN32 - if (parallel_init_done && GetCurrentThreadId() != mainThreadId) - ExitThread(code); -#endif - - exit(code); -} - void simple_string_list_append(SimpleStringList *list, const char *val) { diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h index 5734c33617..356e8ebd32 100644 --- a/src/bin/pg_dump/dumputils.h +++ b/src/bin/pg_dump/dumputils.h @@ -19,14 +19,6 @@ #include "libpq-fe.h" #include "pqexpbuffer.h" -typedef enum /* bits returned by set_dump_section */ -{ - DUMP_PRE_DATA = 0x01, - DUMP_DATA = 0x02, - DUMP_POST_DATA = 0x04, - DUMP_UNSECTIONED = 0xff -} DumpSections; - typedef struct SimpleStringListCell { struct SimpleStringListCell *next; @@ -40,14 +32,9 @@ typedef struct SimpleStringList } SimpleStringList; -typedef void (*on_exit_nicely_callback) (int code, void *arg); - extern int quote_all_identifiers; -extern const char *progname; -extern void (*on_exit_msg_func) (const char *modulename, const char *fmt, va_list ap) -__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 0))); +extern PQExpBuffer (*getLocalPQExpBuffer) (void); -extern void init_parallel_dump_utils(void); extern const char *fmtId(const char *identifier); extern const char *fmtQualifiedId(int remoteVersion, const char *schema, const char *id); @@ -79,17 +66,6 @@ extern void buildShSecLabelQuery(PGconn *conn, const char *catalog_name, extern void emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer, const char *target, const char *objname); extern void set_dump_section(const char *arg, int *dumpSections); -extern void -write_msg(const char *modulename, const char *fmt,...) -__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3))); -extern void -vwrite_msg(const char *modulename, const char *fmt, va_list ap) -__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 0))); -extern void -exit_horribly(const char *modulename, const char *fmt,...) -__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3), noreturn)); -extern void on_exit_nicely(on_exit_nicely_callback function, void *arg); -extern void exit_nicely(int code) __attribute__((noreturn)); extern void simple_string_list_append(SimpleStringList *list, const char *val); extern bool simple_string_list_member(SimpleStringList *list, const char *val); diff --git a/src/bin/pg_dump/parallel.c b/src/bin/pg_dump/parallel.c index dedf4311b9..ae0d329ea2 100644 --- a/src/bin/pg_dump/parallel.c +++ b/src/bin/pg_dump/parallel.c @@ -16,9 +16,9 @@ *------------------------------------------------------------------------- */ -#include "pg_backup_db.h" +#include "postgres_fe.h" -#include "dumputils.h" +#include "pg_backup_utils.h" #include "parallel.h" #ifndef WIN32 @@ -78,10 +78,6 @@ static const char *modulename = gettext_noop("parallel archiver"); static ParallelSlot *GetMyPSlot(ParallelState *pstate); static void -parallel_exit_msg_func(const char *modulename, - const char *fmt, va_list ap) -__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 0))); -static void parallel_msg_master(ParallelSlot *slot, const char *modulename, const char *fmt, va_list ap) __attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 0))); @@ -112,6 +108,47 @@ static char *readMessageFromPipe(int fd); #define messageEquals(msg, pattern) \ (strcmp(msg, pattern) == 0) +#ifdef WIN32 +static void shutdown_parallel_dump_utils(int code, void *unused); +bool parallel_init_done = false; +static DWORD tls_index; +DWORD mainThreadId; +#endif + + +#ifdef WIN32 +static void +shutdown_parallel_dump_utils(int code, void *unused) +{ + /* Call the cleanup function only from the main thread */ + if (mainThreadId == GetCurrentThreadId()) + WSACleanup(); +} +#endif + +void +init_parallel_dump_utils(void) +{ +#ifdef WIN32 + if (!parallel_init_done) + { + WSADATA wsaData; + int err; + + tls_index = TlsAlloc(); + mainThreadId = GetCurrentThreadId(); + err = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (err != 0) + { + fprintf(stderr, _("WSAStartup failed: %d\n"), err); + exit_nicely(1); + } + on_exit_nicely(shutdown_parallel_dump_utils, NULL); + parallel_init_done = true; + } +#endif +} + static ParallelSlot * GetMyPSlot(ParallelState *pstate) { @@ -129,29 +166,44 @@ GetMyPSlot(ParallelState *pstate) } /* - * This is the function that will be called from exit_horribly() to print the - * error message. If the worker process does exit_horribly(), we forward its + * Fail and die, with a message to stderr. Parameters as for write_msg. + * + * This is defined in parallel.c, because in parallel mode, things are more + * complicated. If the worker process does exit_horribly(), we forward its * last words to the master process. The master process then does * exit_horribly() with this error message itself and prints it normally. * After printing the message, exit_horribly() on the master will shut down * the remaining worker processes. */ -static void -parallel_exit_msg_func(const char *modulename, const char *fmt, va_list ap) +void +exit_horribly(const char *modulename, const char *fmt,...) { + va_list ap; ParallelState *pstate = shutdown_info.pstate; ParallelSlot *slot; - Assert(pstate); + va_start(ap, fmt); - slot = GetMyPSlot(pstate); - - if (!slot) - /* We're the parent, just write the message out */ + if (pstate == NULL) + { + /* Not in parallel mode, just write to stderr */ vwrite_msg(modulename, fmt, ap); + } else - /* If we're a worker process, send the msg to the master process */ - parallel_msg_master(slot, modulename, fmt, ap); + { + slot = GetMyPSlot(pstate); + + if (!slot) + /* We're the parent, just write the message out */ + vwrite_msg(modulename, fmt, ap); + else + /* If we're a worker process, send the msg to the master process */ + parallel_msg_master(slot, modulename, fmt, ap); + } + + va_end(ap); + + exit_nicely(1); } /* Sends the error message from the worker to the master process */ @@ -172,6 +224,54 @@ parallel_msg_master(ParallelSlot *slot, const char *modulename, sendMessageToMaster(pipefd, buf); } +/* + * A thread-local version of getLocalPQExpBuffer(). + * + * Non-reentrant but reduces memory leakage. (On Windows the memory leakage + * will be one buffer per thread, which is at least better than one per call). + */ +static PQExpBuffer +getThreadLocalPQExpBuffer(void) +{ + /* + * The Tls code goes awry if we use a static var, so we provide for both + * static and auto, and omit any use of the static var when using Tls. + */ + static PQExpBuffer s_id_return = NULL; + PQExpBuffer id_return; + +#ifdef WIN32 + if (parallel_init_done) + id_return = (PQExpBuffer) TlsGetValue(tls_index); /* 0 when not set */ + else + id_return = s_id_return; +#else + id_return = s_id_return; +#endif + + if (id_return) /* first time through? */ + { + /* same buffer, just wipe contents */ + resetPQExpBuffer(id_return); + } + else + { + /* new buffer */ + id_return = createPQExpBuffer(); +#ifdef WIN32 + if (parallel_init_done) + TlsSetValue(tls_index, id_return); + else + s_id_return = id_return; +#else + s_id_return = id_return; +#endif + + } + + return id_return; +} + /* * pg_dump and pg_restore register the Archive pointer for the exit handler * (called from exit_horribly). This function mainly exists so that we can @@ -408,7 +508,7 @@ ParallelBackupStart(ArchiveHandle *AH, RestoreOptions *ropt) * set and falls back to AHX otherwise. */ shutdown_info.pstate = pstate; - on_exit_msg_func = parallel_exit_msg_func; + getLocalPQExpBuffer = getThreadLocalPQExpBuffer; #ifdef WIN32 tMasterThreadId = GetCurrentThreadId(); diff --git a/src/bin/pg_dump/parallel.h b/src/bin/pg_dump/parallel.h index 7422f12db4..a7caa6cdbe 100644 --- a/src/bin/pg_dump/parallel.h +++ b/src/bin/pg_dump/parallel.h @@ -16,6 +16,9 @@ *------------------------------------------------------------------------- */ +#ifndef PG_DUMP_PARALLEL_H +#define PG_DUMP_PARALLEL_H + #include "pg_backup_db.h" struct _archiveHandle; @@ -62,6 +65,13 @@ typedef struct ParallelState ParallelSlot *parallelSlot; } ParallelState; +#ifdef WIN32 +extern bool parallel_init_done; +extern DWORD mainThreadId; +#endif + +extern void init_parallel_dump_utils(void); + extern int GetIdleWorker(ParallelState *pstate); extern bool IsEveryWorkerIdle(ParallelState *pstate); extern void ListenToWorkers(struct _archiveHandle * AH, ParallelState *pstate, bool do_wait); @@ -77,3 +87,9 @@ extern void DispatchJobForTocEntry(struct _archiveHandle * AH, extern void ParallelBackupEnd(struct _archiveHandle * AH, ParallelState *pstate); extern void checkAborting(struct _archiveHandle * AH); + +extern void +exit_horribly(const char *modulename, const char *fmt,...) +__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3), noreturn)); + +#endif /* PG_DUMP_PARALLEL_H */ diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index 39b4f8ecca..d202b42220 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -21,7 +21,7 @@ */ #include "pg_backup_db.h" -#include "dumputils.h" +#include "pg_backup_utils.h" #include "parallel.h" #include diff --git a/src/bin/pg_dump/pg_backup_custom.c b/src/bin/pg_dump/pg_backup_custom.c index c2e94ca084..263bcd3c53 100644 --- a/src/bin/pg_dump/pg_backup_custom.c +++ b/src/bin/pg_dump/pg_backup_custom.c @@ -25,8 +25,8 @@ */ #include "compress_io.h" -#include "dumputils.h" #include "parallel.h" +#include "pg_backup_utils.h" /*-------- * Routines in the format interface diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c index e16c193e3b..cd2ddedada 100644 --- a/src/bin/pg_dump/pg_backup_db.c +++ b/src/bin/pg_dump/pg_backup_db.c @@ -11,7 +11,9 @@ */ #include "pg_backup_db.h" +#include "pg_backup_utils.h" #include "dumputils.h" +#include "parallel.h" #include #include diff --git a/src/bin/pg_dump/pg_backup_directory.c b/src/bin/pg_dump/pg_backup_directory.c index 66151f584b..524bde3d6b 100644 --- a/src/bin/pg_dump/pg_backup_directory.c +++ b/src/bin/pg_dump/pg_backup_directory.c @@ -34,7 +34,7 @@ */ #include "compress_io.h" -#include "dumputils.h" +#include "pg_backup_utils.h" #include "parallel.h" #include diff --git a/src/bin/pg_dump/pg_backup_null.c b/src/bin/pg_dump/pg_backup_null.c index 6ac81982b8..c321068b4e 100644 --- a/src/bin/pg_dump/pg_backup_null.c +++ b/src/bin/pg_dump/pg_backup_null.c @@ -23,7 +23,8 @@ */ #include "pg_backup_archiver.h" -#include "dumputils.h" +#include "pg_backup_utils.h" +#include "parallel.h" #include /* for dup */ diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c index 6465ac3e6c..2358b9d160 100644 --- a/src/bin/pg_dump/pg_backup_tar.c +++ b/src/bin/pg_dump/pg_backup_tar.c @@ -31,7 +31,8 @@ #include "pg_backup.h" #include "pg_backup_archiver.h" #include "pg_backup_tar.h" -#include "dumputils.h" +#include "pg_backup_utils.h" +#include "parallel.h" #include "pgtar.h" #include diff --git a/src/bin/pg_dump/pg_backup_utils.c b/src/bin/pg_dump/pg_backup_utils.c new file mode 100644 index 0000000000..dee717c3da --- /dev/null +++ b/src/bin/pg_dump/pg_backup_utils.c @@ -0,0 +1,126 @@ +/*------------------------------------------------------------------------- + * + * pg_backup_utils.c + * Utility routines shared by pg_dump and pg_restore + * + * + * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/bin/pg_dump/pg_backup_utils.c + * + *------------------------------------------------------------------------- + */ +#include "postgres_fe.h" + +#include "pg_backup_utils.h" +#include "parallel.h" + +/* Globals exported by this file */ +const char *progname = NULL; + +#define MAX_ON_EXIT_NICELY 20 + +static struct +{ + on_exit_nicely_callback function; + void *arg; +} on_exit_nicely_list[MAX_ON_EXIT_NICELY]; + +static int on_exit_nicely_index; + +/* + * Parse a --section=foo command line argument. + * + * Set or update the bitmask in *dumpSections according to arg. + * dumpSections is initialised as DUMP_UNSECTIONED by pg_dump and + * pg_restore so they can know if this has even been called. + */ +void +set_dump_section(const char *arg, int *dumpSections) +{ + /* if this is the first call, clear all the bits */ + if (*dumpSections == DUMP_UNSECTIONED) + *dumpSections = 0; + + if (strcmp(arg, "pre-data") == 0) + *dumpSections |= DUMP_PRE_DATA; + else if (strcmp(arg, "data") == 0) + *dumpSections |= DUMP_DATA; + else if (strcmp(arg, "post-data") == 0) + *dumpSections |= DUMP_POST_DATA; + else + { + fprintf(stderr, _("%s: unrecognized section name: \"%s\"\n"), + progname, arg); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); + exit_nicely(1); + } +} + + +/* + * Write a printf-style message to stderr. + * + * The program name is prepended, if "progname" has been set. + * Also, if modulename isn't NULL, that's included too. + * Note that we'll try to translate the modulename and the fmt string. + */ +void +write_msg(const char *modulename, const char *fmt,...) +{ + va_list ap; + + va_start(ap, fmt); + vwrite_msg(modulename, fmt, ap); + va_end(ap); +} + +/* + * As write_msg, but pass a va_list not variable arguments. + */ +void +vwrite_msg(const char *modulename, const char *fmt, va_list ap) +{ + if (progname) + { + if (modulename) + fprintf(stderr, "%s: [%s] ", progname, _(modulename)); + else + fprintf(stderr, "%s: ", progname); + } + vfprintf(stderr, _(fmt), ap); +} + +/* Register a callback to be run when exit_nicely is invoked. */ +void +on_exit_nicely(on_exit_nicely_callback function, void *arg) +{ + if (on_exit_nicely_index >= MAX_ON_EXIT_NICELY) + exit_horribly(NULL, "out of on_exit_nicely slots\n"); + on_exit_nicely_list[on_exit_nicely_index].function = function; + on_exit_nicely_list[on_exit_nicely_index].arg = arg; + on_exit_nicely_index++; +} + +/* + * Run accumulated on_exit_nicely callbacks in reverse order and then exit + * quietly. This needs to be thread-safe. + */ +void +exit_nicely(int code) +{ + int i; + + for (i = on_exit_nicely_index - 1; i >= 0; i--) + (*on_exit_nicely_list[i].function) (code, + on_exit_nicely_list[i].arg); + +#ifdef WIN32 + if (parallel_init_done && GetCurrentThreadId() != mainThreadId) + ExitThread(code); +#endif + + exit(code); +} diff --git a/src/bin/pg_dump/pg_backup_utils.h b/src/bin/pg_dump/pg_backup_utils.h new file mode 100644 index 0000000000..0e31cff47c --- /dev/null +++ b/src/bin/pg_dump/pg_backup_utils.h @@ -0,0 +1,40 @@ +/*------------------------------------------------------------------------- + * + * pg_backup_utils.h + * Utility routines shared by pg_dump and pg_restore. + * + * + * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/bin/pg_dump/pg_backup_utils.h + * + *------------------------------------------------------------------------- + */ + +#ifndef PG_BACKUP_UTILS_H +#define PG_BACKUP_UTILS_H + +typedef enum /* bits returned by set_dump_section */ +{ + DUMP_PRE_DATA = 0x01, + DUMP_DATA = 0x02, + DUMP_POST_DATA = 0x04, + DUMP_UNSECTIONED = 0xff +} DumpSections; + +typedef void (*on_exit_nicely_callback) (int code, void *arg); + +extern const char *progname; + +extern void set_dump_section(const char *arg, int *dumpSections); +extern void +write_msg(const char *modulename, const char *fmt,...) +__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3))); +extern void +vwrite_msg(const char *modulename, const char *fmt, va_list ap) +__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 0))); +extern void on_exit_nicely(on_exit_nicely_callback function, void *arg); +extern void exit_nicely(int code) __attribute__((noreturn)); + +#endif /* PG_BACKUP_UTILS_H */ diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index e4cf92a1a2..aa6993a366 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -59,7 +59,9 @@ #include "pg_backup_archiver.h" #include "pg_backup_db.h" +#include "pg_backup_utils.h" #include "dumputils.h" +#include "parallel.h" extern char *optarg; extern int optind, diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c index 8a6d36329d..141e71342c 100644 --- a/src/bin/pg_dump/pg_dump_sort.c +++ b/src/bin/pg_dump/pg_dump_sort.c @@ -14,7 +14,8 @@ *------------------------------------------------------------------------- */ #include "pg_backup_archiver.h" -#include "dumputils.h" +#include "pg_backup_utils.h" +#include "parallel.h" /* translator: this is a module name */ static const char *modulename = gettext_noop("sorter"); diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 040cd94e5b..78f702f897 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -63,6 +63,7 @@ static PGresult *executeQuery(PGconn *conn, const char *query); static void executeCommand(PGconn *conn, const char *query); static char pg_dump_bin[MAXPGPATH]; +static const char *progname; static PQExpBuffer pgdumpopts; static char *connstr = ""; static bool skip_acls = false; @@ -82,6 +83,7 @@ static int server_version; static FILE *OPF; static char *filename = NULL; +#define exit_nicely(code) exit(code) int main(int argc, char *argv[]) diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c index 0cc17fd416..c585098c72 100644 --- a/src/bin/pg_dump/pg_restore.c +++ b/src/bin/pg_dump/pg_restore.c @@ -40,8 +40,9 @@ */ #include "pg_backup_archiver.h" - +#include "pg_backup_utils.h" #include "dumputils.h" +#include "parallel.h" #include