[PATCH] Cygwin: Implement 'reserved' marker in fdtable entries
Mark Geisert
mark@maxrnd.com
Sun May 24 09:04:58 GMT 2026
Hi Christian,
Thank you for the review. I've inlined answers below...
On 5/22/2026 7:21 AM, Christian Franke wrote:
> Jon Turney wrote:
>> On 22/05/2026 08:28, Mark Geisert wrote:
>>> ...
>>>
>>> The notion is that an fdtable entry provided by cygheap_fdnew is marked
>>> so that another thread can't obtain it. Care is taken to reset the
>>> marker when the entry is no longer needed. Actually, in the usual case
>>> the marker is overwritten with a pointer to an fhandler_base structure,
>>> by the reserving thread, as the syscall completes.
>>>
>>> Reported-by: Christian Franke <Christian.Franke@t-online.de>
>>> Addresses: https://cygwin.com/pipermail/cygwin/2026-May/259664.html
>>> Signed-off-by: Mark Geisert <mark@maxrnd.com>
>>> Fixes: e859706578ba (* autoload.cc (NtCreateFile): Add.)
>>
>> Thanks!
>>
>> This all seems fine and reasonable, but I have a couple of small
>> comments.
>
> A test with an enhanced version of the STC was successful.
> I could push this version (attached) to cygwin-apps/stc if desired.
That sounds great to me!
[...]
>>> @@ -595,7 +599,11 @@ class cygheap_fdnew : public cygheap_fdmanip
>>> else
>>> fd = cygheap->fdtab.find_unused_handle (seed_fd + 1);
>>> if (fd >= 0)
>>> - locked = lockit;
>>> + {
>>> + locked = lockit;
>>> + /* mark as "reserved" for open(), or other syscall, in
>>> progress */
>>> + cygheap->fdtab[fd] = (fhandler_base *)(int64_t) fd;
>>
>> So, we're already relying on "a small integer cast to pointer can't
>> collide with an actual pointer value we might get" (which is fine).
>>
>> But then there's no reason why we can't use a distinct constant (like
>> 1 or -1), to indicate a reserved slow throughout, which would make
>> this easier to understand?
>
> If the current method is kept, I would suggest to change the cast to:
> (fhandler_base *)(intptr_t) fd
That looks good; I'm thinking of a #define defining the expression that
we decide on to lessen code clutter.
>>
>>> ...
>>> @@ -607,7 +615,18 @@ class cygheap_fdnew : public cygheap_fdmanip
>>> ~cygheap_fdnew ()
>>> {
>>> if (cygheap->fdtab[fd])
>>> - cygheap->fdtab[fd]->inc_refcnt ();
>>> + {
>>> + /* check if fdtab entry is a "reserved" marker */
>>> + if (cygheap->fdtab[fd] == (fhandler_base *)(int64_t) fd)
>>> + {
>>> + /* remove "reserved" marker */
>>> + cygheap->fdtab.lock ();
>>> + cygheap->fdtab[fd] = NULL;
>>> + cygheap->fdtab.unlock ();
>>> + }
>>> + else
>>> + cygheap->fdtab[fd]->inc_refcnt ();
>>> + }
>
> Are the fdtab.lock()/unlock() calls really needed here?
>
> If yes, this variant prevents nested lock()ing and leaves the unlock()
> for the base class dtor:
>
> {
> /* remove "reserved" marker */
> if (!locked)
> {
> cygheap->fdtab.lock ();
> locked = true;
> }
> cygheap->fdtab[fd] = NULL;
> }
I'm glad you raised this question! I do like your variant better.
I would update my patch to have this coding.
But your mentioning the lock being unlocked in the dtor made me look at
the classes again (in cygheap.h). The default on cygheap_fdnew() is to
lock the fdtable lock in the ctor. And now I see the lock is unlocked
in the dtor. SMH that means the fdtable is locked for the same duration
of time that my proposed "reserved" flag covers!
This shows us (me especially) that we don't currently have concurrent
open()s between threads as I assumed we did. Something like my scheme
could allow them, maybe, but the fdtable locking would have to be given
up to achieve it. Maybe this is something for the future...
The upshot is that only the patch to syscalls.cc is needed to fix the
issue you reported. The other changes are subject to withdrawal...
Comments welcome from anybody reading this.
Sheepishly,
..mark
More information about the Cygwin-patches
mailing list