performance improvement in cygthread::detach()

Joe Buehler
Fri May 9 17:11:00 GMT 2003


One of the things I noticed while doing some tracing is that there can
be a performance hit for a pipe read in cygthread::detach() in the following:

	  HANDLE w4[2];
	  w4[0] = signal_arrived;
	  w4[1] = *this;
	  res = WaitForSingleObject (sigwait, INFINITE);
	  if (res != WAIT_OBJECT_0)
	    system_printf ("WFSO sigwait %p failed, res %u, %E", sigwait, res);
	  res = WaitForMultipleObjects (2, w4, FALSE, INFINITE);
	  if (res != WAIT_OBJECT_0)
	    /* nothing */;
	  else if (WaitForSingleObject (sigwait, 5) == WAIT_OBJECT_0)
	    res = WaitForSingleObject (*this, INFINITE);
	      signalled = true;
	      terminate_thread ();
	      set_sig_errno (EINTR);	/* caller should be dealing with return
					   values. */

The fhandler_base::raw_read() code in the separate reader cygthread does a SetEvent(),
then a ReadFile(), then another SetEvent().  The above code waits for the SetEvent(),
then waits for a signal or reader thread exit, then does another wait for SetEvent()
with timeout.

There is a timing race.  On a fast dual-processor machine (e.g.) the separate reader thread
can be done before the first WaitForSingleObject() call in the code above.  SetEvent will
be called twice before detach() does its first test.  This means that the second
WaitForSingleObject() will wait 5 mS for an event that will never arrive, since raw_read()
already did two SetEvent() calls.

I observed this happening in ksh code like X=$(expr 0 + 1).  The expr is a ksh93 builtin
that runs very fast.  The subprocess that writes "1" to the pipe that ksh is reading
to set X can exit before detach() is even looking for it to start.  And thus the performance
hit -- the data has been read but detach() is delaying unnecessarily.

An easy fix is a semaphore or two separate events, so the first and second event signals
from the reader thread can be distinguished.
Joe Buehler

More information about the Cygwin-developers mailing list