diff options
Diffstat (limited to 'libpthread/nptl_db/td_thr_tsd.c')
| -rw-r--r-- | libpthread/nptl_db/td_thr_tsd.c | 96 | 
1 files changed, 96 insertions, 0 deletions
| diff --git a/libpthread/nptl_db/td_thr_tsd.c b/libpthread/nptl_db/td_thr_tsd.c new file mode 100644 index 000000000..08f617b7d --- /dev/null +++ b/libpthread/nptl_db/td_thr_tsd.c @@ -0,0 +1,96 @@ +/* Get a thread-specific data pointer for a thread. +   Copyright (C) 1999,2001,2002,2003 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#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; +} | 
