On May 27 17:17, Corinna Vinschen wrote:
> On May 27 14:23, Corinna Vinschen wrote:
> > Hi Takashi,
> > 
> > On May 21 20:53, Takashi Yano wrote:
> > > [...]
> > > +  if (output_handle_local)
> > > +    {
> > > +      OBJECT_BASIC_INFORMATION obi;
> > > +      NTSTATUS status;
> > > +      ULONG hdl_cnt = 0;
> > > +
> > > +      status = NtQueryObject (output_handle_local, 
> > > ObjectBasicInformation,
> > > +   &obi, sizeof obi, NULL);
> > > +      if (!NT_SUCCESS (status))
> > > + debug_printf ("NtQueryObject: %y", status);
> > > +      else
> > > + hdl_cnt = obi.HandleCount;
> > > +      termios_printf("HandleCount: %d", hdl_cnt);
> > > +      if (hdl_cnt == 1)
> > > + SetEvent (input_available_event);
> > > +      CloseHandle (output_handle_local);
> > > +    }
> >  
> > Isn't that racy?  Consider two processes doing that at the same time.
> > Both calls to NtQueryObject could come up with hdl_cnt == 2 and the
> > problem persists.
> > 
> > Wouldn't it be safer to call SetEvent(input_available_event) all the
> > time from here?
> 
> We discussed this already in March and only briefly talked about a
> change like this requiring changes to fhandler_pty_slave::read.
> However, I don't see this.  The read code already takes 0 bytes input
> and broken pipe scenarios into account.  Do you see something needing
> a change I don't?

Never mind, it doesn't work quite as expected, so changes would be
required.

I created another version of your patch which avoids duplicating the
tested handle and makes the test-and-close-handle operation atomic:

        * fhandler_tty.cc (fhandler_pty_common::close): Don't close output_mutex
        here.  Move into callers.
        (fhandler_pty_master::close): Use NtQueryObject instead of
        PeekNamedPipe to detect closing the last master handle.

diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index e91b3e3..12f6124 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -552,7 +552,10 @@ fhandler_pty_slave::close ()
        get_output_handle_cyg ());
   if ((unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ()))
     fhandler_console::free_console (); /* assumes that we are the last pty 
closer */
-  return fhandler_pty_common::close ();
+  fhandler_pty_common::close ();
+  if (!ForceCloseHandle (output_mutex))
+    termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex);
+  return 0;
 }
 
 int
@@ -1259,8 +1262,6 @@ fhandler_pty_common::close ()
   termios_printf ("pty%d <%p,%p> closing", get_minor (), get_handle (), 
get_output_handle ());
   if (!ForceCloseHandle (input_mutex))
     termios_printf ("CloseHandle (input_mutex<%p>), %E", input_mutex);
-  if (!ForceCloseHandle (output_mutex))
-    termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex);
   if (!ForceCloseHandle1 (get_handle (), from_pty))
     termios_printf ("CloseHandle (get_handle ()<%p>), %E", get_handle ());
   if (!ForceCloseHandle1 (get_output_handle (), to_pty))
@@ -1281,6 +1282,9 @@ fhandler_pty_master::cleanup ()
 int
 fhandler_pty_master::close ()
 {
+  OBJECT_BASIC_INFORMATION obi;
+  NTSTATUS status;
+
   termios_printf ("closing from_master(%p)/to_master(%p)/to_master_cyg(%p) 
since we own them(%u)",
                  from_master, to_master, to_master_cyg, dwProcessId);
   if (cygwin_finished_initializing)
@@ -1309,13 +1313,22 @@ fhandler_pty_master::close ()
        }
     }
 
-  fhandler_pty_common::close ();
-
   /* Check if the last master handle has been closed.  If so, set
      input_available_event to wake up potentially waiting slaves. */
-  if (!PeekNamedPipe (from_master, NULL, 0, NULL, NULL, NULL)
-      && GetLastError () == ERROR_BROKEN_PIPE) 
-    SetEvent (input_available_event);
+  acquire_output_mutex (INFINITE);
+  status = NtQueryObject (get_output_handle (), ObjectBasicInformation,
+                         &obi, sizeof obi, NULL);
+  fhandler_pty_common::close ();
+  release_output_mutex ();
+  if (!ForceCloseHandle (output_mutex))
+    termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex);
+  if (!NT_SUCCESS (status))
+    debug_printf ("NtQueryObject: %y", status);
+  else if (obi.HandleCount == 1)
+    {
+      termios_printf("Closing last master");
+      SetEvent (input_available_event);
+    }
 
   if (!ForceCloseHandle (from_master))
     termios_printf ("error closing from_master %p, %E", from_master);

Does that look ok?  It fixes the reported problem for me.


Thanks,
Corinna

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Maintainer                 cygwin AT cygwin DOT com
Red Hat

Attachment: pgp2AtKGtAz0B.pgp
Description: PGP signature

Reply via email to