Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
glibc/nptl_db/td_thr_tsd.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
96 lines (78 sloc)
2.91 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Get a thread-specific data pointer for a thread. | |
Copyright (C) 1999-2016 Free Software Foundation, Inc. | |
This file is part of the GNU C Library. | |
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. | |
The GNU C Library is free software; you can redistribute it and/or | |
modify it under the terms of the GNU Lesser General Public | |
License as published by the Free Software Foundation; either | |
version 2.1 of the License, or (at your option) any later version. | |
The GNU C Library is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
Lesser General Public License for more details. | |
You should have received a copy of the GNU Lesser General Public | |
License along with the GNU C Library; if not, see | |
<http://www.gnu.org/licenses/>. */ | |
#include <stdint.h> | |
#include "thread_dbP.h" | |
td_err_e | |
td_thr_tsd (const td_thrhandle_t *th, const thread_key_t tk, void **data) | |
{ | |
td_err_e err; | |
psaddr_t tk_seq, level1, level2, seq, value; | |
void *copy; | |
uint32_t pthread_key_2ndlevel_size, idx1st, idx2nd; | |
LOG ("td_thr_tsd"); | |
/* Get the key entry. */ | |
err = DB_GET_VALUE (tk_seq, th->th_ta_p, __pthread_keys, tk); | |
if (err == TD_NOAPLIC) | |
return TD_BADKEY; | |
if (err != TD_OK) | |
return err; | |
/* Fail if this key is not at all used. */ | |
if (((uintptr_t) tk_seq & 1) == 0) | |
return TD_BADKEY; | |
/* This makes sure we have the size information on hand. */ | |
err = DB_GET_FIELD_ADDRESS (level2, th->th_ta_p, 0, pthread_key_data_level2, | |
data, 1); | |
if (err != TD_OK) | |
return err; | |
/* Compute the indeces. */ | |
pthread_key_2ndlevel_size | |
= DB_DESC_NELEM (th->th_ta_p->ta_field_pthread_key_data_level2_data); | |
idx1st = tk / pthread_key_2ndlevel_size; | |
idx2nd = tk % pthread_key_2ndlevel_size; | |
/* Now fetch the first level pointer. */ | |
err = DB_GET_FIELD (level1, th->th_ta_p, th->th_unique, pthread, | |
specific, idx1st); | |
if (err == TD_NOAPLIC) | |
return TD_DBERR; | |
if (err != TD_OK) | |
return err; | |
/* Check the pointer to the second level array. */ | |
if (level1 == 0) | |
return TD_NOTSD; | |
/* Locate the element within the second level array. */ | |
err = DB_GET_FIELD_ADDRESS (level2, th->th_ta_p, | |
level1, pthread_key_data_level2, data, idx2nd); | |
if (err == TD_NOAPLIC) | |
return TD_DBERR; | |
if (err != TD_OK) | |
return err; | |
/* Now copy in that whole structure. */ | |
err = DB_GET_STRUCT (copy, th->th_ta_p, level2, pthread_key_data); | |
if (err != TD_OK) | |
return err; | |
/* Check whether the data is valid. */ | |
err = DB_GET_FIELD_LOCAL (seq, th->th_ta_p, copy, pthread_key_data, seq, 0); | |
if (err != TD_OK) | |
return err; | |
if (seq != tk_seq) | |
return TD_NOTSD; | |
/* Finally, fetch the value. */ | |
err = DB_GET_FIELD_LOCAL (value, th->th_ta_p, copy, pthread_key_data, | |
data, 0); | |
if (err == TD_OK) | |
*data = value; | |
return err; | |
} |