Race condition spawning childs/pipe stuff?

Michelsen, Robert Robert.Michelsen@vitk.vossloh.com
Wed Oct 19 08:43:00 GMT 2005


I seem to encounter a race condition when running large recursive build
processes (make).
Occasionally, the build process hangs with a spawned child (sh.exe)
eating with 100% user cpu.
It seems the build command itself (spawned make) finished but
child/parent? shell doesnt exit.

When i kill sh.exe manually, the (recursive) build process continues and
I suspect some kind of race condition somewhere in pipe stuff.

The condition itself is not reproducable.

Cygwin dll is: 1.5.19, api ver: 0.138, build date: 2005-10-03 13:32

I attached gdb to process and examined threads:

----------- snip ----
$ ./gdb
GNU gdb
(gdb) attach 3048
Attaching to process 3048

[Switching to thread 3048.0xca8]
(gdb) info threads
* 3 thread 3048.0xca8  0x7c911231 in ntdll!DbgUiConnectToDbg () from
  2 thread 3048.0xd04  0x7c91eb94 in ntdll!LdrAccessResource () from
  1 thread 3048.0xf90  0x7c91eb94 in ntdll!LdrAccessResource () from

(gdb) thread 1
[Switching to thread 1 (thread 3048.0xf90)]#0  0x7c91eb94 in
ntdll!LdrAccessResource ()
   from /cygdrive/c/WINDOWS/system32/ntdll.dll
(gdb) bt
#0  0x7c91eb94 in ntdll!LdrAccessResource () from
#1  0x7c91ea53 in ntdll!ZwYieldExecution () from
#2  0x7c81e956 in SwitchToThread () from
#3  0x61054215 in low_priority_sleep (secs=0) at
#4  0xfffffffe in ?? ()

(gdb) thread 2
[Switching to thread 2 (thread 3048.0xd04)]#0  0x7c91eb94 in
ntdll!LdrAccessResource ()
   from /cygdrive/c/WINDOWS/system32/ntdll.dll
(gdb) bt
#0  0x7c91eb94 in ntdll!LdrAccessResource () from
#1  0x7c91e288 in ntdll!ZwReadFile () from
#2  0x7c801875 in ReadFile () from
#3  0x0000074c in ?? ()

(gdb) thread 3
[Switching to thread 3 (thread 3048.0xca8)]#0  0x7c911231 in
ntdll!DbgUiConnectToDbg ()
   from /cygdrive/c/WINDOWS/system32/ntdll.dll
(gdb) bt
#0  0x7c911231 in ntdll!DbgUiConnectToDbg () from
#1  0x7c9607a8 in ntdll!KiIntSystemCall () from
#2  0x00000005 in ?? ()

(gdb) q
The program is running.  Quit anyway (and detach it)? (y or n) y
Detaching from program: , Pid 3048

----------- snip ----

Thread 1 seems to be the eater.
Gdb doesnt reveal much info so i used my favorite win32 user mode
debugger, ollydbg:

----------- snip ----

Ident      Entry      Data block   Last error                   Status
Priority   User time     System time
00000388   7C96077B   7FFDD000     ERROR_SUCCESS (00000000)     Active
32 + 0       0.0000 s      0.0000 s
00000D04   7C810856   7FFDE000     ERROR_SUCCESS (00000000)     Active
32 + 0       0.0000 s      0.0000 s
00000F90   00000000   7FFDF000     ERROR_SUCCESS (00000000)     Active
32 + 0      52.8437 s     94.5156 s

----------- snip ----

You see (main) thread 0xf90 is eating all the cpu.
I examined the call stack and used gdb's "l/info" commands to get
symbols (i have appropriate .dbg file)
I manually added the symbols as comments "(xxxx)":

----------- snip ----
Call stack of main thread
Address    Stack      Procedure
Called from                   Frame
0022DD84   7C91EA53   Includes ntdll.KiFastSystemCallRet
0022DD88   7C81E956   ntdll.ZwYieldExecution
0022DD8C   61054215   cygwin1.610F5138
cygwin1.61054210 (low_priority_sleep + 80)
0022DDAC   6106DF57   cygwin1.610541C0 (low_priority_sleep,
miscfuncs.cc:230)   cygwin1.6106DF52 (_pinfo::sync_proc_pipe() + 34)
0022DDBC   61095984   cygwin1.6106DF30 (_pinfo::sync_proc_pipe(),
pinfo.cc:977) cygwin1.6109597F (spawn_guts(char const* ...) + 5263)
0022E99C   61095E35   ? cygwin1.610944F0 (spawn_guts(char const* ...),
spawn.cc) cygwin1.61095E30 (spawnve + 224)             0022E998
0022E9CC   610188AB   cygwin1.61095D50  (spawnve)
cygwin1.610188A6 (execve + 38)          	 0022E9C8

----------- snip ----

I searched the current cygwin sources and found following snippets ...

----- snip spawn.cc ----

static int __stdcall
spawn_guts (const char * prog_arg, const char *const *argv,
            const char *const envp[], int mode)

  /* If wr_proc_pipe doesn't exist then this process was not started by
a cygwin
         process.  So, we need to wait around until the process we've
just "execed"
         dies.  Use our own wait facility to wait for our own pid to
exit (there
         is some minor special case code in proc_waiter and friends to

         If wr_proc_pipe exists, then it should be duplicated to the
         If the child has exited already, that's ok.  The parent will
pick up
         on this fact when we exit.  dup_proc_pipe will close our end of
the pipe.
         Note that wr_proc_pipe may also be == INVALID_HANDLE_VALUE.
That will make
         dup_proc_pipe essentially a no-op.  */
      if (!newargv.win16_exe && myself->wr_proc_pipe)
          myself->sync_proc_pipe ();        /* Make sure that we own
                                           just in case we've been
                                           execed. */
          myself.zap_cwd ();
          myself->dup_proc_pipe (pi.hProcess);

----- snip pinfo.cc ----

_pinfo::sync_proc_pipe ()
  if (wr_proc_pipe && wr_proc_pipe != INVALID_HANDLE_VALUE)
    while (wr_proc_pipe_owner != GetCurrentProcessId ())
      low_priority_sleep (0);


It seems "sync_proc_pipe" is looping forever because the condition
"wr_proc_pipe_owner != GetCurrentProcessId ()" is satisfied but never

I updated cygwin core several times but this kind of error persists.

What gives?


Robert Michelsen

Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/

More information about the Cygwin mailing list