Back to index

glibc  2.9
specific.c
Go to the documentation of this file.
00001 /* Linuxthreads - a simple clone()-based implementation of Posix        */
00002 /* threads for Linux.                                                   */
00003 /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
00004 /*                                                                      */
00005 /* This program is free software; you can redistribute it and/or        */
00006 /* modify it under the terms of the GNU Library General Public License  */
00007 /* as published by the Free Software Foundation; either version 2       */
00008 /* of the License, or (at your option) any later version.               */
00009 /*                                                                      */
00010 /* This program is distributed in the hope that it will be useful,      */
00011 /* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
00012 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
00013 /* GNU Library General Public License for more details.                 */
00014 
00015 /* Thread-specific data */
00016 
00017 #include <errno.h>
00018 #include <stddef.h>
00019 #include <stdlib.h>
00020 #include "pthread.h"
00021 #include "internals.h"
00022 #include "spinlock.h"
00023 #include "restart.h"
00024 #include <bits/libc-lock.h>
00025 #include <not-cancel.h>
00026 
00027 /* Table of keys. */
00028 
00029 static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] =
00030   { { 0, NULL } };
00031 
00032 /* For debugging purposes put the maximum number of keys in a variable.  */
00033 const int __linuxthreads_pthread_keys_max = PTHREAD_KEYS_MAX;
00034 const int __linuxthreads_pthread_key_2ndlevel_size = PTHREAD_KEY_2NDLEVEL_SIZE;
00035 
00036 /* Mutex to protect access to pthread_keys */
00037 
00038 static pthread_mutex_t pthread_keys_mutex = PTHREAD_MUTEX_INITIALIZER;
00039 
00040 /* Create a new key */
00041 
00042 int __pthread_key_create(pthread_key_t * key, destr_function destr)
00043 {
00044   int i;
00045 
00046   pthread_mutex_lock(&pthread_keys_mutex);
00047   for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
00048     if (! pthread_keys[i].in_use) {
00049       /* Mark key in use */
00050       pthread_keys[i].in_use = 1;
00051       pthread_keys[i].destr = destr;
00052       pthread_mutex_unlock(&pthread_keys_mutex);
00053       *key = i;
00054       return 0;
00055     }
00056   }
00057   pthread_mutex_unlock(&pthread_keys_mutex);
00058   return EAGAIN;
00059 }
00060 strong_alias (__pthread_key_create, pthread_key_create)
00061 
00062 /* Reset deleted key's value to NULL in each live thread.
00063  * NOTE: this executes in the context of the thread manager! */
00064 
00065 struct pthread_key_delete_helper_args {
00066   /* Damn, we need lexical closures in C! ;) */
00067   unsigned int idx1st, idx2nd;
00068   pthread_descr self;
00069 };
00070 
00071 static void pthread_key_delete_helper(void *arg, pthread_descr th)
00072 {
00073   struct pthread_key_delete_helper_args *args = arg;
00074   unsigned int idx1st = args->idx1st;
00075   unsigned int idx2nd = args->idx2nd;
00076   pthread_descr self = args->self;
00077 
00078   if (self == 0)
00079     self = args->self = thread_self();
00080 
00081   if (!th->p_terminated) {
00082     /* pthread_exit() may try to free th->p_specific[idx1st] concurrently. */
00083     __pthread_lock(th->p_lock, self);
00084     if (th->p_specific[idx1st] != NULL)
00085       th->p_specific[idx1st][idx2nd] = NULL;
00086     __pthread_unlock(th->p_lock);
00087   }
00088 }
00089 
00090 /* Delete a key */
00091 int pthread_key_delete(pthread_key_t key)
00092 {
00093   pthread_descr self = thread_self();
00094 
00095   pthread_mutex_lock(&pthread_keys_mutex);
00096   if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use) {
00097     pthread_mutex_unlock(&pthread_keys_mutex);
00098     return EINVAL;
00099   }
00100   pthread_keys[key].in_use = 0;
00101   pthread_keys[key].destr = NULL;
00102 
00103   /* Set the value of the key to NULL in all running threads, so
00104      that if the key is reallocated later by pthread_key_create, its
00105      associated values will be NULL in all threads.
00106 
00107      If no threads have been created yet, or if we are exiting, clear
00108      it just in the current thread.  */
00109 
00110   struct pthread_key_delete_helper_args args;
00111   args.idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
00112   args.idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
00113   if (__pthread_manager_request != -1
00114       && !(__builtin_expect (__pthread_exit_requested, 0)))
00115     {
00116       struct pthread_request request;
00117 
00118       args.self = 0;
00119 
00120       request.req_thread = self;
00121       request.req_kind = REQ_FOR_EACH_THREAD;
00122       request.req_args.for_each.arg = &args;
00123       request.req_args.for_each.fn = pthread_key_delete_helper;
00124 
00125       TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
00126                                      (char *) &request, sizeof(request)));
00127       suspend(self);
00128     }
00129   else
00130     {
00131       if (self->p_specific[args.idx1st] != NULL)
00132        self->p_specific[args.idx1st][args.idx2nd] = NULL;
00133     }
00134 
00135   pthread_mutex_unlock(&pthread_keys_mutex);
00136   return 0;
00137 }
00138 
00139 /* Set the value of a key */
00140 
00141 int __pthread_setspecific(pthread_key_t key, const void * pointer)
00142 {
00143   pthread_descr self = thread_self();
00144   unsigned int idx1st, idx2nd;
00145 
00146   if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use)
00147     return EINVAL;
00148   idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
00149   idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
00150   if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL) {
00151     void *newp = calloc(PTHREAD_KEY_2NDLEVEL_SIZE, sizeof (void *));
00152     if (newp == NULL)
00153       return ENOMEM;
00154     THREAD_SETMEM_NC(self, p_specific[idx1st], newp);
00155   }
00156   THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd] = (void *) pointer;
00157   return 0;
00158 }
00159 strong_alias (__pthread_setspecific, pthread_setspecific)
00160 
00161 /* Get the value of a key */
00162 
00163 void * __pthread_getspecific(pthread_key_t key)
00164 {
00165   pthread_descr self = thread_self();
00166   unsigned int idx1st, idx2nd;
00167 
00168   if (key >= PTHREAD_KEYS_MAX)
00169     return NULL;
00170   idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
00171   idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
00172   if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL
00173       || !pthread_keys[key].in_use)
00174     return NULL;
00175   return THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd];
00176 }
00177 strong_alias (__pthread_getspecific, pthread_getspecific)
00178 
00179 /* Call the destruction routines on all keys */
00180 
00181 void __pthread_destroy_specifics()
00182 {
00183   pthread_descr self = thread_self();
00184   int i, j, round, found_nonzero;
00185   destr_function destr;
00186   void * data;
00187 
00188   for (round = 0, found_nonzero = 1;
00189        found_nonzero && round < PTHREAD_DESTRUCTOR_ITERATIONS;
00190        round++) {
00191     found_nonzero = 0;
00192     for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++)
00193       if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL)
00194         for (j = 0; j < PTHREAD_KEY_2NDLEVEL_SIZE; j++) {
00195           destr = pthread_keys[i * PTHREAD_KEY_2NDLEVEL_SIZE + j].destr;
00196           data = THREAD_GETMEM_NC(self, p_specific[i])[j];
00197           if (destr != NULL && data != NULL) {
00198             THREAD_GETMEM_NC(self, p_specific[i])[j] = NULL;
00199             destr(data);
00200             found_nonzero = 1;
00201           }
00202         }
00203   }
00204   __pthread_lock(THREAD_GETMEM(self, p_lock), self);
00205   for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) {
00206     if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL) {
00207       void *p = THREAD_GETMEM_NC(self, p_specific[i]);
00208       THREAD_SETMEM_NC(self, p_specific[i], NULL);
00209       free(p);
00210     }
00211   }
00212   __pthread_unlock(THREAD_GETMEM(self, p_lock));
00213 }
00214 
00215 #if !(USE_TLS && HAVE___THREAD)
00216 
00217 /* Thread-specific data for libc. */
00218 
00219 int
00220 __pthread_internal_tsd_set (int key, const void * pointer)
00221 {
00222   pthread_descr self = thread_self();
00223 
00224   THREAD_SETMEM_NC(self, p_libc_specific[key], (void *) pointer);
00225   return 0;
00226 }
00227 
00228 void *
00229 __pthread_internal_tsd_get (int key)
00230 {
00231   pthread_descr self = thread_self();
00232 
00233   return THREAD_GETMEM_NC(self, p_libc_specific[key]);
00234 }
00235 
00236 void ** __attribute__ ((__const__))
00237 __pthread_internal_tsd_address (int key)
00238 {
00239   pthread_descr self = thread_self();
00240   return &self->p_libc_specific[key];
00241 }
00242 
00243 #endif