3 * Copyright © 2001 Novell, Inc. All Rights Reserved.
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Artistic License, as specified in the README file.
11 * FILENAME : NWTInfo.c
12 * DESCRIPTION : Thread-local storage for Perl.
13 * The thread's information is stored in a hashed table that is based on
14 * the lowest 5 bits of the current thread ID.
16 * Date : January 2001.
22 #include "win32ish.h" // For "BOOL", "TRUE" and "FALSE"
32 // Number of entries in the hashtable
34 #define NUM_ENTRIES 32 /* 2^5 */
37 // macro to calculate the hash index for a given Thread ID
39 #define INDEXOF(tid) ((tid) & 0x1f)
42 // Semaphore to control access to global linked list
45 static SEMAPHORE g_tinfoSem = NULL;
46 static SEMAPHORE g_tCtxSem = NULL;
48 static LONG g_tinfoSem = 0L;
49 static LONG g_tCtxSem = 0L;
52 // Hash table of thread information structures
54 ThreadInfo* g_ThreadInfo[NUM_ENTRIES];
55 ThreadContext* g_ThreadCtx;
59 /*============================================================================================
61 Function : fnTerminateThreadInfo
63 Description : This function undoes fnInitializeThreadInfo; call once per NLM instance.
69 ==============================================================================================*/
71 BOOL fnTerminateThreadInfo(void)
78 kSemaphoreWait(g_tinfoSem);
80 WaitOnLocalSemaphore(g_tinfoSem);
82 for (index = 0; index < NUM_ENTRIES; index++)
84 if (g_ThreadInfo[index] != NULL)
87 kSemaphoreSignal(g_tinfoSem);
89 SignalLocalSemaphore(g_tinfoSem);
95 kSemaphoreFree(g_tinfoSem);
98 CloseLocalSemaphore(g_tinfoSem);
107 /*============================================================================================
109 Function : fnInitializeThreadInfo
111 Description : Initializes the global ThreadInfo hashtable and semaphore.
112 Call once per NLM instance
118 ==============================================================================================*/
120 void fnInitializeThreadInfo(void)
128 g_tinfoSem = kSemaphoreAlloc((BYTE *)"threadInfo", 1);
130 g_tinfoSem = OpenLocalSemaphore(1);
134 for (index = 0; index < NUM_ENTRIES; index++)
135 g_ThreadInfo[index] = NULL;
141 /*============================================================================================
143 Function : fnRegisterWithThreadTable
145 Description : This function registers/adds a new thread with the thread table.
151 ==============================================================================================*/
153 BOOL fnRegisterWithThreadTable(void)
155 ThreadInfo* tinfo = NULL;
158 tinfo = fnAddThreadInfo(labs((int)kCurrentThread()));
160 tinfo = fnAddThreadInfo(GetThreadID());
170 /*============================================================================================
172 Function : fnUnregisterWithThreadTable
174 Description : This function unregisters/removes a thread from the thread table.
180 ==============================================================================================*/
182 BOOL fnUnregisterWithThreadTable(void)
185 return fnRemoveThreadInfo(labs((int)kCurrentThread()));
187 return fnRemoveThreadInfo(GetThreadID());
192 /*============================================================================================
194 Function : fnAddThreadInfo
196 Description : Adds a new ThreadInfo for the requested thread.
198 Parameters : tid (IN) - ID of the thread.
200 Returns : Pointer to the ThreadInfo Structure.
202 ==============================================================================================*/
204 ThreadInfo* fnAddThreadInfo(int tid)
206 ThreadInfo* tip = NULL;
212 kSemaphoreWait(g_tinfoSem);
214 WaitOnLocalSemaphore(g_tinfoSem);
218 // Add a new one to the beginning of the hash entry
220 tip = (ThreadInfo *) malloc(sizeof(ThreadInfo));
226 kSemaphoreSignal(g_tinfoSem);
228 SignalLocalSemaphore(g_tinfoSem);
233 index = INDEXOF(tid); // just take the bottom five bits
234 tip->next = g_ThreadInfo[index];
236 tip->m_dontTouchHashLists = FALSE;
237 tip->m_allocList = NULL;
239 g_ThreadInfo [index] = tip;
243 kSemaphoreSignal(g_tinfoSem);
245 SignalLocalSemaphore(g_tinfoSem);
253 /*============================================================================================
255 Function : fnRemoveThreadInfo
257 Description : Frees the specified thread info structure and removes it from the
260 Parameters : tid (IN) - ID of the thread.
264 ==============================================================================================*/
266 BOOL fnRemoveThreadInfo(int tid)
268 ThreadInfo* tip = NULL;
269 ThreadInfo* prevt = NULL;
270 int index = INDEXOF(tid); // just take the bottom five bits
275 kSemaphoreWait(g_tinfoSem);
277 WaitOnLocalSemaphore(g_tinfoSem);
281 for (tip = g_ThreadInfo[index]; tip != NULL; tip = tip->next)
286 g_ThreadInfo[index] = tip->next;
288 prevt->next = tip->next;
295 kSemaphoreSignal(g_tinfoSem);
297 SignalLocalSemaphore(g_tinfoSem);
309 kSemaphoreSignal(g_tinfoSem);
311 SignalLocalSemaphore(g_tinfoSem);
315 return FALSE; // entry not found
319 /*============================================================================================
321 Function : fnGetThreadInfo
323 Description : Returns the thread info for the given thread ID or NULL if not successful.
325 Parameters : tid (IN) - ID of the thread.
327 Returns : Pointer to the ThreadInfo Structure.
329 ==============================================================================================*/
331 ThreadInfo* fnGetThreadInfo(int tid)
334 int index = INDEXOF(tid); // just take the bottom five bits
338 kSemaphoreWait(g_tinfoSem);
340 WaitOnLocalSemaphore(g_tinfoSem);
344 // see if this is already in the table at the index'th offset
346 for (tip = g_ThreadInfo[index]; tip != NULL; tip = tip->next)
353 kSemaphoreSignal(g_tinfoSem);
355 SignalLocalSemaphore(g_tinfoSem);
365 kSemaphoreSignal(g_tinfoSem);
367 SignalLocalSemaphore(g_tinfoSem);
374 BOOL fnInsertHashListAddrs(void *addrs, BOOL dontTouchHashList)
382 kSemaphoreWait(g_tinfoSem);
384 WaitOnLocalSemaphore(g_tinfoSem);
389 tid=index = abs(kCurrentThread());
391 tid=index = GetThreadID();
394 index = INDEXOF(index); // just take the bottom five bits
396 // see if this is already in the table at the index'th offset
398 for (tip = g_ThreadInfo[index]; tip != NULL; tip = tip->next)
405 kSemaphoreSignal(g_tinfoSem);
407 SignalLocalSemaphore(g_tinfoSem);
410 tip->m_allocList = addrs;
411 tip->m_dontTouchHashLists = dontTouchHashList;
419 kSemaphoreSignal(g_tinfoSem);
421 SignalLocalSemaphore(g_tinfoSem);
428 BOOL fnGetHashListAddrs(void **addrs, BOOL *dontTouchHashList)
436 kSemaphoreWait(g_tinfoSem);
438 WaitOnLocalSemaphore(g_tinfoSem);
443 tid=index = abs(kCurrentThread());
445 tid=index = GetThreadID();
448 index = INDEXOF(index); // just take the bottom five bits
450 // see if this is already in the table at the index'th offset
452 for (tip = g_ThreadInfo[index]; tip != NULL; tip = tip->next)
459 kSemaphoreSignal(g_tinfoSem);
461 SignalLocalSemaphore(g_tinfoSem);
464 *addrs = tip->m_allocList;
465 *dontTouchHashList = tip->m_dontTouchHashLists;
473 kSemaphoreSignal(g_tinfoSem);
475 SignalLocalSemaphore(g_tinfoSem);
483 /*============================================================================================
485 Function : fnInitializeThreadCtx
487 Description : Initialises the thread context.
493 ==============================================================================================*/
495 long fnInitializeThreadCtx(void)
502 g_tCtxSem = kSemaphoreAlloc((BYTE *)"threadCtx", 1);
504 g_tCtxSem = OpenLocalSemaphore(1);
514 /*============================================================================================
516 Function : fnAddThreadCtx
518 Description : Add a new thread context.
520 Parameters : lTLSIndex (IN) - Index
521 t (IN) - void pointer.
523 Returns : Pointer to ThreadContext structure.
525 ==============================================================================================*/
527 ThreadContext* fnAddThreadCtx(long lTLSIndex, void *t)
529 ThreadContext* tip = NULL;
530 ThreadContext* temp = NULL;
535 kSemaphoreWait(g_tCtxSem);
537 WaitOnLocalSemaphore(g_tCtxSem);
541 // add a new one to the beginning of the list
543 tip = (ThreadContext *) malloc(sizeof(ThreadContext));
549 kSemaphoreSignal(g_tCtxSem);
551 SignalLocalSemaphore(g_tCtxSem);
558 lTLSIndex = labs(kCurrentThread());
560 lTLSIndex = GetThreadID();
564 tip->tid = lTLSIndex;
567 if(g_ThreadCtx==NULL) {
571 //Traverse to the end
573 while(temp->next != NULL)
584 kSemaphoreSignal(g_tCtxSem);
586 SignalLocalSemaphore(g_tCtxSem);
593 /*============================================================================================
595 Function : fnRemoveThreadCtx
597 Description : Removes a thread context.
599 Parameters : lTLSIndex (IN) - Index
603 ==============================================================================================*/
605 BOOL fnRemoveThreadCtx(long lTLSIndex)
607 ThreadContext* tip = NULL;
608 ThreadContext* prevt = NULL;
613 kSemaphoreWait(g_tCtxSem);
615 WaitOnLocalSemaphore(g_tCtxSem);
620 lTLSIndex = labs(kCurrentThread());
622 lTLSIndex = GetThreadID();
627 if (tip->tid == lTLSIndex) {
629 g_ThreadCtx = tip->next;
631 prevt->next = tip->next;
638 kSemaphoreSignal(g_tCtxSem);
640 SignalLocalSemaphore(g_tCtxSem);
652 kSemaphoreSignal(g_tCtxSem);
654 SignalLocalSemaphore(g_tCtxSem);
658 return FALSE; // entry not found
662 /*============================================================================================
664 Function : fnGetThreadCtx
666 Description : Get a thread context.
668 Parameters : lTLSIndex (IN) - Index
672 ==============================================================================================*/
674 void* fnGetThreadCtx(long lTLSIndex)
681 kSemaphoreWait(g_tCtxSem);
683 WaitOnLocalSemaphore(g_tCtxSem);
688 lTLSIndex = labs(kCurrentThread());
690 lTLSIndex = GetThreadID();
695 if (tip->tid == lTLSIndex) {
699 kSemaphoreSignal(g_tCtxSem);
701 SignalLocalSemaphore(g_tCtxSem);
712 kSemaphoreSignal(g_tCtxSem);
714 SignalLocalSemaphore(g_tCtxSem);