(root)/
glibc-2.38/
nptl/
nptl_deallocate_tsd.c
       1  /* Deallocation thread-specific data structures related to pthread_key_create.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <pthreadP.h>
      19  
      20  /* Deallocate POSIX thread-local-storage.  */
      21  void
      22  __nptl_deallocate_tsd (void)
      23  {
      24    struct pthread *self = THREAD_SELF;
      25  
      26    /* Maybe no data was ever allocated.  This happens often so we have
      27       a flag for this.  */
      28    if (THREAD_GETMEM (self, specific_used))
      29      {
      30        size_t round;
      31        size_t cnt;
      32  
      33        round = 0;
      34        do
      35          {
      36            size_t idx;
      37  
      38            /* So far no new nonzero data entry.  */
      39            THREAD_SETMEM (self, specific_used, false);
      40  
      41            for (cnt = idx = 0; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
      42              {
      43                struct pthread_key_data *level2;
      44  
      45                level2 = THREAD_GETMEM_NC (self, specific, cnt);
      46  
      47                if (level2 != NULL)
      48                  {
      49                    size_t inner;
      50  
      51                    for (inner = 0; inner < PTHREAD_KEY_2NDLEVEL_SIZE;
      52                         ++inner, ++idx)
      53                      {
      54                        void *data = level2[inner].data;
      55  
      56                        if (data != NULL)
      57                          {
      58                            /* Always clear the data.  */
      59                            level2[inner].data = NULL;
      60  
      61                            /* Make sure the data corresponds to a valid
      62                               key.  This test fails if the key was
      63                               deallocated and also if it was
      64                               re-allocated.  It is the user's
      65                               responsibility to free the memory in this
      66                               case.  */
      67                            if (level2[inner].seq
      68                                == __pthread_keys[idx].seq
      69                                /* It is not necessary to register a destructor
      70                                   function.  */
      71                                && __pthread_keys[idx].destr != NULL)
      72                              /* Call the user-provided destructor.  */
      73                              __pthread_keys[idx].destr (data);
      74                          }
      75                      }
      76                  }
      77                else
      78                  idx += PTHREAD_KEY_1STLEVEL_SIZE;
      79              }
      80  
      81            if (THREAD_GETMEM (self, specific_used) == 0)
      82              /* No data has been modified.  */
      83              goto just_free;
      84          }
      85        /* We only repeat the process a fixed number of times.  */
      86        while (__builtin_expect (++round < PTHREAD_DESTRUCTOR_ITERATIONS, 0));
      87  
      88        /* Just clear the memory of the first block for reuse.  */
      89        memset (&THREAD_SELF->specific_1stblock, '\0',
      90                sizeof (self->specific_1stblock));
      91  
      92      just_free:
      93        /* Free the memory for the other blocks.  */
      94        for (cnt = 1; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
      95          {
      96            struct pthread_key_data *level2;
      97  
      98            level2 = THREAD_GETMEM_NC (self, specific, cnt);
      99            if (level2 != NULL)
     100              {
     101                /* The first block is allocated as part of the thread
     102                   descriptor.  */
     103                free (level2);
     104                THREAD_SETMEM_NC (self, specific, cnt, NULL);
     105              }
     106          }
     107  
     108        THREAD_SETMEM (self, specific_used, false);
     109      }
     110  }
     111  libc_hidden_def (__nptl_deallocate_tsd)