Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/generic/tclThread.c @ 35

Last change on this file since 35 was 25, checked in by landauf, 17 years ago

added tcl to libs

File size: 11.1 KB
Line 
1/*
2 * tclThread.c --
3 *
4 *      This file implements Platform independent thread operations. Most of
5 *      the real work is done in the platform dependent files.
6 *
7 * Copyright (c) 1998 by Sun Microsystems, Inc.
8 *
9 * See the file "license.terms" for information on usage and redistribution of
10 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 *
12 * RCS: @(#) $Id: tclThread.c,v 1.19 2007/12/13 15:23:20 dgp Exp $
13 */
14
15#include "tclInt.h"
16
17/*
18 * There are three classes of synchronization objects: mutexes, thread data
19 * keys, and condition variables. The following are used to record the memory
20 * used for these objects so they can be finalized.
21 *
22 * These statics are guarded by the mutex in the caller of
23 * TclRememberThreadData, e.g., TclpThreadDataKeyInit
24 */
25
26typedef struct {
27    int num;            /* Number of objects remembered */
28    int max;            /* Max size of the array */
29    char **list;        /* List of pointers */
30} SyncObjRecord;
31
32static SyncObjRecord keyRecord = {0, 0, NULL};
33static SyncObjRecord mutexRecord = {0, 0, NULL};
34static SyncObjRecord condRecord = {0, 0, NULL};
35
36/*
37 * Prototypes of functions used only in this file.
38 */
39
40static void             ForgetSyncObject(char *objPtr, SyncObjRecord *recPtr);
41static void             RememberSyncObject(char *objPtr,
42                            SyncObjRecord *recPtr);
43
44/*
45 * Several functions are #defined to nothing in tcl.h if TCL_THREADS is not
46 * specified. Here we undo that so the functions are defined in the stubs
47 * table.
48 */
49
50#ifndef TCL_THREADS
51#undef Tcl_MutexLock
52#undef Tcl_MutexUnlock
53#undef Tcl_MutexFinalize
54#undef Tcl_ConditionNotify
55#undef Tcl_ConditionWait
56#undef Tcl_ConditionFinalize
57#endif
58
59/*
60 *----------------------------------------------------------------------
61 *
62 * Tcl_GetThreadData --
63 *
64 *      This function allocates and initializes a chunk of thread local
65 *      storage.
66 *
67 * Results:
68 *      A thread-specific pointer to the data structure.
69 *
70 * Side effects:
71 *      Will allocate memory the first time this thread calls for this chunk
72 *      of storage.
73 *
74 *----------------------------------------------------------------------
75 */
76
77void *
78Tcl_GetThreadData(
79    Tcl_ThreadDataKey *keyPtr,  /* Identifier for the data chunk */
80    int size)                   /* Size of storage block */
81{
82    void *result;
83#ifdef TCL_THREADS
84    /*
85     * Initialize the key for this thread.
86     */
87    result = TclpThreadDataKeyGet(keyPtr);
88
89    if (result == NULL) {
90        result = ckalloc((size_t) size);
91        memset(result, 0, (size_t) size);
92        TclpThreadDataKeySet(keyPtr, result);
93    }
94#else /* TCL_THREADS */
95    if (*keyPtr == NULL) {
96        result = ckalloc((size_t) size);
97        memset(result, 0, (size_t) size);
98        *keyPtr = (Tcl_ThreadDataKey)result;
99        RememberSyncObject((char *) keyPtr, &keyRecord);
100    }
101    result = * (void **) keyPtr;
102#endif /* TCL_THREADS */
103    return result;
104}
105
106/*
107 *----------------------------------------------------------------------
108 *
109 * TclThreadDataKeyGet --
110 *
111 *      This function returns a pointer to a block of thread local storage.
112 *
113 * Results:
114 *      A thread-specific pointer to the data structure, or NULL if the memory
115 *      has not been assigned to this key for this thread.
116 *
117 * Side effects:
118 *      None.
119 *
120 *----------------------------------------------------------------------
121 */
122
123void *
124TclThreadDataKeyGet(
125    Tcl_ThreadDataKey *keyPtr)  /* Identifier for the data chunk, really
126                                 * (pthread_key_t **) */
127{
128#ifdef TCL_THREADS
129    return TclpThreadDataKeyGet(keyPtr);
130#else /* TCL_THREADS */
131    char *result = *(char **) keyPtr;
132    return result;
133#endif /* TCL_THREADS */
134}
135
136
137/*
138 *----------------------------------------------------------------------
139 *
140 * RememberSyncObject
141 *
142 *      Keep a list of (mutexes/condition variable/data key) used during
143 *      finalization.
144 *
145 *      Assume master lock is held.
146 *
147 * Results:
148 *      None.
149 *
150 * Side effects:
151 *      Add to the appropriate list.
152 *
153 *----------------------------------------------------------------------
154 */
155
156static void
157RememberSyncObject(
158    char *objPtr,               /* Pointer to sync object */
159    SyncObjRecord *recPtr)      /* Record of sync objects */
160{
161    char **newList;
162    int i, j;
163
164
165    /*
166     * Reuse any free slot in the list.
167     */
168
169    for (i=0 ; i < recPtr->num ; ++i) {
170        if (recPtr->list[i] == NULL) {
171            recPtr->list[i] = objPtr;
172            return;
173        }
174    }
175
176    /*
177     * Grow the list of pointers if necessary, copying only non-NULL
178     * pointers to the new list.
179     */
180
181    if (recPtr->num >= recPtr->max) {
182        recPtr->max += 8;
183        newList = (char **) ckalloc(recPtr->max * sizeof(char *));
184        for (i=0,j=0 ; i<recPtr->num ; i++) {
185            if (recPtr->list[i] != NULL) {
186                newList[j++] = recPtr->list[i];
187            }
188        }
189        if (recPtr->list != NULL) {
190            ckfree((char *) recPtr->list);
191        }
192        recPtr->list = newList;
193        recPtr->num = j;
194    }
195
196    recPtr->list[recPtr->num] = objPtr;
197    recPtr->num++;
198}
199
200/*
201 *----------------------------------------------------------------------
202 *
203 * ForgetSyncObject
204 *
205 *      Remove a single object from the list.
206 *      Assume master lock is held.
207 *
208 * Results:
209 *      None.
210 *
211 * Side effects:
212 *      Remove from the appropriate list.
213 *
214 *----------------------------------------------------------------------
215 */
216
217static void
218ForgetSyncObject(
219    char *objPtr,               /* Pointer to sync object */
220    SyncObjRecord *recPtr)      /* Record of sync objects */
221{
222    int i;
223
224    for (i=0 ; i<recPtr->num ; i++) {
225        if (objPtr == recPtr->list[i]) {
226            recPtr->list[i] = NULL;
227            return;
228        }
229    }
230}
231
232/*
233 *----------------------------------------------------------------------
234 *
235 * TclRememberMutex
236 *
237 *      Keep a list of mutexes used during finalization.
238 *      Assume master lock is held.
239 *
240 * Results:
241 *      None.
242 *
243 * Side effects:
244 *      Add to the mutex list.
245 *
246 *----------------------------------------------------------------------
247 */
248
249void
250TclRememberMutex(
251    Tcl_Mutex *mutexPtr)
252{
253    RememberSyncObject((char *)mutexPtr, &mutexRecord);
254}
255
256/*
257 *----------------------------------------------------------------------
258 *
259 * Tcl_MutexFinalize --
260 *
261 *      Finalize a single mutex and remove it from the list of remembered
262 *      objects.
263 *
264 * Results:
265 *      None.
266 *
267 * Side effects:
268 *      Remove the mutex from the list.
269 *
270 *----------------------------------------------------------------------
271 */
272
273void
274Tcl_MutexFinalize(
275    Tcl_Mutex *mutexPtr)
276{
277#ifdef TCL_THREADS
278    TclpFinalizeMutex(mutexPtr);
279#endif
280    TclpMasterLock();
281    ForgetSyncObject((char *) mutexPtr, &mutexRecord);
282    TclpMasterUnlock();
283}
284
285/*
286 *----------------------------------------------------------------------
287 *
288 * TclRememberCondition
289 *
290 *      Keep a list of condition variables used during finalization.
291 *      Assume master lock is held.
292 *
293 * Results:
294 *      None.
295 *
296 * Side effects:
297 *      Add to the condition variable list.
298 *
299 *----------------------------------------------------------------------
300 */
301
302void
303TclRememberCondition(
304    Tcl_Condition *condPtr)
305{
306    RememberSyncObject((char *) condPtr, &condRecord);
307}
308
309/*
310 *----------------------------------------------------------------------
311 *
312 * Tcl_ConditionFinalize --
313 *
314 *      Finalize a single condition variable and remove it from the list of
315 *      remembered objects.
316 *
317 * Results:
318 *      None.
319 *
320 * Side effects:
321 *      Remove the condition variable from the list.
322 *
323 *----------------------------------------------------------------------
324 */
325
326void
327Tcl_ConditionFinalize(
328    Tcl_Condition *condPtr)
329{
330#ifdef TCL_THREADS
331    TclpFinalizeCondition(condPtr);
332#endif
333    TclpMasterLock();
334    ForgetSyncObject((char *) condPtr, &condRecord);
335    TclpMasterUnlock();
336}
337
338/*
339 *----------------------------------------------------------------------
340 *
341 * TclFinalizeThreadData --
342 *
343 *      This function cleans up the thread-local storage. This is called once
344 *      for each thread.
345 *
346 * Results:
347 *      None.
348 *
349 * Side effects:
350 *      Frees up all thread local storage.
351 *
352 *----------------------------------------------------------------------
353 */
354
355void
356TclFinalizeThreadData(void)
357{
358    TclpFinalizeThreadDataThread();
359}
360
361/*
362 *----------------------------------------------------------------------
363 *
364 * TclFinalizeSynchronization --
365 *
366 *      This function cleans up all synchronization objects: mutexes,
367 *      condition variables, and thread-local storage.
368 *
369 * Results:
370 *      None.
371 *
372 * Side effects:
373 *      Frees up the memory.
374 *
375 *----------------------------------------------------------------------
376 */
377
378void
379TclFinalizeSynchronization(void)
380{
381    int i;
382    void *blockPtr;
383    Tcl_ThreadDataKey *keyPtr;
384#ifdef TCL_THREADS
385    Tcl_Mutex *mutexPtr;
386    Tcl_Condition *condPtr;
387
388    TclpMasterLock();
389#endif
390
391    /*
392     * If we're running unthreaded, the TSD blocks are simply stored inside
393     * their thread data keys. Free them here.
394     */
395
396    if (keyRecord.list != NULL) {
397        for (i=0 ; i<keyRecord.num ; i++) {
398            keyPtr = (Tcl_ThreadDataKey *) keyRecord.list[i];
399            blockPtr = (void *) *keyPtr;
400            ckfree(blockPtr);
401        }
402        ckfree((char *) keyRecord.list);
403        keyRecord.list = NULL;
404    }
405    keyRecord.max = 0;
406    keyRecord.num = 0;
407   
408#ifdef TCL_THREADS
409    /*
410     * Call thread storage master cleanup.
411     */
412
413    TclFinalizeThreadStorage();
414
415    for (i=0 ; i<mutexRecord.num ; i++) {
416        mutexPtr = (Tcl_Mutex *)mutexRecord.list[i];
417        if (mutexPtr != NULL) {
418            TclpFinalizeMutex(mutexPtr);
419        }
420    }
421    if (mutexRecord.list != NULL) {
422        ckfree((char *) mutexRecord.list);
423        mutexRecord.list = NULL;
424    }
425    mutexRecord.max = 0;
426    mutexRecord.num = 0;
427
428    for (i=0 ; i<condRecord.num ; i++) {
429        condPtr = (Tcl_Condition *) condRecord.list[i];
430        if (condPtr != NULL) {
431            TclpFinalizeCondition(condPtr);
432        }
433    }
434    if (condRecord.list != NULL) {
435        ckfree((char *) condRecord.list);
436        condRecord.list = NULL;
437    }
438    condRecord.max = 0;
439    condRecord.num = 0;
440
441    TclpMasterUnlock();
442#endif /* TCL_THREADS */
443}
444
445/*
446 *----------------------------------------------------------------------
447 *
448 * Tcl_ExitThread --
449 *
450 *      This function is called to terminate the current thread. This should
451 *      be used by extensions that create threads with additional interpreters
452 *      in them.
453 *
454 * Results:
455 *      None.
456 *
457 * Side effects:
458 *      All thread exit handlers are invoked, then the thread dies.
459 *
460 *----------------------------------------------------------------------
461 */
462
463void
464Tcl_ExitThread(
465    int status)
466{
467    Tcl_FinalizeThread();
468#ifdef TCL_THREADS
469    TclpThreadExit(status);
470#endif
471}
472
473#ifndef TCL_THREADS
474
475/*
476 *----------------------------------------------------------------------
477 *
478 * Tcl_ConditionWait, et al. --
479 *
480 *      These noop functions are provided so the stub table does not have to
481 *      be conditionalized for threads. The real implementations of these
482 *      functions live in the platform specific files.
483 *
484 * Results:
485 *      None.
486 *
487 * Side effects:
488 *      None.
489 *
490 *----------------------------------------------------------------------
491 */
492
493#undef Tcl_ConditionWait
494void
495Tcl_ConditionWait(
496    Tcl_Condition *condPtr,     /* Really (pthread_cond_t **) */
497    Tcl_Mutex *mutexPtr,        /* Really (pthread_mutex_t **) */
498    Tcl_Time *timePtr)          /* Timeout on waiting period */
499{
500}
501
502#undef Tcl_ConditionNotify
503void
504Tcl_ConditionNotify(
505    Tcl_Condition *condPtr)
506{
507}
508
509#undef Tcl_MutexLock
510void
511Tcl_MutexLock(
512    Tcl_Mutex *mutexPtr)
513{
514}
515
516#undef Tcl_MutexUnlock
517void
518Tcl_MutexUnlock(
519    Tcl_Mutex *mutexPtr)
520{
521}
522#endif /* !TCL_THREADS */
523
524/*
525 * Local Variables:
526 * mode: c
527 * c-basic-offset: 4
528 * fill-column: 78
529 * End:
530 */
Note: See TracBrowser for help on using the repository browser.