sys_close (int fd)
{
int rc = -1;
+ bool reader_thread_exited = false;
if (fd < 0)
{
if (fd < MAXDESC && fd_info[fd].cp)
{
child_process * cp = fd_info[fd].cp;
+ DWORD thrd_status = STILL_ACTIVE;
+
+ /* Thread handle will be NULL if we already called delete_child. */
+ if (cp->thrd != NULL
+ && GetExitCodeThread (cp->thrd, &thrd_status)
+ && thrd_status != STILL_ACTIVE)
+ reader_thread_exited = true;
fd_info[fd].cp = NULL;
because socket handles are fully fledged kernel handles. */
if (fd < MAXDESC)
{
- if ((fd_info[fd].flags & FILE_DONT_CLOSE) == 0)
+ if ((fd_info[fd].flags & FILE_DONT_CLOSE) == 0
+ /* If the reader thread already exited, close the descriptor,
+ since otherwise no one will close it, and we will be
+ leaking descriptors. */
+ || reader_thread_exited)
{
fd_info[fd].flags = 0;
rc = _close (fd);
else
{
/* We don't close here descriptors open by pipe processes
- for reading from the pipe, because the reader thread
- might be stuck in _sys_read_ahead, and then we will hang
- here. If the reader thread exits normally, it will close
- the descriptor; otherwise we will leave a zombie thread
+ for reading from the pipe when the reader thread might
+ still be running, since that thread might be stuck in
+ _sys_read_ahead, and then we will hang here. If the
+ reader thread exits normally, it will close the
+ descriptor; otherwise we will leave a zombie thread
hanging around. */
rc = 0;
/* Leave the flag set for the reader thread to close the
}
/* If this thread was reading from a pipe process, close the
descriptor used for reading, as sys_close doesn't in that case. */
- if (fd_info[fd].flags == FILE_DONT_CLOSE)
+ if ((fd_info[fd].flags & FILE_DONT_CLOSE) == FILE_DONT_CLOSE)
{
- fd_info[fd].flags = 0;
- _close (fd);
+ int i;
+ /* If w32.c:sys_close is still processing this descriptor, wait
+ for a while for it to finish. */
+ for (i = 0; i < 5; i++)
+ {
+ if (fd_info[fd].flags == FILE_DONT_CLOSE)
+ {
+ fd_info[fd].flags = 0;
+ _close (fd);
+ break;
+ }
+ Sleep (5);
+ }
}
return 0;
}