[Bug 35344] Cygwin's fork() always fails ( from post-install scripts onwards)

wine-bugs at winehq.org wine-bugs at winehq.org
Mon Aug 5 00:56:04 CDT 2019


https://bugs.winehq.org/show_bug.cgi?id=35344

Damjan Jovanovic <damjan.jov at gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |download, source
          Component|-unknown                    |wineserver

--- Comment #6 from Damjan Jovanovic <damjan.jov at 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?

-- 
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.



More information about the wine-bugs mailing list