16.10.2020 19:18, Tom Lane wrote:
Oh, very interesting.
Now that you have it somewhat in captivity, maybe you could determine
some things:
1. Is it only stdout that's affected? What of other stdio streams?
(Note that testing stderr might be tricky because it's probably
line-buffered.)
stderr is affected too. Just replacing stdout with stderr in connect.c and 000_connect.pl gives the same result.
Moreover, the following modification:
...
outfile = fopen("out", "w");
...
fprintf(stdout, "stdout test\n");
fprintf(stderr, "stderr test\n");
fprintf(outfile, "outfile test\n");
WSACleanup();
...
---
for (my $i =0; $i < 100000; $i++) {
unlink('out');
IPC::Run::run(\@cmd, '>', \$stdout, '2>', \$stderr);
open(my $fh, '<', 'out') or die $!;
my $fileout = <$fh>;
ok(defined $fileout && $fileout ne '');
close($fh);
}
detects similar failures too. (On a fail the out file exists but has zero size.)
2. Does an fflush() just before, or just after, WSACleanup() fix it?
"fflush(NULL);" just before or after WSACleanup() fixes things.
I've managed to record in ProcMon the activity log for a failed run (aside normal runs). Excerpts from the log are attached. As we can see, the failed process doesn't even try to write into IPC-Run's temp file.
Depending on your answers to the above, maybe some hack like this
would be acceptable:
free(conn); #ifdef WIN32
+ fflush(NULL); WSACleanup(); #endif }
It's not very nice for a library to be doing global things like that,
but if the alternative is loss of output, maybe we should.
But now we see that the WSACleanup call is a global thing by itself.
But wait a minute: I just looked at Microsoft's docs [1] and found
In a multithreaded environment, WSACleanup terminates Windows Sockets operations for all threads.
This makes me (a) wonder if that explains the side-effects on stdio,
and (b) question why libpq is calling WSACleanup at all.
What if we arranged to call WSAStartup just once, during the first
libpq connection-open in a process, and then never did WSACleanup?
Surely the OS can cope with that, and it eliminates any risk that
WSACleanup breaks something.
What bothers me is:
There must be a call to WSACleanup for each successful call to WSAStartup. Only the final WSACleanup function call performs the actual cleanup. The preceding calls simply decrement an internal reference count in the WS2_32.DLL.
So third-party application developers should understand that when using libpq they would have to call WSACleanup one more time to perform "the actual cleanup". (And thus WSAStartup is kind of like a global thing too.)
But may be it's a way better than to have a confirmed risk of losing data.
Best regards,
Alexander