1  /* Allocate a new thread structure.
       2     Copyright (C) 2000-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library;  if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <assert.h>
      20  #include <errno.h>
      21  #include <pthread.h>
      22  #include <stdlib.h>
      23  #include <string.h>
      24  
      25  #include <pt-internal.h>
      26  
      27  /* This braindamage is necessary because the standard says that some
      28     of the threads functions "shall fail" if "No thread could be found
      29     corresponding to that specified by the given thread ID."  */
      30  
      31  /* The size of the thread ID lookup table.  */
      32  int __pthread_max_threads;
      33  
      34  /* List of thread structures corresponding to free thread IDs.  */
      35  struct __pthread *__pthread_free_threads;
      36  pthread_mutex_t __pthread_free_threads_lock;
      37  
      38  static inline error_t
      39  initialize_pthread (struct __pthread *new)
      40  {
      41    error_t err;
      42  
      43    err = __pthread_init_specific (new);
      44    if (err)
      45      return err;
      46  
      47    new->nr_refs = 1;
      48    new->cancel_lock = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
      49    new->cancel_hook = NULL;
      50    new->cancel_hook_arg = NULL;
      51    new->cancel_state = PTHREAD_CANCEL_ENABLE;
      52    new->cancel_type = PTHREAD_CANCEL_DEFERRED;
      53    new->cancel_pending = 0;
      54  
      55    new->state_lock = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
      56    new->state_cond = (pthread_cond_t) PTHREAD_COND_INITIALIZER;
      57    new->terminated = FALSE;
      58  
      59    memset (&new->res_state, '\0', sizeof (new->res_state));
      60  
      61    new->tcb = NULL;
      62  
      63    new->next = 0;
      64    new->prevp = 0;
      65  
      66    return 0;
      67  }
      68  
      69  
      70  /* Allocate a new thread structure and its pthread thread ID (but not
      71     a kernel thread).  */
      72  int
      73  __pthread_alloc (struct __pthread **pthread)
      74  {
      75    error_t err;
      76  
      77    struct __pthread *new;
      78    struct __pthread **threads;
      79    struct __pthread **old_threads;
      80    int max_threads;
      81    int new_max_threads;
      82  
      83    __pthread_mutex_lock (&__pthread_free_threads_lock);
      84    for (new = __pthread_free_threads; new; new = new->next)
      85      {
      86        /* There is no need to take NEW->STATE_LOCK: if NEW is on this
      87           list, then it is protected by __PTHREAD_FREE_THREADS_LOCK
      88           except in __pthread_dealloc_finish where after it is added to the
      89           list (with the lock held), it drops the lock and then sets
      90           NEW->STATE and immediately stops using NEW.  */
      91        if (new->terminated)
      92  	{
      93  	  __pthread_dequeue (new);
      94  	  break;
      95  	}
      96      }
      97    __pthread_mutex_unlock (&__pthread_free_threads_lock);
      98  
      99    if (new)
     100      {
     101        if (new->tcb)
     102  	{
     103  	  /* Drop old values */
     104  	  _dl_deallocate_tls (new->tcb, 1);
     105  	}
     106  
     107        err = initialize_pthread (new);
     108        if (!err)
     109  	*pthread = new;
     110        return err;
     111      }
     112  
     113    /* Allocate a new thread structure.  */
     114    new = malloc (sizeof (struct __pthread));
     115    if (new == NULL)
     116      return ENOMEM;
     117  
     118    err = initialize_pthread (new);
     119    if (err)
     120      {
     121        free (new);
     122        return err;
     123      }
     124  
     125  retry:
     126    __libc_rwlock_wrlock (GL (dl_pthread_threads_lock));
     127  
     128    if (GL (dl_pthread_num_threads) < __pthread_max_threads)
     129      {
     130        /* We have a free slot.  Use the slot number plus one as the
     131           thread ID for the new thread.  */
     132        new->thread = 1 + GL (dl_pthread_num_threads)++;
     133        GL (dl_pthread_threads)[new->thread - 1] = NULL;
     134  
     135        __libc_rwlock_unlock (GL (dl_pthread_threads_lock));
     136  
     137        *pthread = new;
     138        return 0;
     139      }
     140  #ifdef PTHREAD_THREADS_MAX
     141    else if (GL (dl_pthread_num_threads) >= PTHREAD_THREADS_MAX)
     142      {
     143        /* We have reached the limit on the number of threads per process.  */
     144        __libc_rwlock_unlock (GL (dl_pthread_threads_lock));
     145  
     146        free (new);
     147        return EAGAIN;
     148      }
     149  #endif
     150  
     151    /* We are going to enlarge the threads table.  Save its current
     152       size.  We're going to release the lock before doing the necessary
     153       memory allocation, since that's a potentially blocking operation.  */
     154    max_threads = __pthread_max_threads;
     155  
     156    __libc_rwlock_unlock (GL (dl_pthread_threads_lock));
     157  
     158    /* Allocate a new lookup table that's twice as large.  */
     159    new_max_threads
     160        = max_threads > 0 ? max_threads * 2 : _POSIX_THREAD_THREADS_MAX;
     161    threads = malloc (new_max_threads * sizeof (struct __pthread *));
     162    if (threads == NULL)
     163      {
     164        free (new);
     165        return ENOMEM;
     166      }
     167  
     168    __libc_rwlock_wrlock (GL (dl_pthread_threads_lock));
     169  
     170    /* Check if nobody else has already enlarged the table.  */
     171    if (max_threads != __pthread_max_threads)
     172      {
     173        /* Yep, they did.  */
     174        __libc_rwlock_unlock (GL (dl_pthread_threads_lock));
     175  
     176        /* Free the newly allocated table and try again to allocate a slot.  */
     177        free (threads);
     178        goto retry;
     179      }
     180  
     181    /* Copy over the contents of the old table.  */
     182    memcpy (threads, GL (dl_pthread_threads),
     183  	  __pthread_max_threads * sizeof (struct __pthread *));
     184  
     185    /* Save the location of the old table.  We want to deallocate its
     186       storage after we released the lock.  */
     187    old_threads = GL (dl_pthread_threads);
     188  
     189    /* Replace the table with the new one.  */
     190    __pthread_max_threads = new_max_threads;
     191    GL (dl_pthread_threads) = threads;
     192  
     193    /* And allocate ourselves one of the newly created slots.  */
     194    new->thread = 1 + GL (dl_pthread_num_threads)++;
     195    GL (dl_pthread_threads)[new->thread - 1] = NULL;
     196  
     197    __libc_rwlock_unlock (GL (dl_pthread_threads_lock));
     198  
     199    free (old_threads);
     200  
     201    *pthread = new;
     202    return 0;
     203  }
     204  
     205  void
     206  attribute_hidden
     207  __pthread_init_static_tls (struct link_map *map)
     208  {
     209    int i;
     210  
     211    __libc_rwlock_wrlock (GL (dl_pthread_threads_lock));
     212    for (i = 0; i < GL (dl_pthread_num_threads); ++i)
     213      {
     214        struct __pthread *t = GL (dl_pthread_threads)[i];
     215  
     216        if (t == NULL)
     217  	continue;
     218  
     219  # if TLS_TCB_AT_TP
     220        void *dest = (char *) t->tcb - map->l_tls_offset;
     221  # elif TLS_DTV_AT_TP
     222        void *dest = (char *) t->tcb + map->l_tls_offset + TLS_PRE_TCB_SIZE;
     223  # else
     224  #  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
     225  # endif
     226  
     227        /* Initialize the memory.  */
     228        memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
     229  	      '\0', map->l_tls_blocksize - map->l_tls_initimage_size);
     230      }
     231    __libc_rwlock_unlock (GL (dl_pthread_threads_lock));
     232  }