@@ -37,19 +37,29 @@ static int win32_check_directory_write_permissions(void);
3737 * If throw_error is true, this raises a PG_FATAL error and pg_upgrade
3838 * terminates; otherwise it is just reported as PG_REPORT and exec_prog()
3939 * returns false.
40+ *
41+ * The code requires it be called first from the primary thread on Windows.
4042 */
4143bool
4244exec_prog (const char * log_file , const char * opt_log_file ,
4345 bool throw_error , const char * fmt ,...)
4446{
45- int result ;
47+ int result = 0 ;
4648 int written ;
4749
4850#define MAXCMDLEN (2 * MAXPGPATH)
4951 char cmd [MAXCMDLEN ];
5052 FILE * log ;
5153 va_list ap ;
5254
55+ #ifdef WIN32
56+ static DWORD mainThreadId = 0 ;
57+
58+ /* We assume we are called from the primary thread first */
59+ if (mainThreadId == 0 )
60+ mainThreadId = GetCurrentThreadId ();
61+ #endif
62+
5363 written = strlcpy (cmd , SYSTEMQUOTE , sizeof (cmd ));
5464 va_start (ap , fmt );
5565 written += vsnprintf (cmd + written , MAXCMDLEN - written , fmt , ap );
@@ -61,6 +71,22 @@ exec_prog(const char *log_file, const char *opt_log_file,
6171 if (written >= MAXCMDLEN )
6272 pg_log (PG_FATAL , "command too long\n" );
6373
74+ pg_log (PG_VERBOSE , "%s\n" , cmd );
75+
76+ #ifdef WIN32
77+ /*
78+ * For some reason, Windows issues a file-in-use error if we write data
79+ * to the log file from a non-primary thread just before we create a
80+ * subprocess that also writes to the same log file. One fix is to
81+ * sleep for 100ms. A cleaner fix is to write to the log file _after_
82+ * the subprocess has completed, so we do this only when writing from
83+ * a non-primary thread. fflush(), running system() twice, and
84+ * pre-creating the file do not see to help.
85+ */
86+ if (mainThreadId != GetCurrentThreadId ())
87+ result = system (cmd );
88+ #endif
89+
6490 log = fopen (log_file , "a" );
6591
6692#ifdef WIN32
@@ -84,19 +110,30 @@ exec_prog(const char *log_file, const char *opt_log_file,
84110
85111 if (log == NULL )
86112 pg_log (PG_FATAL , "cannot write to log file %s\n" , log_file );
113+
87114#ifdef WIN32
88- fprintf (log , "\n\n" );
115+ /* Are we printing "command:" before its output? */
116+ if (mainThreadId == GetCurrentThreadId ())
117+ fprintf (log , "\n\n" );
89118#endif
90- pg_log (PG_VERBOSE , "%s\n" , cmd );
91119 fprintf (log , "command: %s\n" , cmd );
120+ #ifdef WIN32
121+ /* Are we printing "command:" after its output? */
122+ if (mainThreadId != GetCurrentThreadId ())
123+ fprintf (log , "\n\n" );
124+ #endif
92125
93126 /*
94127 * In Windows, we must close the log file at this point so the file is not
95128 * open while the command is running, or we get a share violation.
96129 */
97130 fclose (log );
98131
99- result = system (cmd );
132+ #ifdef WIN32
133+ /* see comment above */
134+ if (mainThreadId == GetCurrentThreadId ())
135+ #endif
136+ result = system (cmd );
100137
101138 if (result != 0 )
102139 {
@@ -118,7 +155,6 @@ exec_prog(const char *log_file, const char *opt_log_file,
118155 }
119156
120157#ifndef WIN32
121-
122158 /*
123159 * We can't do this on Windows because it will keep the "pg_ctl start"
124160 * output filename open until the server stops, so we do the \n\n above on
0 commit comments