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