Blame nptl/pthread_setspecific.c

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