| [1] | 1 | /* | 
|---|
|  | 2 | * pthread_keys.c -  pthread specific keys related functions | 
|---|
|  | 3 | * | 
|---|
|  | 4 | * Copyright (c) 2008,2009,2010,2011,2012 Ghassan Almaless | 
|---|
|  | 5 | * Copyright (c) 2011,2012 UPMC Sorbonne Universites | 
|---|
|  | 6 | * | 
|---|
|  | 7 | * This file is part of ALMOS. | 
|---|
|  | 8 | * | 
|---|
|  | 9 | * ALMOS is free software; you can redistribute it and/or modify it | 
|---|
|  | 10 | * under the terms of the GNU General Public License as published by | 
|---|
|  | 11 | * the Free Software Foundation; version 2.0 of the License. | 
|---|
|  | 12 | * | 
|---|
|  | 13 | * ALMOS is distributed in the hope that it will be useful, but | 
|---|
|  | 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
|  | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|---|
|  | 16 | * General Public License for more details. | 
|---|
|  | 17 | * | 
|---|
|  | 18 | * You should have received a copy of the GNU General Public License | 
|---|
|  | 19 | * along with ALMOS; if not, write to the Free Software Foundation, | 
|---|
|  | 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 
|---|
|  | 21 | */ | 
|---|
|  | 22 |  | 
|---|
|  | 23 | #include <sys/types.h> | 
|---|
|  | 24 | #include <errno.h> | 
|---|
|  | 25 | #include <string.h> | 
|---|
|  | 26 | #include <cpu-syscall.h> | 
|---|
|  | 27 | #include <pthread.h> | 
|---|
|  | 28 | #include <stdio.h> | 
|---|
|  | 29 |  | 
|---|
|  | 30 | #define KEY_FREE 0 | 
|---|
|  | 31 | #define KEY_BUSY 1 | 
|---|
|  | 32 |  | 
|---|
|  | 33 | typedef void (key_destr_func_t)(void*); | 
|---|
|  | 34 |  | 
|---|
|  | 35 | typedef struct key_entry_s | 
|---|
|  | 36 | { | 
|---|
|  | 37 | int state; | 
|---|
|  | 38 | key_destr_func_t *destructor; | 
|---|
|  | 39 | }key_entry_t; | 
|---|
|  | 40 |  | 
|---|
|  | 41 | static pthread_spinlock_t lock; | 
|---|
|  | 42 | static key_entry_t keys_tbl[PTHREAD_KEYS_MAX]; | 
|---|
|  | 43 | static unsigned long next_key; | 
|---|
|  | 44 |  | 
|---|
|  | 45 | void __pthread_keys_init(void) | 
|---|
|  | 46 | { | 
|---|
|  | 47 | key_entry_t *ptr = &keys_tbl[0]; | 
|---|
|  | 48 | memset(ptr, 0, sizeof(keys_tbl)); | 
|---|
|  | 49 | next_key = 0; | 
|---|
|  | 50 | pthread_spin_init(&lock, 0); | 
|---|
|  | 51 | } | 
|---|
|  | 52 |  | 
|---|
|  | 53 | void __pthread_keys_destroy(void) | 
|---|
|  | 54 | { | 
|---|
|  | 55 | __pthread_tls_t *tls; | 
|---|
|  | 56 | int iter, key; | 
|---|
|  | 57 | void *old_val; | 
|---|
|  | 58 | int hasVal, err; | 
|---|
|  | 59 |  | 
|---|
|  | 60 | tls = cpu_get_tls(); | 
|---|
|  | 61 |  | 
|---|
|  | 62 | for(iter=0; iter < PTHREAD_DESTRUCTOR_ITERATIONS; iter++) | 
|---|
|  | 63 | { | 
|---|
|  | 64 | for(key=0, hasVal = 0; key < PTHREAD_KEYS_MAX; key++) | 
|---|
|  | 65 | { | 
|---|
|  | 66 | if(tls->values_tbl[key] == NULL) | 
|---|
|  | 67 | continue; | 
|---|
|  | 68 |  | 
|---|
|  | 69 | old_val = tls->values_tbl[key]; | 
|---|
|  | 70 | tls->values_tbl[key] = NULL; | 
|---|
|  | 71 |  | 
|---|
|  | 72 | if((old_val == NULL) || (keys_tbl[key].destructor == NULL)) | 
|---|
|  | 73 | continue; | 
|---|
|  | 74 |  | 
|---|
|  | 75 | keys_tbl[key].destructor(old_val); | 
|---|
|  | 76 | hasVal = 1; | 
|---|
|  | 77 | } | 
|---|
|  | 78 |  | 
|---|
|  | 79 | if(!hasVal) return; | 
|---|
|  | 80 | } | 
|---|
|  | 81 | } | 
|---|
|  | 82 |  | 
|---|
|  | 83 | int pthread_key_create(pthread_key_t *key, void (*destructor)(void*)) | 
|---|
|  | 84 | { | 
|---|
|  | 85 | int _key; | 
|---|
|  | 86 | int err; | 
|---|
|  | 87 |  | 
|---|
|  | 88 | if(key == NULL) | 
|---|
|  | 89 | return EINVAL; | 
|---|
|  | 90 |  | 
|---|
|  | 91 | err = 0; | 
|---|
|  | 92 |  | 
|---|
|  | 93 | pthread_spin_lock(&lock); | 
|---|
|  | 94 |  | 
|---|
|  | 95 | for(_key=next_key; (keys_tbl[_key].state != KEY_FREE) && (_key < PTHREAD_KEYS_MAX); _key++); | 
|---|
|  | 96 |  | 
|---|
|  | 97 | if(_key != PTHREAD_KEYS_MAX) | 
|---|
|  | 98 | { | 
|---|
|  | 99 | keys_tbl[_key].state = KEY_BUSY; | 
|---|
|  | 100 | next_key = _key + 1; | 
|---|
|  | 101 | } | 
|---|
|  | 102 | else | 
|---|
|  | 103 | err = EAGAIN; | 
|---|
|  | 104 |  | 
|---|
|  | 105 | pthread_spin_unlock(&lock); | 
|---|
|  | 106 |  | 
|---|
|  | 107 | if(err) return err; | 
|---|
|  | 108 |  | 
|---|
|  | 109 | keys_tbl[_key].destructor = destructor; | 
|---|
|  | 110 | *key = _key; | 
|---|
|  | 111 | return 0; | 
|---|
|  | 112 | } | 
|---|
|  | 113 |  | 
|---|
|  | 114 | int pthread_key_delete(pthread_key_t key) | 
|---|
|  | 115 | { | 
|---|
|  | 116 | if((key >= PTHREAD_KEYS_MAX) || (keys_tbl[key].state != KEY_BUSY)) | 
|---|
|  | 117 | return EINVAL; | 
|---|
|  | 118 |  | 
|---|
|  | 119 | keys_tbl[key].state = KEY_FREE; | 
|---|
|  | 120 |  | 
|---|
|  | 121 | if(key < next_key) | 
|---|
|  | 122 | { | 
|---|
|  | 123 | pthread_spin_lock(&lock); | 
|---|
|  | 124 | next_key = (key < next_key) ? key : next_key; | 
|---|
|  | 125 | pthread_spin_unlock(&lock); | 
|---|
|  | 126 | } | 
|---|
|  | 127 |  | 
|---|
|  | 128 | return 0; | 
|---|
|  | 129 | } | 
|---|
|  | 130 |  | 
|---|
|  | 131 | int pthread_setspecific(pthread_key_t key, const void *value) | 
|---|
|  | 132 | { | 
|---|
|  | 133 | __pthread_tls_t *tls; | 
|---|
|  | 134 |  | 
|---|
|  | 135 | if((key >= PTHREAD_KEYS_MAX) || (keys_tbl[key].state != KEY_BUSY)) | 
|---|
|  | 136 | return EINVAL; | 
|---|
|  | 137 |  | 
|---|
|  | 138 | tls = cpu_get_tls(); | 
|---|
|  | 139 | tls->values_tbl[key] = (void*)value; | 
|---|
|  | 140 |  | 
|---|
|  | 141 | return 0; | 
|---|
|  | 142 | } | 
|---|
|  | 143 |  | 
|---|
|  | 144 | void *pthread_getspecific(pthread_key_t key) | 
|---|
|  | 145 | { | 
|---|
|  | 146 | __pthread_tls_t *tls; | 
|---|
|  | 147 |  | 
|---|
|  | 148 | if((key >= PTHREAD_KEYS_MAX) || (keys_tbl[key].state != KEY_BUSY)) | 
|---|
|  | 149 | return NULL; | 
|---|
|  | 150 |  | 
|---|
|  | 151 | tls = cpu_get_tls(); | 
|---|
|  | 152 | return tls->values_tbl[key]; | 
|---|
|  | 153 | } | 
|---|
|  | 154 |  | 
|---|
|  | 155 |  | 
|---|