Why is __sglue initialized in _cygtls::init_thread()?

Corinna Vinschen vinschen@redhat.com
Fri Apr 1 13:34:26 GMT 2022

On Mar 30 10:58, Sebastian Huber wrote:
> Hello,
> I have a question to _cygtls::init_thread():
> void
> _cygtls::init_thread (void *x, DWORD (*func) (void *, void *))
> {
>   if (x)
>     {
>       memset (this, 0, sizeof (*this));
>       _REENT_INIT_PTR (&local_clib);
>       stackptr = stack;
>       altstack.ss_flags = SS_DISABLE;
>       if (_GLOBAL_REENT)
> 	{
> 	  local_clib._stdin = _GLOBAL_REENT->_stdin;
> 	  local_clib._stdout = _GLOBAL_REENT->_stdout;
> 	  local_clib._stderr = _GLOBAL_REENT->_stderr;
> 	  if (_GLOBAL_REENT->__cleanup)
> 	    local_clib.__cleanup = _cygtls::cleanup_early;
> 	  local_clib.__sglue._niobs = 3;
> 	  local_clib.__sglue._iobs = &_GLOBAL_REENT->__sf[0];
> 	}
>     }
> Why is __sglue initialized here? It seems to be unused in general for
> local_clib.__sglue:
> 1. The __sglue::next member was still NULL, so even if someone calls
> _reclaim_reent(), cleanup_glue() would not get called.
> 2. FILE objects are added to the __sglue list only by __sfp().  This
> function only uses the __sglue member of _GLOBAL_REENT.

Yes, all threads basically just copy _GLOBAL_REENT stdio.

> It could be used by _fcloseall_r() through _fwalk_reent() which seems to be
> unused by Cygwin.

It's used, see cygwin_setmode() in syscalls.cc.

> It could be used by __fp_lock_all() and __fp_unlock_all() through _fwalk()
> which is used only by Cygwin in the pthread::atfork*() functions.
> It could be used by _cleanup_r() through _fwalk_reent().

The original reason to do this is hidden in history, apparently.
git blame points to an 18 years old patch from Chris Faylor:

commit 5e0f482f2cac33d5ce758e4dc0f665a4e195f4e1
Author: Christopher Faylor <...>
Date:   Mon Jan 26 18:52:02 2004 +0000

    * cygtls.cc (_threadinfo::init_thread): Add more local reent stdio
    * dcrt0.cc (initial_env): Can it really be true that XP doesn't allow attaching
    a debugger during DLL attach?  Add temporary workaround.
    (dll_crt0_0): Ensure that _impure_ptr stdio is initialized before any threads.
    (dll_crt0_1): Move _impure_ptr initialization to dll_crt0_0.
    * exceptions.cc (try_to_debug): Reinstate old method for looping while
    * syscalls.cc (_cygwin_istext_for_stdio): Regularize debugging output.  Remove
    hopefully extraneous check.
    (setmode_helper): Add debugging output for improbable case.  Use "binary"
    rather "raw" for consistency.

Guessing from the commit message, it seems this is just trying to copy
the essential stdio parts for the per-thread _REENT initialization.

> In the above three cases the file walk would operate on the three FILE
> objects in _GLOBAL_REENT->__sf. I would like to change the __sglue handling,
> so it would be great if someone could explain the Cygwin use case for the
> __sglue initialization in _cygtls::init_thread().

The use cases are probably just those you outlined above.  When changing
how __sglue works, just keep in mind that _cygtls::init_thread needs to
copy the essential global stdio state into the per-thread _REENT.  Given
that __sglue is never actually used *directly* by Cygwin, any change
within newlib should be transparent to Cygwin.


More information about the Newlib mailing list