https://bugs.winehq.org/show_bug.cgi?id=35344
Damjan Jovanovic damjan.jov@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Keywords| |download, source Component|-unknown |wineserver
--- Comment #6 from Damjan Jovanovic damjan.jov@gmail.com --- Luckily it's an open-source Windows API app, ie. our dogfood, so we can see what's going on easily.
We know fork() fails. In Cygwin's source code, the chain of events looks as follows: 1) fork() in winsup/cygwin/sigproc.h calls dofork(). 2) dofork() then tries to construct a local hold_everything of type hold_everything. 3) This class hold_everything in winsup/cygwin/sigproc.h has a field lock_signals signals which will be initialized by its constructor. 4) This constructor for lock_signals (same file) does: worked = sig_send (NULL, __SIGHOLD) == 0 5) That sig_send() in winsup/cygwin/sigproc.cc writes to HANDLE sendsig, which is the global static HANDLE my_sendsig in this particular call, then tries to WaitForSingleObject (pack.wakeup, WSSC) where WSSC is 60000 (which explains why fork() takes extremely long to fail). This however fails with WAIT_TIMEOUT so sig_send() sets errno=ENOSYS and returns with -1.
Why does writing to my_sendsig not generate a response on pack.wakeup in due time? 1. During Cygwin startup, dll_crt0_0() in winsup/cygwin/dcrt0.cc calls sigproc_init(), as does dll_crt0_1() if dynamically_loaded is true. 2. sigproc_init() in winsup/cygwin/sigproc.cc calls: new cygthread (wait_sig, cygself, "sig"); 3. wait_sig() in winsup/cygwin/sigproc.cc is meant to signal pack.wakeup.
But 3 never happens, that is, the new cygthread(...) does not result in the thread getting created and the wait_sig() function getting called to signal the fork() thread. Why not?
cygthread (LPVOID_THREAD_START_ROUTINE start, LPVOID param, const char *name) : __name (name), func ((LPTHREAD_START_ROUTINE) start), arglen (0), arg (param), notify_detached (NULL) { QueueUserAPC (async_create, GetCurrentThread (), (ULONG_PTR) this); //create(); }
If QueueUserAPC() is commented and create() uncommented, the thread starts and another failure happens later on, but for now let's debug QueueUserAPC().
async_create() definitely doesn't get called, so the failure is between QueueUserAPC() and the callback it is given. This looks like a Wine bug.
In Wine: 1. kernel32.dll QueueUserAPC() 2. ntdll.dll NtQueueApcThread() 3. wineserver DECL_HANDLER(queue_apc) 4. wineserver queue_apc()
Since the first 2 are trivial, let's focus on wineserver. queue_apc() calls get_apc_queue() to retrieve &thread->user_apc, then adds the APC to the queue, and since it's the first in the queue, calls wake_thread( thread ).
wake_thread() returns 0, meaning the wait condition is still not satisfied. It's not clear whether this a problem though.
Next, the APC must come out of wineserver and return to the application so it can be run and the thread created. How would that happen?
---
Setting the component to "wineserver" for now, until I investigate the APC's return trip.
Is there anyone more familiar with APCs that can help?