Blame nptl/pthread_setspecific.c

Packit 6c4009
/* Copyright (C) 2002-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include "pthreadP.h"
Packit 6c4009
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
__pthread_setspecific (pthread_key_t key, const void *value)
Packit 6c4009
{
Packit 6c4009
  struct pthread *self;
Packit 6c4009
  unsigned int idx1st;
Packit 6c4009
  unsigned int idx2nd;
Packit 6c4009
  struct pthread_key_data *level2;
Packit 6c4009
  unsigned int seq;
Packit 6c4009
Packit 6c4009
  self = THREAD_SELF;
Packit 6c4009
Packit 6c4009
  /* Special case access to the first 2nd-level block.  This is the
Packit 6c4009
     usual case.  */
Packit 6c4009
  if (__glibc_likely (key < PTHREAD_KEY_2NDLEVEL_SIZE))
Packit 6c4009
    {
Packit 6c4009
      /* Verify the key is sane.  */
Packit 6c4009
      if (KEY_UNUSED ((seq = __pthread_keys[key].seq)))
Packit 6c4009
	/* Not valid.  */
Packit 6c4009
	return EINVAL;
Packit 6c4009
Packit 6c4009
      level2 = &self->specific_1stblock[key];
Packit 6c4009
Packit 6c4009
      /* Remember that we stored at least one set of data.  */
Packit 6c4009
      if (value != NULL)
Packit 6c4009
	THREAD_SETMEM (self, specific_used, true);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      if (key >= PTHREAD_KEYS_MAX
Packit 6c4009
	  || KEY_UNUSED ((seq = __pthread_keys[key].seq)))
Packit 6c4009
	/* Not valid.  */
Packit 6c4009
	return EINVAL;
Packit 6c4009
Packit 6c4009
      idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
Packit 6c4009
      idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
Packit 6c4009
Packit 6c4009
      /* This is the second level array.  Allocate it if necessary.  */
Packit 6c4009
      level2 = THREAD_GETMEM_NC (self, specific, idx1st);
Packit 6c4009
      if (level2 == NULL)
Packit 6c4009
	{
Packit 6c4009
	  if (value == NULL)
Packit 6c4009
	    /* We don't have to do anything.  The value would in any case
Packit 6c4009
	       be NULL.  We can save the memory allocation.  */
Packit 6c4009
	    return 0;
Packit 6c4009
Packit 6c4009
	  level2
Packit 6c4009
	    = (struct pthread_key_data *) calloc (PTHREAD_KEY_2NDLEVEL_SIZE,
Packit 6c4009
						  sizeof (*level2));
Packit 6c4009
	  if (level2 == NULL)
Packit 6c4009
	    return ENOMEM;
Packit 6c4009
Packit 6c4009
	  THREAD_SETMEM_NC (self, specific, idx1st, level2);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Pointer to the right array element.  */
Packit 6c4009
      level2 = &level2[idx2nd];
Packit 6c4009
Packit 6c4009
      /* Remember that we stored at least one set of data.  */
Packit 6c4009
      THREAD_SETMEM (self, specific_used, true);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Store the data and the sequence number so that we can recognize
Packit 6c4009
     stale data.  */
Packit 6c4009
  level2->seq = seq;
Packit 6c4009
  level2->data = (void *) value;
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
weak_alias (__pthread_setspecific, pthread_setspecific)
Packit 6c4009
hidden_def (__pthread_setspecific)