1 /* Copyright (C) 2002-2022 Free Software Foundation, Inc.
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 <stdlib.h>
19 #include "pthreadP.h"
20 #include <shlib-compat.h>
21 
22 void *
___pthread_getspecific(pthread_key_t key)23 ___pthread_getspecific (pthread_key_t key)
24 {
25   struct pthread_key_data *data;
26 
27   /* Special case access to the first 2nd-level block.  This is the
28      usual case.  */
29   if (__glibc_likely (key < PTHREAD_KEY_2NDLEVEL_SIZE))
30     data = &THREAD_SELF->specific_1stblock[key];
31   else
32     {
33       /* Verify the key is sane.  */
34       if (key >= PTHREAD_KEYS_MAX)
35 	/* Not valid.  */
36 	return NULL;
37 
38       unsigned int idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
39       unsigned int idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
40 
41       /* If the sequence number doesn't match or the key cannot be defined
42 	 for this thread since the second level array is not allocated
43 	 return NULL, too.  */
44       struct pthread_key_data *level2 = THREAD_GETMEM_NC (THREAD_SELF,
45 							  specific, idx1st);
46       if (level2 == NULL)
47 	/* Not allocated, therefore no data.  */
48 	return NULL;
49 
50       /* There is data.  */
51       data = &level2[idx2nd];
52     }
53 
54   void *result = data->data;
55   if (result != NULL)
56     {
57       uintptr_t seq = data->seq;
58 
59       if (__glibc_unlikely (seq != __pthread_keys[key].seq))
60 	result = data->data = NULL;
61     }
62 
63   return result;
64 }
65 versioned_symbol (libc, ___pthread_getspecific, pthread_getspecific,
66 		  GLIBC_2_34);
67 libc_hidden_ver (___pthread_getspecific, __pthread_getspecific)
68 #ifndef SHARED
69 strong_alias (___pthread_getspecific, __pthread_getspecific)
70 #endif
71 
72 #if OTHER_SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
73 compat_symbol (libpthread, ___pthread_getspecific, __pthread_getspecific,
74 	       GLIBC_2_0);
75 compat_symbol (libpthread, ___pthread_getspecific, pthread_getspecific,
76 	       GLIBC_2_0);
77 #endif
78