Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * pg_backup_utils.c
4 : : * Utility routines shared by pg_dump and pg_restore
5 : : *
6 : : *
7 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
8 : : * Portions Copyright (c) 1994, Regents of the University of California
9 : : *
10 : : * src/bin/pg_dump/pg_backup_utils.c
11 : : *
12 : : *-------------------------------------------------------------------------
13 : : */
14 : : #include "postgres_fe.h"
15 : :
16 : : #ifdef WIN32
17 : : #include "parallel.h"
18 : : #endif
19 : : #include "pg_backup_utils.h"
20 : :
21 : : /* Globals exported by this file */
22 : : const char *progname = NULL;
23 : :
24 : : #ifdef WIN32
25 : :
26 : : /*
27 : : * Flag telling worker threads to stay quiet about query failures because
28 : : * we're cancelling their queries as part of tearing down the process. See
29 : : * the comment in pg_backup_utils.h.
30 : : *
31 : : * The cancel thread writes it while worker threads read it, so it's marked
32 : : * volatile to keep the compiler from caching the value. A plain volatile
33 : : * bool isn't a memory barrier, but it's good enough here. A lot of things
34 : : * happen between set_cancel_in_progress() in the cancel thread and the other
35 : : * threads calling is_cancel_in_progress(), including network operations,
36 : : * which implicitly act as memory barriers. Furthermore, the flag is only
37 : : * ever flipped one way (false to true) and a worker briefly observing the
38 : : * stale false just means it would print one error before the process dies.
39 : : * The only goal of this flag is to make sure workers don't log "query
40 : : * cancelled" errors during the shutdown process.
41 : : *
42 : : * XXX: This should be swapped out for a proper atomic when we have those in
43 : : * the frontend code, so that we wouldn't need to rationalizee all of the
44 : : * above.
45 : : */
46 : : static volatile bool cancelInProgress = false;
47 : :
48 : : void
49 : : set_cancel_in_progress(void)
50 : : {
51 : : cancelInProgress = true;
52 : : }
53 : :
54 : : bool
55 : : is_cancel_in_progress(void)
56 : : {
57 : : return cancelInProgress;
58 : : }
59 : :
60 : : #endif /* WIN32 */
61 : :
62 : : #define MAX_ON_EXIT_NICELY 20
63 : :
64 : : static struct
65 : : {
66 : : on_exit_nicely_callback function;
67 : : void *arg;
68 : : } on_exit_nicely_list[MAX_ON_EXIT_NICELY];
69 : :
70 : : static int on_exit_nicely_index;
71 : :
72 : : /*
73 : : * Parse a --section=foo command line argument.
74 : : *
75 : : * Set or update the bitmask in *dumpSections according to arg.
76 : : * dumpSections is initialised as DUMP_UNSECTIONED by pg_dump and
77 : : * pg_restore so they can know if this has even been called.
78 : : */
79 : : void
80 : 6 : set_dump_section(const char *arg, int *dumpSections)
81 : : {
82 : : /* if this is the first call, clear all the bits */
83 [ + - ]: 6 : if (*dumpSections == DUMP_UNSECTIONED)
84 : 6 : *dumpSections = 0;
85 : :
86 [ + + ]: 6 : if (strcmp(arg, "pre-data") == 0)
87 : 2 : *dumpSections |= DUMP_PRE_DATA;
88 [ + + ]: 4 : else if (strcmp(arg, "data") == 0)
89 : 2 : *dumpSections |= DUMP_DATA;
90 [ + - ]: 2 : else if (strcmp(arg, "post-data") == 0)
91 : 2 : *dumpSections |= DUMP_POST_DATA;
92 : : else
93 : : {
94 : 0 : pg_log_error("unrecognized section name: \"%s\"", arg);
95 : 0 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
96 : 0 : exit_nicely(1);
97 : : }
98 : 6 : }
99 : :
100 : :
101 : : /* Register a callback to be run when exit_nicely is invoked. */
102 : : void
103 : 275 : on_exit_nicely(on_exit_nicely_callback function, void *arg)
104 : : {
105 [ - + ]: 275 : if (on_exit_nicely_index >= MAX_ON_EXIT_NICELY)
106 : 0 : pg_fatal("out of on_exit_nicely slots");
107 : 275 : on_exit_nicely_list[on_exit_nicely_index].function = function;
108 : 275 : on_exit_nicely_list[on_exit_nicely_index].arg = arg;
109 : 275 : on_exit_nicely_index++;
110 : 275 : }
111 : :
112 : : /*
113 : : * Run accumulated on_exit_nicely callbacks in reverse order and then exit
114 : : * without printing any message.
115 : : *
116 : : * If running in a parallel worker thread on Windows, we only exit the thread,
117 : : * not the whole process.
118 : : *
119 : : * Note that in parallel operation on Windows, the callback(s) will be run
120 : : * by each thread since the list state is necessarily shared by all threads;
121 : : * each callback must contain logic to ensure it does only what's appropriate
122 : : * for its thread. On Unix, callbacks are also run by each process, but only
123 : : * for callbacks established before we fork off the child processes. (It'd
124 : : * be cleaner to reset the list after fork(), and let each child establish
125 : : * its own callbacks; but then the behavior would be completely inconsistent
126 : : * between Windows and Unix. For now, just be sure to establish callbacks
127 : : * before forking to avoid inconsistency.)
128 : : */
129 : : void
130 : 394 : exit_nicely(int code)
131 : : {
132 : : int i;
133 : :
134 [ + + ]: 604 : for (i = on_exit_nicely_index - 1; i >= 0; i--)
135 : 210 : on_exit_nicely_list[i].function(code,
136 : : on_exit_nicely_list[i].arg);
137 : :
138 : : #ifdef WIN32
139 : : if (parallel_init_done && GetCurrentThreadId() != mainThreadId)
140 : : _endthreadex(code);
141 : : #endif
142 : :
143 : 394 : exit(code);
144 : : }
|