176{
177#ifndef WIN32
178 pid_t child;
179#else
180 HANDLE child;
181 transfer_thread_arg *new_arg;
182#endif
183
186 else
187 {
188 /* parallel */
189#ifdef WIN32
190 if (thread_handles == NULL)
192
193 if (transfer_thread_args == NULL)
194 {
196
198
199 /*
200 * For safety and performance, we keep the args allocated during
201 * the entire life of the process, and we don't free the args in a
202 * thread different from the one that allocated it.
203 */
205 transfer_thread_args[
i] =
pg_malloc0(
sizeof(transfer_thread_arg));
206 }
207
208 cur_thread_args = (void **) transfer_thread_args;
209#endif
210 /* harvest any dead children */
212 ;
213
214 /* must we wait for a dead child? */
217
218 /* set this before we start the job */
220
221 /* Ensure stdio state is quiesced before forking */
222 fflush(NULL);
223
224#ifndef WIN32
225 child = fork();
226 if (child == 0)
227 {
229 old_tablespace, new_tablespace);
230 /* if we take another exit path, it will be non-zero */
231 /* use _exit to skip atexit() functions */
232 _exit(0);
233 }
234 else if (child < 0)
235 /* fork failed */
236 pg_fatal(
"could not create worker process: %m");
237#else
238 /* empty array element are always at the end */
240
241 /* Can only pass one pointer into the function, so use a struct */
242 new_arg->old_db_arr = old_db_arr;
243 new_arg->new_db_arr = new_db_arr;
245 new_arg->old_pgdata =
pg_strdup(old_pgdata);
247 new_arg->new_pgdata =
pg_strdup(new_pgdata);
248 pg_free(new_arg->old_tablespace);
249 new_arg->old_tablespace = old_tablespace ?
pg_strdup(old_tablespace) : NULL;
250 new_arg->new_tablespace = new_tablespace ?
pg_strdup(new_tablespace) : NULL;
251
252 child = (HANDLE) _beginthreadex(NULL, 0, (void *) win32_transfer_all_new_dbs,
253 new_arg, 0, NULL);
254 if (child == 0)
255 pg_fatal(
"could not create worker thread: %m");
256
258#endif
259 }
260}
void transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr, char *old_pgdata, char *new_pgdata, char *old_tablespace, char *new_tablespace)