openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

thread.c (19177B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File: 	thread.c
      8  * Purpose:	Defines SAL routines for Unix threads
      9  *
     10  * Thread Abstraction
     11  *
     12  * POSIX does not keep thread names.  The keep the names, we have a
     13  * linked list of all threads we create.  If your OS has the ability to
     14  * retrieve the thread name, most of this code can be deleted.  If you
     15  * don't care about thread names, you may just have sal_thread_name
     16  * always return the empty string.
     17  *
     18  * The most important use for thread names is in sal/appl/xxx/console.c,
     19  * where the console output of background tasks can be prefixed by the
     20  * task name.
     21  */
     22 
     23 #include <pthread.h>
     24 #include <sys/types.h>
     25 #include <sys/time.h>
     26 #include <sys/param.h>
     27 #include <sys/prctl.h>
     28 #include <sys/syscall.h>
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <signal.h>
     32 #include <string.h>
     33 #include <unistd.h>
     34 
     35 #include <assert.h>
     36 #include <sal/core/thread.h>
     37 #include <sal/core/sync.h>
     38 #include <sal/core/time.h>
     39 #include <sal/core/spl.h>
     40 #include <sal/limits.h>
     41 
     42 #if defined (__STRICT_ANSI__)
     43 #define NO_CONTROL_C
     44 #endif
     45 
     46 #ifndef SAL_THREAD_RT_PRIO_HIGHEST
     47 #define SAL_THREAD_RT_PRIO_HIGHEST  90
     48 #endif
     49 
     50 static pthread_mutex_t _sal_thread_lock = PTHREAD_MUTEX_INITIALIZER;
     51 
     52 #define THREAD_LOCK() pthread_mutex_lock(&_sal_thread_lock)
     53 #define THREAD_UNLOCK() pthread_mutex_unlock(&_sal_thread_lock)
     54 
     55 #if defined(BROADCOM_DEBUG) && defined(INCLUDE_BCM_SAL_PROFILE)
     56 static unsigned int _sal_thread_count_curr;
     57 static unsigned int _sal_thread_count_max;
     58 static unsigned int _sal_thread_stack_size_curr;
     59 static unsigned int _sal_thread_stack_size_max;
     60 #define SAL_THREAD_RESOURCE_USAGE_INCR(a_cnt, a_cnt_max, a_sz,      \
     61                                        a_sz_max, n_ssize, ilock)    \
     62     a_cnt++;                                                        \
     63     a_sz += (n_ssize);                                              \
     64     a_cnt_max = ((a_cnt) > (a_cnt_max)) ? (a_cnt) : (a_cnt_max);    \
     65     a_sz_max = ((a_sz) > (a_sz_max)) ? (a_sz) : (a_sz_max)
     66 
     67 #define SAL_THREAD_RESOURCE_USAGE_DECR(a_count, a_ssize, n_ssize, ilock)\
     68         a_count--;                                                      \
     69         a_ssize -= (n_ssize)
     70 
     71 /*
     72  * Function:
     73  *      sal_thread_resource_usage_get
     74  * Purpose:
     75  *      Provides count of active threads and stack allocation
     76  * Parameters:
     77  *      alloc_curr - Current memory usage.
     78  *      alloc_max - Memory usage high water mark
     79  */
     80 
     81 void
     82 sal_thread_resource_usage_get(unsigned int *sal_thread_count_curr,
     83                               unsigned int *sal_stack_size_curr,
     84                               unsigned int *sal_thread_count_max,
     85                               unsigned int *sal_stack_size_max)
     86 {
     87     if (sal_thread_count_curr != NULL) {
     88         *sal_thread_count_curr = _sal_thread_count_curr;
     89     }
     90     if (sal_stack_size_curr != NULL) {
     91         *sal_stack_size_curr = _sal_thread_stack_size_curr;
     92     }
     93     if (sal_thread_count_max != NULL) {
     94         *sal_thread_count_max = _sal_thread_count_max;
     95     }
     96     if (sal_stack_size_max != NULL) {
     97         *sal_stack_size_max = _sal_thread_stack_size_max;
     98     }
     99 }
    100 
    101 #else
    102 /* Resource tracking disabled */
    103 #define SAL_THREAD_RESOURCE_USAGE_INCR(a_cnt, a_cnt_max, a_sz,      \
    104                                        a_sz_max, n_ssize, ilock)
    105 #define SAL_THREAD_RESOURCE_USAGE_DECR(a_count, a_ssize, n_ssize, ilock)
    106 #endif
    107 
    108 /* If user defined min stack size in Make.local
    109  * then undefine local stack min
    110  * and set user defined value as the new min
    111  */
    112 #ifdef SAL_THREAD_STACK_MIN
    113 #ifdef PTHREAD_STACK_MIN
    114 #undef PTHREAD_STACK_MIN
    115 #endif
    116 #define PTHREAD_STACK_MIN SAL_THREAD_STACK_MIN
    117 #else
    118 /* If no user defined min stack size
    119  * and if no local stack min
    120  * define local stack min
    121  */
    122 #ifndef PTHREAD_STACK_MIN
    123 #define PTHREAD_STACK_MIN 16384
    124 #endif
    125 #endif
    126 
    127 /*
    128  * Function:
    129  *	thread_boot
    130  * Purpose:
    131  *	Entry point for each new thread created
    132  * Parameters:
    133  *	ti - information about thread being created
    134  * Notes:
    135  *	Signals and other parameters are configured before jumping to
    136  *	the actual thread's main routine.
    137  */
    138 
    139 typedef struct thread_info_s {
    140     void		(*f)(void *);
    141     char		*name;
    142     pthread_t		id;
    143     void		*arg;
    144     int                 ss;
    145     sal_sem_t           sem;
    146     struct thread_info_s *next;
    147 } thread_info_t;
    148 
    149 static thread_info_t	*thread_head = NULL;
    150 
    151 static void *
    152 thread_boot(void *ti_void)
    153 {
    154 
    155     thread_info_t	*ti = ti_void;
    156     void		(*f)(void *);
    157     void		*arg;
    158 #ifndef NO_CONTROL_C
    159     sigset_t		new_mask, orig_mask;
    160 
    161     /* Make sure no child thread catches Control-C */
    162     sigemptyset(&new_mask);
    163     sigaddset(&new_mask, SIGINT);
    164     sigprocmask(SIG_BLOCK, &new_mask, &orig_mask);
    165 #endif
    166 
    167     /* Ensure that we give up all resources upon exit */
    168     pthread_detach(pthread_self());
    169 
    170 #ifdef PR_SET_NAME
    171     prctl(PR_SET_NAME, ti->name, 0, 0, 0);
    172 #endif
    173 
    174 #ifndef netbsd
    175     /* not supported */
    176     pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
    177     pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    178 #endif /* netbsd */
    179 
    180     f = ti->f;
    181     arg = ti->arg;
    182 
    183     ti->id = pthread_self();
    184 
    185     /* Notify parent to continue */
    186     sal_sem_give(ti->sem);
    187 
    188     /* Call thread function */
    189     (*f)(arg);
    190 
    191     /* Thread function did not call sal_thread_exit() */
    192     sal_thread_exit(0);
    193 
    194     /* Will never get here */
    195     return NULL;
    196 }
    197 
    198 /*
    199  * Function:
    200  *	sal_thread_create
    201  * Purpose:
    202  *	Abstraction for task creation
    203  * Parameters:
    204  *	name - name of task
    205  *	ss - stack size requested
    206  *	prio - scheduling prio (0 = highest, 255 = lowest)
    207  *	func - address of function to call
    208  *	arg - argument passed to func.
    209  * Returns:
    210  *	Thread ID
    211  */
    212 
    213 sal_thread_t
    214 sal_thread_create(char *name, int ss, int prio, void (f)(void *), void *arg)
    215 {
    216     pthread_attr_t	attribs;
    217     struct sched_param param;
    218     thread_info_t	*ti;
    219     pthread_t		id;
    220     sal_sem_t           sem;
    221 
    222     if (pthread_attr_init(&attribs)) {
    223         return(SAL_THREAD_ERROR);
    224     }
    225 
    226     ss += PTHREAD_STACK_MIN;
    227     pthread_attr_setstacksize(&attribs, ss);
    228 
    229     if (prio == SAL_THREAD_PRIO_NO_PREEMPT) {
    230         pthread_attr_setinheritsched(&attribs, PTHREAD_EXPLICIT_SCHED);
    231         pthread_attr_setschedpolicy(&attribs, SCHED_FIFO);
    232         param.sched_priority = SAL_THREAD_RT_PRIO_HIGHEST;
    233         pthread_attr_setschedparam(&attribs, &param);
    234     }
    235 
    236     if ((ti = malloc(sizeof (*ti))) == NULL) {
    237 	return SAL_THREAD_ERROR;
    238     }
    239 
    240     if ((sem = sal_sem_create("threadBoot", 1, 0)) == NULL) {
    241 	free(ti);
    242 	return SAL_THREAD_ERROR;
    243     }
    244     ti->name = NULL;
    245     if ((ti->name = malloc(strlen(name)+1)) == NULL) {
    246         free(ti);
    247         sal_sem_destroy(sem);
    248         return SAL_THREAD_ERROR;
    249     }
    250     /* coverity[secure_coding] */
    251     strcpy(ti->name, name);
    252 
    253     ti->f = f;
    254     
    255     ti->arg = arg;
    256     ti->id = (pthread_t)0;
    257     ti->ss = ss;
    258     ti->sem = sem;
    259 
    260     THREAD_LOCK();
    261     ti->next = thread_head;
    262     thread_head = ti;
    263     THREAD_UNLOCK();
    264 
    265     if (pthread_create(&id, &attribs, thread_boot, (void *)ti)) {
    266         THREAD_LOCK();
    267 	thread_head = thread_head->next;
    268         THREAD_UNLOCK();
    269         if (ti->name != NULL) {
    270             free(ti->name);
    271         }
    272 	free(ti);
    273         sal_sem_destroy(sem);
    274 	return(SAL_THREAD_ERROR);
    275     }
    276 
    277     SAL_THREAD_RESOURCE_USAGE_INCR(
    278         _sal_thread_count_curr,
    279         _sal_thread_count_max,
    280         _sal_thread_stack_size_curr,
    281         _sal_thread_stack_size_max,
    282         ss,
    283         ilock);
    284 
    285     /*
    286      * Note that at this point ti can no longer be safely
    287      * dereferenced, as the thread we just created may have
    288      * exited already. Instead we wait for the new thread
    289      * to update thread_info_t and tell us to continue.
    290      */
    291     sal_sem_take(sem, sal_sem_FOREVER);
    292     sal_sem_destroy(sem);
    293 
    294     return ((sal_thread_t)id);
    295 }
    296 
    297 /*
    298  * Function:
    299  *	sal_thread_destroy
    300  * Purpose:
    301  *	Abstraction for task deletion
    302  * Parameters:
    303  *	thread - thread ID
    304  * Returns:
    305  *	0 on success, -1 on failure
    306  * Notes:
    307  *	This routine is not generally used by Broadcom drivers because
    308  *	it's unsafe.  If a task is destroyed while holding a mutex or
    309  *	other resource, system operation becomes unpredictable.  Also,
    310  *	some RTOS's do not include kill routines.
    311  *
    312  *	Instead, Broadcom tasks are written so they can be notified via
    313  *	semaphore when it is time to exit, at which time they call
    314  *	sal_thread_exit().
    315  */
    316 
    317 int
    318 sal_thread_destroy(sal_thread_t thread)
    319 {
    320 #ifdef netbsd
    321     /* not supported */
    322     return -1;
    323 #else
    324     thread_info_t	*ti, **tp;
    325     pthread_t		id = (pthread_t) thread;
    326 
    327     if (pthread_cancel(id)) {
    328 	return -1;
    329     }
    330 
    331     ti = NULL;
    332 
    333     THREAD_LOCK();
    334     for (tp = &thread_head; (*tp) != NULL; tp = &(*tp)->next) {
    335 	if ((*tp)->id == id) {
    336 	    ti = (*tp);
    337 	    (*tp) = (*tp)->next;
    338 	    break;
    339 	}
    340     }
    341     THREAD_UNLOCK();
    342 
    343     if (ti) {
    344         SAL_THREAD_RESOURCE_USAGE_DECR(
    345             _sal_thread_count_curr,
    346             _sal_thread_stack_size_curr,
    347             ti->ss,
    348             ilock);
    349         if (ti->name != NULL) {
    350             free(ti->name);
    351         }
    352         free(ti);
    353     }
    354 
    355     return 0;
    356 #endif
    357 }
    358 
    359 /*
    360  * Function:
    361  *	sal_thread_self
    362  * Purpose:
    363  *	Return thread ID of caller
    364  * Parameters:
    365  *	None
    366  * Returns:
    367  *	Thread ID
    368  */
    369 
    370 sal_thread_t
    371 sal_thread_self(void)
    372 {
    373     return (sal_thread_t) pthread_self();
    374 }
    375 
    376 int
    377 sal_thread_id_get(void)
    378 {
    379     return syscall(SYS_gettid);
    380 }
    381 
    382 /*
    383  * Function:
    384  *	sal_thread_name
    385  * Purpose:
    386  *	Return name given to thread when it was created
    387  * Parameters:
    388  *	thread - thread ID
    389  *	thread_name - buffer to return thread name;
    390  *		gets empty string if not available
    391  *	thread_name_size - maximum size of buffer
    392  * Returns:
    393  *	NULL, if name not available
    394  *	thread_name, if name available
    395  */
    396 char *
    397 sal_thread_name(sal_thread_t thread, char *thread_name, int thread_name_size)
    398 {
    399     thread_info_t	*ti;
    400     char                *name;
    401 
    402     name = NULL;
    403 
    404     THREAD_LOCK();
    405     for (ti = thread_head; ti != NULL; ti = ti->next) {
    406 	if (ti->id == (pthread_t)thread) {
    407 	    strncpy(thread_name, ti->name, thread_name_size);
    408 	    thread_name[thread_name_size - 1] = 0;
    409 	    name = thread_name;
    410             break;
    411 	}
    412     }
    413     THREAD_UNLOCK();
    414 
    415     if (name == NULL) {
    416         thread_name[0] = 0;
    417     }
    418 
    419     return name;
    420 }
    421 
    422 /*
    423  * Function:
    424  *	sal_thread_exit
    425  * Purpose:
    426  *	Exit the calling thread
    427  * Parameters:
    428  *	rc - return code from thread.
    429  * Notes:
    430  *	Never returns.
    431  */
    432 
    433 void
    434 sal_thread_exit(int rc)
    435 {
    436     thread_info_t	*ti, **tp;
    437     pthread_t		id = pthread_self();
    438 
    439     ti = NULL;
    440 
    441     THREAD_LOCK();
    442     for (tp = &thread_head; (*tp) != NULL; tp = &(*tp)->next) {
    443 	if ((*tp)->id == id) {
    444 	    ti = (*tp);
    445 	    (*tp) = (*tp)->next;
    446 	    break;
    447 	}
    448     }
    449     THREAD_UNLOCK();
    450 
    451     if (ti) {
    452         SAL_THREAD_RESOURCE_USAGE_DECR(
    453             _sal_thread_count_curr,
    454             _sal_thread_stack_size_curr,
    455             ti->ss,
    456             ilock);
    457         if (ti->name != NULL) {
    458             free(ti->name);
    459         }
    460         free(ti);
    461     }
    462 
    463     pthread_exit(INT_TO_PTR(rc));
    464 }
    465 
    466 /*
    467  * Function:
    468  *	sal_thread_yield
    469  * Purpose:
    470  *	Yield the processor to other tasks.
    471  * Parameters:
    472  *	None
    473  */
    474 
    475 void
    476 sal_thread_yield(void)
    477 {
    478     sal_usleep(1);
    479 }
    480 
    481 /*
    482  * Function:
    483  *	sal_thread_main_set
    484  * Purpose:
    485  *	Set which thread is the main thread
    486  * Parameters:
    487  *	thread - thread ID
    488  * Notes:
    489  *	The main thread is the one that runs in the foreground on the
    490  *	console.  It prints normally, takes keyboard signals, etc.
    491  */
    492 
    493 static sal_thread_t _sal_thread_main = 0;
    494 
    495 void
    496 sal_thread_main_set(sal_thread_t thread)
    497 {
    498     _sal_thread_main = thread;
    499 }
    500 
    501 /*
    502  * Function:
    503  *	sal_thread_main_get
    504  * Purpose:
    505  *	Return which thread is the main thread
    506  * Returns:
    507  *	Thread ID
    508  * Notes:
    509  *	See sal_thread_main_set().
    510  */
    511 
    512 sal_thread_t
    513 sal_thread_main_get(void)
    514 {
    515     return _sal_thread_main;
    516 }
    517 
    518 /*
    519  * Function:
    520  *	sal_sleep
    521  * Purpose:
    522  *	Suspend calling thread for a specified number of seconds.
    523  * Parameters:
    524  *	sec - number of seconds to suspend
    525  * Notes:
    526  *	Other tasks are free to run while the caller is suspended.
    527  */
    528 
    529 void
    530 sal_sleep(int sec)
    531 {
    532     struct timeval tv;
    533     tv.tv_sec = (time_t) sec;
    534     tv.tv_usec = 0;
    535     select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &tv);
    536 }
    537 
    538 /*
    539  * Function:
    540  *	sal_usleep
    541  * Purpose:
    542  *	Suspend calling thread for a specified number of microseconds.
    543  * Parameters:
    544  *	usec - number of microseconds to suspend
    545  * Notes:
    546  *	The actual delay period depends on the resolution of the
    547  *	Unix select routine, whose precision is limited to the
    548  *	the period of the scheduler tick, generally 1/60 or 1/100 sec.
    549  *	Other tasks are free to run while the caller is suspended.
    550  *
    551  *	A short usleep less than 20000 usec is done by doing a 'yield'
    552  *	within a loop, rather than a true 'sleep'. If no other tasks are
    553  *	using the CPU, this will effectively be a busy-wait, as the yield
    554  *	will immediately return. This can make it appear that the calling
    555  *	thread is using a lot of CPU, though this is only because no other
    556  *	task is in a running state. To avoid this appearance of 100% CPU
    557  *	load, the calling thread can increase the delay to 20000.
    558  *	The appearance of 100% CPU load for this thread should not have any
    559  *	effects on other threads. The thread that is spinning doing a
    560  *	sal_usleep() is continually calling an OS yield, so any other scheduled
    561  *	threads will run. The only time you will see this thread getting 100%
    562  *	CPU is if no other tasks are trying to run.
    563  */
    564 
    565 void
    566 sal_usleep(uint32 usec)
    567 {
    568     struct timeval tv;
    569 
    570     if (usec < (2 * SECOND_USEC)/HZ) {
    571         sal_usecs_t now;
    572         sal_usecs_t earlier;
    573         sal_usecs_t delta;
    574         sal_usecs_t max_time = SAL_UINT32_MAX;
    575 
    576         earlier = sal_time_usecs();
    577         do {
    578 #if defined(_POSIX_PRIORITY_SCHEDULING) && (_POSIX_PRIORITY_SCHEDULING >= 200112L)
    579             sched_yield();
    580 #else
    581             tv.tv_sec = 0;
    582             tv.tv_usec = 0;
    583             select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &tv);
    584 #endif
    585             now = sal_time_usecs();
    586             if (now < earlier) {
    587                 delta = max_time - earlier + now;
    588             } else {
    589                 delta = now - earlier;
    590             }
    591         } while (delta < usec);
    592     }
    593     else {
    594         tv.tv_sec = (time_t) (usec / SECOND_USEC);
    595         tv.tv_usec = (long) (usec % SECOND_USEC);
    596         select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &tv);
    597     }
    598 }
    599 
    600 #define UDELAY_USE_CLOCK_GETTIME (-1)
    601 /*
    602  * Function:
    603  *	sal_udelay
    604  * Purpose:
    605  *	Spin wait for an approximate number of microseconds
    606  * Parameters:
    607  *	usec - number of microseconds
    608  * Notes:
    609  *	MUST be called once before normal use so it can self-calibrate.
    610  *	Code for self-calibrating delay loop is courtesy of
    611  *	Geoffrey Espin, the comp.os.vxworks Usenet group, and
    612  *	JA Borkhuis (http://www.xs4all.nl/~borkhuis).
    613  *      The current implementation assumes that sal_time_usecs has
    614  *      system tick resolution (or better).
    615  */
    616 
    617 void
    618 sal_udelay(uint32 usec)
    619 {
    620     static volatile int _sal_udelay_counter;
    621     static int loops = 0;
    622     uint32 iy;
    623     int ix; 
    624 #ifdef CLOCK_MONOTONIC
    625     int error;
    626     struct timespec now, earlier;
    627     long delta_usec, diff_nsec;
    628 
    629     if (loops == 0) {
    630         error = clock_getres(CLOCK_MONOTONIC, &now);
    631         if (!error && !now.tv_sec && (now.tv_nsec <= 1000)) {
    632             loops = UDELAY_USE_CLOCK_GETTIME;
    633         }
    634     }
    635 
    636     if (loops == UDELAY_USE_CLOCK_GETTIME) {
    637         error = clock_gettime(CLOCK_MONOTONIC, &earlier);
    638         assert(!error);
    639         do {
    640             error = clock_gettime(CLOCK_MONOTONIC, &now);
    641             assert(!error);
    642             diff_nsec = now.tv_nsec - earlier.tv_nsec;
    643             if (diff_nsec < 0) {
    644                 diff_nsec += 1000000000;
    645                 now.tv_sec--;
    646             }
    647             delta_usec = (now.tv_sec - earlier.tv_sec) * 1000000 +
    648                          (diff_nsec / 1000);
    649         } while ((uint32)delta_usec < usec);
    650         return;
    651     }
    652 #endif
    653     if (loops == 0 || usec == 0) {      /* Need calibration? */
    654         int max_loops;
    655         int start = 0, stop = 0;
    656         int mpt = (SECOND_USEC / HZ);   /* usec/tick */
    657 
    658         for (loops = 1; loops < 0x1000 && stop == start; loops <<= 1) {
    659             /* Wait for clock turn over */
    660             for (stop = start = sal_time_usecs() / mpt;
    661                  start == stop;
    662                  start = sal_time_usecs() / mpt) {
    663                 /* Empty */
    664             }
    665             sal_udelay(mpt);    /* Single recursion */
    666             stop = sal_time_usecs() / mpt;
    667         }
    668 
    669         max_loops = loops / 2;  /* Loop above overshoots */
    670 
    671         start = stop = 0;
    672 
    673         if (loops < 4) {
    674             loops = 4;
    675         }
    676 
    677         for (loops /= 4; loops < max_loops && stop == start; loops++) {
    678             /* Wait for clock turn over */
    679             for (stop = start = sal_time_usecs() / mpt;
    680                  start == stop;
    681                  start = sal_time_usecs() / mpt) {
    682                 /* Empty */
    683             }
    684             sal_udelay(mpt);    /* Single recursion */
    685             stop = sal_time_usecs() / mpt;
    686         }
    687     }
    688    
    689     for (iy = 0; iy < usec; iy++) {
    690         for (ix = 0; ix < loops; ix++) {
    691             _sal_udelay_counter++;      /* Prevent optimizations */
    692         }
    693     }
    694 }
    695 
    696 #define MAX_TLS_KEY_SUPPORTED 8
    697 
    698 typedef struct {
    699     pthread_key_t key;
    700     int mapped;
    701 } pthread_key_map_t;
    702 
    703 static pthread_key_map_t key_maps[MAX_TLS_KEY_SUPPORTED];
    704 static int sal_tls_inited = FALSE;
    705 
    706 static void 
    707 sal_tls_init(void)
    708 {  
    709     int i;
    710 
    711     if (sal_tls_inited) {
    712         return;    
    713     }
    714     for (i = 0; i < MAX_TLS_KEY_SUPPORTED; i++) {
    715         key_maps[i].mapped = FALSE;
    716     }
    717     sal_tls_inited = TRUE;
    718     return;
    719 }
    720 
    721 sal_tls_key_t * 
    722 sal_tls_key_create(void (*destructor)(void *))
    723 {
    724     int i;
    725     int lvl;
    726     
    727     lvl = sal_splhi();
    728     sal_tls_init();    
    729     for (i = 0; i < MAX_TLS_KEY_SUPPORTED; i++) {
    730         if (!key_maps[i].mapped) { 
    731         	key_maps[i].mapped = TRUE;         
    732             break;
    733         }
    734     }
    735     sal_spl(lvl);
    736      
    737     if (i >= MAX_TLS_KEY_SUPPORTED) {
    738         return NULL;
    739     }
    740     if (0 == pthread_key_create(&key_maps[i].key, destructor)) {
    741         return (void *)&key_maps[i].key;
    742     } else {
    743     	key_maps[i].mapped = FALSE;
    744         return NULL;    
    745     }
    746 }
    747 
    748 int 
    749 sal_tls_key_set(sal_tls_key_t *key, void *val)
    750 {
    751     if (key == NULL) {
    752         return FALSE;   
    753     }
    754     
    755     if (!sal_tls_inited) {
    756         return FALSE;   
    757     }
    758     
    759     if (0 == pthread_setspecific(*(pthread_key_t *)key, val)) {
    760         return TRUE;
    761     } else {
    762         return FALSE;   
    763     }
    764         
    765 }
    766 
    767 void *
    768 sal_tls_key_get(sal_tls_key_t *key)
    769 {   
    770     if (key == 0) {
    771         return NULL;
    772     }
    773     if (!sal_tls_inited) {
    774         return NULL;    
    775     }
    776     return pthread_getspecific(*(pthread_key_t *)key); 
    777 }
    778 
    779 int 
    780 sal_tls_key_delete(sal_tls_key_t *key)
    781 {
    782     if (key == 0) {
    783         return FALSE;
    784     }
    785     if (!sal_tls_inited) {
    786         return FALSE;   
    787     }
    788     if (0 == pthread_key_delete(*(pthread_key_t *)key)) {
    789         return TRUE;
    790     } else {
    791         return FALSE;   
    792     }
    793 }
    794