Move Thread::Semaphore from ext/ to dist/
[perl.git] / NetWare / NWTInfo.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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