Hi,

Since the basic problem is that `getopt` doesn't have a per-task value it
can use, how would it keep track of which TLS key it's been allocated?

Here's what I found in libc that would need task (thread) specific data:

  - libs/libc/misc/lib_umask.c has g_mask
  - libs/libc/libgen/lib_dirname.c and libs/libc/libgen/lib_basename each
have a g_retchar
  - libs/libc/syslog/lib_setlogmask.c has g_syslog_mask (and a comment
describing this issue)
  - libs/libc/pwd/* uses either g_passwd and g_passwd_buffer or g_pwd and
g_buf
  - libs/libc/grp/* uses a similar pair for group data
  - libs/libc/unistd/lib_getopt.c we know of, it has four words of global
data
  - libs/libc/time/lib_localtime.c uses g_tm and may need per-task timezone
settings
  - libs/libc/netdb/lib_netdb.c specifies h_errno as a global
  - libs/libc/netdb/lib_gethostbyname2.c  and lib_gethostbyaddr.c use
g_hostent and g_hostbuffer
  - libs/libc/stdlib/lib_srand.c uses a variety of globals depending on
build options
  - libs/libc/string/lib_strtok.c uses g_saveptr

Statically allocating a TLS key for each module would consume around 11
keys in each task. Dynamically allocated TLS keys cannot ever be released,
because these are globals handed over to user code with no indication when
they're no longer needed. It may be better to have an additional static
element in tls_info_s pointing to a heap-allocated structure containing the
libc globals. Functionally this is the same as a statically reserved TLS
key, but it's clearer what it's for.

-- 
Byron

On Thu, Mar 25, 2021 at 12:51 AM Gregory Nutt <spudan...@gmail.com> wrote:

> On 3/24/2021 8:38 AM, Matias N. wrote:
> > So, if I follow correctly, we could maybe have one TLS pointer pointing
> to a struct of pointers, one per each group of globals (one of this groups,
> would be the set of variables used by getopt()), like:
> >
> > struct task_globals_s
> > {
> >    struct getopt_globals_s *getopt_globals;
> >    /* ...others */
> > };
> >
> > Then getopt globals would only be allocated once for each task, and only
> when getopt() is called.
> >
> > Something like that?
>
> Yes, that is a possibility.  But that is already implemented just as you
> describe as POSIX thread-specific data.
>
> The TLS data structure is defined in include/nuttx/tls.h as following.
> it is just an array of pointer size things and the errno variable.
>
>     struct tls_info_s
>     {
>     #if CONFIG_TLS_NELEM > 0
>        uintptr_t tl_elem[CONFIG_TLS_NELEM]; /* TLS elements */
>     #endif
>        int tl_errno;                        /* Per-thread error number */
>     };
>
> This structure lies at the "bottom" of stack of every thread in user space.
>
> The standard pthread_getspecific() is then implemented as:
>
>     FAR void *pthread_getspecific(pthread_key_t key)
>     {
>        return (FAR void *)tls_get_value((int)key);
>     }
>
> Where
>
>     uintptr_t tls_get_value(int tlsindex)
>     {
>        FAR struct tls_info_s *info;
>        uintptr_t ret = 0;
>
>        DEBUGASSERT(tlsindex >= 0 && tlsindex < CONFIG_TLS_NELEM);
>        if (tlsindex >= 0 && tlsindex < CONFIG_TLS_NELEM)
>          {
>            /* Get the TLS info structure from the current threads stack */
>
>            info = up_tls_info();
>            DEBUGASSERT(info != NULL);
>
>            /* Get the element value from the TLS info. */
>
>            ret = info->tl_elem[tlsindex];
>          }
>
>        return ret;
>     }
>
> The POSIX interface supports a pthread_key_create() to manage the indexing.
>
>
>
>

Reply via email to