1 
2 /*
3  * Copyright � 2001 Novell, Inc. All Rights Reserved.
4  *
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.
7  *
8  */
9 
10 /*
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.
15  * Author		:	SGP, HYAK
16  * Date			:	January 2001.
17  *
18  */
19 
20 
21 
22 #include "win32ish.h"		// For "BOOL", "TRUE" and "FALSE"
23 #include "nwtinfo.h"
24 
25 #ifdef MPK_ON
26 	#include <mpktypes.h>
27 	#include <mpkapis.h>
28 #else
29 	#include <nwsemaph.h>
30 #endif	//MPK_ON
31 
32 // Number of entries in the hashtable
33 //
34 #define NUM_ENTRIES 32  /* 2^5 */
35 
36 
37 // macro to calculate the hash index for a given Thread ID
38 //
39 #define INDEXOF(tid) ((tid) & 0x1f)
40 
41 
42 // Semaphore to control access to global linked list
43 //
44 #ifdef MPK_ON
45 	static SEMAPHORE g_tinfoSem = NULL;
46 	static SEMAPHORE g_tCtxSem = NULL;
47 #else
48 	static LONG g_tinfoSem = 0L;
49 	static LONG g_tCtxSem = 0L;
50 #endif	//MPK_ON
51 
52 // Hash table of thread information structures
53 //
54 ThreadInfo* g_ThreadInfo[NUM_ENTRIES];
55 ThreadContext* g_ThreadCtx;
56 
57 
58 
59 /*============================================================================================
60 
61  Function		:	fnTerminateThreadInfo
62 
63  Description	:	This function undoes fnInitializeThreadInfo; call once per NLM instance.
64 
65  Parameters 	:	None.
66 
67  Returns		:	Boolean.
68 
69 ==============================================================================================*/
70 
fnTerminateThreadInfo(void)71 BOOL fnTerminateThreadInfo(void)
72 {
73 	int index = 0;
74 
75 	if (g_tinfoSem)
76 	{
77 		#ifdef MPK_ON
78 			kSemaphoreWait(g_tinfoSem);
79 		#else
80 			WaitOnLocalSemaphore(g_tinfoSem);
81 		#endif	//MPK_ON
82 		for (index = 0; index < NUM_ENTRIES; index++)
83 		{
84 			if (g_ThreadInfo[index] != NULL)
85 			{
86 				#ifdef MPK_ON
87 					kSemaphoreSignal(g_tinfoSem);
88 				#else
89 					SignalLocalSemaphore(g_tinfoSem);
90 				#endif	//MPK_ON
91 				return FALSE;
92 			}
93 		}
94 		#ifdef MPK_ON
95 			kSemaphoreFree(g_tinfoSem);
96 			g_tinfoSem = NULL;
97 		#else
98 			CloseLocalSemaphore(g_tinfoSem);
99 			g_tinfoSem = 0;
100 		#endif	//MPK_ON
101 	}
102 
103 	return TRUE;
104 }
105 
106 
107 /*============================================================================================
108 
109  Function		:	fnInitializeThreadInfo
110 
111  Description	:	Initializes the global ThreadInfo hashtable and semaphore.
112 					Call once per NLM instance
113 
114  Parameters 	:	None.
115 
116  Returns		:	Nothing.
117 
118 ==============================================================================================*/
119 
fnInitializeThreadInfo(void)120 void fnInitializeThreadInfo(void)
121 {
122 	int index = 0;
123 
124 	if (g_tinfoSem)
125 		return;
126 
127 	#ifdef MPK_ON
128 		g_tinfoSem = kSemaphoreAlloc((BYTE *)"threadInfo", 1);
129 	#else
130 		g_tinfoSem = OpenLocalSemaphore(1);
131 	#endif	//MPK_ON
132 
133 
134 	for (index = 0; index < NUM_ENTRIES; index++)
135 		g_ThreadInfo[index] = NULL;
136 
137 	return;
138 }
139 
140 
141 /*============================================================================================
142 
143  Function		:	fnRegisterWithThreadTable
144 
145  Description	:	This function registers/adds a new thread with the thread table.
146 
147  Parameters 	:	None.
148 
149  Returns		:	Boolean.
150 
151 ==============================================================================================*/
152 
fnRegisterWithThreadTable(void)153 BOOL fnRegisterWithThreadTable(void)
154 {
155 	ThreadInfo* tinfo = NULL;
156 
157 	#ifdef MPK_ON
158 		tinfo = fnAddThreadInfo(labs((int)kCurrentThread()));
159 	#else
160 		tinfo = fnAddThreadInfo(GetThreadID());
161 	#endif	//MPK_ON
162 
163 	if (!tinfo)
164 		return FALSE;
165 	else
166 		return TRUE;
167 }
168 
169 
170 /*============================================================================================
171 
172  Function		:	fnUnregisterWithThreadTable
173 
174  Description	:	This function unregisters/removes a thread from the thread table.
175 
176  Parameters 	:	None.
177 
178  Returns		:	Boolean.
179 
180 ==============================================================================================*/
181 
fnUnregisterWithThreadTable(void)182 BOOL fnUnregisterWithThreadTable(void)
183 {
184 	#ifdef MPK_ON
185 		return fnRemoveThreadInfo(labs((int)kCurrentThread()));
186 	#else
187 		return fnRemoveThreadInfo(GetThreadID());
188 	#endif	//MPK_ON
189 }
190 
191 
192 /*============================================================================================
193 
194  Function		:	fnAddThreadInfo
195 
196  Description	:	Adds a new ThreadInfo for the requested thread.
197 
198  Parameters 	:	tid	(IN)	-	ID of the thread.
199 
200  Returns		:	Pointer to the ThreadInfo Structure.
201 
202 ==============================================================================================*/
203 
fnAddThreadInfo(int tid)204 ThreadInfo* fnAddThreadInfo(int tid)
205 {
206 	ThreadInfo* tip = NULL;
207 	int index = 0;
208 
209 	if (g_tinfoSem)
210 	{
211 		#ifdef MPK_ON
212 			kSemaphoreWait(g_tinfoSem);
213 		#else
214 			WaitOnLocalSemaphore(g_tinfoSem);
215 		#endif	//MPK_ON
216 	}
217 
218 	// Add a new one to the beginning of the hash entry
219 	//
220 	tip = (ThreadInfo *) malloc(sizeof(ThreadInfo));
221 	if (tip == NULL)
222 	{
223 		if (g_tinfoSem)
224 		{
225 			#ifdef MPK_ON
226 				kSemaphoreSignal(g_tinfoSem);
227 			#else
228 				SignalLocalSemaphore(g_tinfoSem);
229 			#endif	//MPK_ON
230 		}
231 		return NULL;
232 	}
233 	index = INDEXOF(tid);     // just take the bottom five bits
234 	tip->next            =  g_ThreadInfo[index];
235 	tip->tid             =  tid;
236 	tip->m_dontTouchHashLists = FALSE;
237 	tip->m_allocList = NULL;
238 
239 	g_ThreadInfo [index] =  tip;
240 	if (g_tinfoSem)
241 	{
242 		#ifdef MPK_ON
243 			kSemaphoreSignal(g_tinfoSem);
244 		#else
245 			SignalLocalSemaphore(g_tinfoSem);
246 		#endif	//MPK_ON
247 	}
248 
249 	return tip;
250 }
251 
252 
253 /*============================================================================================
254 
255  Function		:	fnRemoveThreadInfo
256 
257  Description	:	Frees the specified thread info structure and removes it from the
258 					global linked list.
259 
260  Parameters 	:	tid	(IN)	-	ID of the thread.
261 
262  Returns		:	Boolean.
263 
264 ==============================================================================================*/
265 
fnRemoveThreadInfo(int tid)266 BOOL fnRemoveThreadInfo(int tid)
267 {
268 	ThreadInfo* tip = NULL;
269 	ThreadInfo* prevt = NULL;
270 	int index = INDEXOF(tid);     // just take the bottom five bits
271 
272 	if (g_tinfoSem)
273 	{
274 		#ifdef MPK_ON
275 			kSemaphoreWait(g_tinfoSem);
276 		#else
277 			WaitOnLocalSemaphore(g_tinfoSem);
278 		#endif	//MPK_ON
279 	}
280 
281 	for (tip = g_ThreadInfo[index]; tip != NULL; tip = tip->next)
282 	{
283 		if (tip->tid == tid)
284 		{
285 			if (prevt == NULL)
286 				g_ThreadInfo[index] = tip->next;
287 			else
288 				prevt->next = tip->next;
289 
290 			free(tip);
291 			tip=NULL;
292 			if (g_tinfoSem)
293 			{
294 				#ifdef MPK_ON
295 					kSemaphoreSignal(g_tinfoSem);
296 				#else
297 					SignalLocalSemaphore(g_tinfoSem);
298 				#endif	//MPK_ON
299 			}
300 
301 			return TRUE;
302 		}
303 		prevt = tip;
304 	}
305 
306 	if (g_tinfoSem)
307 	{
308 		#ifdef MPK_ON
309 			kSemaphoreSignal(g_tinfoSem);
310 		#else
311 			SignalLocalSemaphore(g_tinfoSem);
312 		#endif	//MPK_ON
313 	}
314 
315 	return FALSE;       // entry not found
316 }
317 
318 
319 /*============================================================================================
320 
321  Function		:	fnGetThreadInfo
322 
323  Description	:	Returns the thread info for the given thread ID or NULL if not successful.
324 
325  Parameters 	:	tid	(IN)	-	ID of the thread.
326 
327  Returns		:	Pointer to the ThreadInfo Structure.
328 
329 ==============================================================================================*/
330 
fnGetThreadInfo(int tid)331 ThreadInfo* fnGetThreadInfo(int tid)
332 {
333 	ThreadInfo*  tip;
334 	int index = INDEXOF(tid);     // just take the bottom five bits
335 
336 	if (g_tinfoSem) {
337 		#ifdef MPK_ON
338 			kSemaphoreWait(g_tinfoSem);
339 		#else
340 			WaitOnLocalSemaphore(g_tinfoSem);
341 		#endif	//MPK_ON
342 	}
343 
344 	// see if this is already in the table at the index'th offset
345 	//
346 	for (tip = g_ThreadInfo[index]; tip != NULL; tip = tip->next)
347 	{
348 		if (tip->tid == tid)
349 		{
350 			if (g_tinfoSem)
351 			{
352 				#ifdef MPK_ON
353 					kSemaphoreSignal(g_tinfoSem);
354 				#else
355 					SignalLocalSemaphore(g_tinfoSem);
356 				#endif	//MPK_ON
357 			}
358 			return tip;
359 		}
360 	}
361 
362 	if (g_tinfoSem)
363 	{
364 		#ifdef MPK_ON
365 			kSemaphoreSignal(g_tinfoSem);
366 		#else
367 			SignalLocalSemaphore(g_tinfoSem);
368 		#endif	//MPK_ON
369 	}
370 
371 	return NULL;
372 }
373 
fnInsertHashListAddrs(void * addrs,BOOL dontTouchHashList)374 BOOL fnInsertHashListAddrs(void *addrs, BOOL dontTouchHashList)
375 {
376 	ThreadInfo*  tip;
377 	int index,tid;
378 
379 	if (g_tinfoSem)
380 	{
381 		#ifdef MPK_ON
382 			kSemaphoreWait(g_tinfoSem);
383 		#else
384 			WaitOnLocalSemaphore(g_tinfoSem);
385 		#endif	//MPK_ON
386 	}
387 
388 	#ifdef MPK_ON
389 		tid=index = abs(kCurrentThread());
390 	#else
391 		tid=index = GetThreadID();
392 	#endif	//MPK_ON
393 
394 	index = INDEXOF(index);     // just take the bottom five bits
395 
396 	// see if this is already in the table at the index'th offset
397 	//
398 	for (tip = g_ThreadInfo[index]; tip != NULL; tip = tip->next)
399 	{
400 		if (tip->tid == tid)
401 		{
402 			if (g_tinfoSem)
403 			{
404 				#ifdef MPK_ON
405 					kSemaphoreSignal(g_tinfoSem);
406 				#else
407 					SignalLocalSemaphore(g_tinfoSem);
408 				#endif	//MPK_ON
409 			}
410 			tip->m_allocList = addrs;
411 			tip->m_dontTouchHashLists = dontTouchHashList;
412 			return TRUE;
413 		}
414 	}
415 
416 	if (g_tinfoSem)
417 	{
418 		#ifdef MPK_ON
419 			kSemaphoreSignal(g_tinfoSem);
420 		#else
421 			SignalLocalSemaphore(g_tinfoSem);
422 		#endif	//MPK_ON
423 	}
424 
425 	return FALSE;
426 }
427 
fnGetHashListAddrs(void ** addrs,BOOL * dontTouchHashList)428 BOOL fnGetHashListAddrs(void **addrs, BOOL *dontTouchHashList)
429 {
430 	ThreadInfo*  tip;
431 	int index,tid;
432 
433 	if (g_tinfoSem)
434 	{
435 		#ifdef MPK_ON
436 			kSemaphoreWait(g_tinfoSem);
437 		#else
438 			WaitOnLocalSemaphore(g_tinfoSem);
439 		#endif	//MPK_ON
440 	}
441 
442 	#ifdef MPK_ON
443 		tid=index = abs(kCurrentThread());
444 	#else
445 		tid=index = GetThreadID();
446 	#endif	//MPK_ON
447 
448 	index = INDEXOF(index);     // just take the bottom five bits
449 
450 	// see if this is already in the table at the index'th offset
451 	//
452 	for (tip = g_ThreadInfo[index]; tip != NULL; tip = tip->next)
453 	{
454 		if (tip->tid == tid)
455 		{
456 			if (g_tinfoSem)
457 			{
458 				#ifdef MPK_ON
459 					kSemaphoreSignal(g_tinfoSem);
460 				#else
461 					SignalLocalSemaphore(g_tinfoSem);
462 				#endif	//MPK_ON
463 			}
464 			*addrs = tip->m_allocList;
465 			*dontTouchHashList = tip->m_dontTouchHashLists;
466 			return TRUE;
467 		}
468 	}
469 
470 	if (g_tinfoSem)
471 	{
472 		#ifdef MPK_ON
473 			kSemaphoreSignal(g_tinfoSem);
474 		#else
475 			SignalLocalSemaphore(g_tinfoSem);
476 		#endif	//MPK_ON
477 	}
478 
479 	return FALSE;
480 }
481 
482 
483 /*============================================================================================
484 
485  Function		:	fnInitializeThreadCtx
486 
487  Description	:	Initialises the thread context.
488 
489  Parameters 	:	None.
490 
491  Returns		:	Nothing.
492 
493 ==============================================================================================*/
494 
fnInitializeThreadCtx(void)495 long fnInitializeThreadCtx(void)
496 {
497 	int index = 0;
498 	//long tid;
499 
500 	if (!g_tCtxSem) {
501 		#ifdef MPK_ON
502 			g_tCtxSem = kSemaphoreAlloc((BYTE *)"threadCtx", 1);
503 		#else
504 			g_tCtxSem = OpenLocalSemaphore(1);
505 		#endif	//MPK_ON
506 
507 		g_ThreadCtx =NULL;
508 	}
509 
510 	return 0l;
511 }
512 
513 
514 /*============================================================================================
515 
516  Function		:	fnAddThreadCtx
517 
518  Description	:	Add a new thread context.
519 
520  Parameters 	:	lTLSIndex	(IN)	-	Index
521 					t	(IN)	-	void pointer.
522 
523  Returns		:	Pointer to ThreadContext structure.
524 
525 ==============================================================================================*/
526 
fnAddThreadCtx(long lTLSIndex,void * t)527 ThreadContext* fnAddThreadCtx(long lTLSIndex, void *t)
528 {
529 	ThreadContext* tip = NULL;
530 	ThreadContext* temp = NULL;
531 
532 	if (g_tCtxSem)
533 	{
534 		#ifdef MPK_ON
535 			kSemaphoreWait(g_tCtxSem);
536 		#else
537 			WaitOnLocalSemaphore(g_tCtxSem);
538 		#endif	//MPK_ON
539 	}
540 
541 	// add a new one to the beginning of the list
542 	//
543 	tip = (ThreadContext *) malloc(sizeof(ThreadContext));
544 	if (tip == NULL)
545 	{
546 		if (g_tCtxSem)
547 		{
548 			#ifdef MPK_ON
549 				kSemaphoreSignal(g_tCtxSem);
550 			#else
551 				SignalLocalSemaphore(g_tCtxSem);
552 			#endif	//MPK_ON
553 		}
554 		return NULL;
555 	}
556 
557 	#ifdef MPK_ON
558 		lTLSIndex = labs(kCurrentThread());
559 	#else
560 		lTLSIndex = GetThreadID();
561 	#endif	//MPK_ON
562 
563 	tip->next            =  NULL;
564 	tip->tid             =  lTLSIndex;
565 	tip->tInfo			 =  t;
566 
567 	if(g_ThreadCtx==NULL) {
568 		g_ThreadCtx = tip;
569 	} else {
570 		int count=0;
571 		//Traverse to the end
572 		temp = g_ThreadCtx;
573 		while(temp->next != NULL)
574 		{
575 			temp = temp->next;
576 			count++;
577 		}
578 		temp->next = tip;
579 	}
580 
581 	if (g_tCtxSem)
582 	{
583 		#ifdef MPK_ON
584 			kSemaphoreSignal(g_tCtxSem);
585 		#else
586 			SignalLocalSemaphore(g_tCtxSem);
587 		#endif	//MPK_ON
588 	}
589 	return tip;
590 }
591 
592 
593 /*============================================================================================
594 
595  Function		:	fnRemoveThreadCtx
596 
597  Description	:	Removes a thread context.
598 
599  Parameters 	:	lTLSIndex	(IN)	-	Index
600 
601  Returns		:	Boolean.
602 
603 ==============================================================================================*/
604 
fnRemoveThreadCtx(long lTLSIndex)605 BOOL fnRemoveThreadCtx(long lTLSIndex)
606 {
607 	ThreadContext* tip = NULL;
608 	ThreadContext* prevt = NULL;
609 
610 	if (g_tCtxSem)
611 	{
612 		#ifdef MPK_ON
613 			kSemaphoreWait(g_tCtxSem);
614 		#else
615 			WaitOnLocalSemaphore(g_tCtxSem);
616 		#endif	//MPK_ON
617 	}
618 
619 	#ifdef MPK_ON
620 		lTLSIndex = labs(kCurrentThread());
621 	#else
622 		lTLSIndex = GetThreadID();
623 	#endif	//MPK_ON
624 
625 	tip = g_ThreadCtx;
626 	while(tip) {
627 		if (tip->tid == lTLSIndex) {
628 			if (prevt == NULL)
629 				g_ThreadCtx = tip->next;
630 			else
631 				prevt->next = tip->next;
632 
633 			free(tip);
634 			tip=NULL;
635 			if (g_tCtxSem)
636 			{
637 				#ifdef MPK_ON
638 					kSemaphoreSignal(g_tCtxSem);
639 				#else
640 					SignalLocalSemaphore(g_tCtxSem);
641 				#endif	//MPK_ON
642 			}
643 			return TRUE;
644 		}
645 		prevt = tip;
646 		tip = tip->next;
647 	}
648 
649 	if (g_tCtxSem)
650 	{
651 		#ifdef MPK_ON
652 			kSemaphoreSignal(g_tCtxSem);
653 		#else
654 			SignalLocalSemaphore(g_tCtxSem);
655 		#endif	//MPK_ON
656 	}
657 
658 	return FALSE;       // entry not found
659 }
660 
661 
662 /*============================================================================================
663 
664  Function		:	fnGetThreadCtx
665 
666  Description	:	Get a thread context.
667 
668  Parameters 	:	lTLSIndex	(IN)	-	Index
669 
670  Returns		:	Nothing.
671 
672 ==============================================================================================*/
673 
fnGetThreadCtx(long lTLSIndex)674 void* fnGetThreadCtx(long lTLSIndex)
675 {
676 	ThreadContext*  tip;
677 
678 	if (g_tCtxSem)
679 	{
680 		#ifdef MPK_ON
681 			kSemaphoreWait(g_tCtxSem);
682 		#else
683 			WaitOnLocalSemaphore(g_tCtxSem);
684 		#endif	//MPK_ON
685 	}
686 
687 	#ifdef MPK_ON
688 		lTLSIndex = labs(kCurrentThread());
689 	#else
690 		lTLSIndex = GetThreadID();
691 	#endif	//MPK_ON
692 
693 	tip = g_ThreadCtx;
694 	while(tip) {
695 		if (tip->tid == lTLSIndex) {
696 			if (g_tCtxSem)
697 			{
698 				#ifdef MPK_ON
699 					kSemaphoreSignal(g_tCtxSem);
700 				#else
701 					SignalLocalSemaphore(g_tCtxSem);
702 				#endif	//MPK_ON
703 			}
704 			return (tip->tInfo);
705 		}
706 		tip=tip->next;
707 	}
708 
709 	if (g_tCtxSem)
710 	{
711 		#ifdef MPK_ON
712 			kSemaphoreSignal(g_tCtxSem);
713 		#else
714 			SignalLocalSemaphore(g_tCtxSem);
715 		#endif	//MPK_ON
716 	}
717 
718 	return NULL;
719 }
720 
721