diff options
Diffstat (limited to 'generic/tclThreadJoin.c')
| -rw-r--r-- | generic/tclThreadJoin.c | 317 | 
1 files changed, 161 insertions, 156 deletions
| diff --git a/generic/tclThreadJoin.c b/generic/tclThreadJoin.c index d3afe33..5c70a62 100644 --- a/generic/tclThreadJoin.c +++ b/generic/tclThreadJoin.c @@ -1,71 +1,66 @@ -/*  +/*   * tclThreadJoin.c --   * - *	This file implements a platform independent emulation layer for - *	the handling of joinable threads. The Mac and Windows platforms - *	use this code to provide the functionality of joining threads. - *	This code is currently not necessary on Unix. + *	This file implements a platform independent emulation layer for the + *	handling of joinable threads. The Windows platform uses this code to + *	provide the functionality of joining threads.  This code is currently + *	not necessary on Unix.   *   * Copyright (c) 2000 by Scriptics Corporation   * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tclThreadJoin.c,v 1.4 2002/04/24 20:35:40 hobbs Exp $ + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES.   */  #include "tclInt.h" -#if defined(WIN32) || defined(MAC_TCL) +#ifdef _WIN32 -/* The information about each joinable thread is remembered in a - * structure as defined below. +/* + * The information about each joinable thread is remembered in a structure as + * defined below.   */  typedef struct JoinableThread { -  Tcl_ThreadId  id;                     /* The id of the joinable thread */ -  int           result;                 /* A place for the result after the -					 * demise of the thread */ -  int           done;                   /* Boolean flag. Initialized to 0 -					 * and set to 1 after the exit of -					 * the thread. This allows a thread -					 * requesting a join to detect when -					 * waiting is not necessary. */ -  int           waitedUpon;             /* Boolean flag. Initialized to 0 -					 * and set to 1 by the thread waiting -					 * for this one via Tcl_JoinThread. -					 * Used to lock any other thread -					 * trying to wait on this one. -					 */ -  Tcl_Mutex     threadMutex;            /* The mutex used to serialize access -					 * to this structure. */ -  Tcl_Condition cond;                   /* This is the condition a thread has -					 * to wait upon to get notified of the -					 * end of the described thread. It is -					 * signaled indirectly by -					 * Tcl_ExitThread. */ -  struct JoinableThread* nextThreadPtr; /* Reference to the next thread in the -					 * list of joinable threads */ +    Tcl_ThreadId  id;		/* The id of the joinable thread. */ +    int result;			/* A place for the result after the demise of +				 * the thread. */ +    int done;			/* Boolean flag. Initialized to 0 and set to 1 +				 * after the exit of the thread. This allows a +				 * thread requesting a join to detect when +				 * waiting is not necessary. */ +    int waitedUpon;		/* Boolean flag. Initialized to 0 and set to 1 +				 * by the thread waiting for this one via +				 * Tcl_JoinThread.  Used to lock any other +				 * thread trying to wait on this one. */ +    Tcl_Mutex threadMutex;	/* The mutex used to serialize access to this +				 * structure. */ +    Tcl_Condition cond;		/* This is the condition a thread has to wait +				 * upon to get notified of the end of the +				 * described thread. It is signaled indirectly +				 * by Tcl_ExitThread. */ +    struct JoinableThread *nextThreadPtr; +				/* Reference to the next thread in the list of +				 * joinable threads. */  } JoinableThread; -/* The following variable is used to maintain the global list of all - * joinable threads. Usage by a thread is allowed only if the - * thread acquired the 'joinMutex'. +/* + * The following variable is used to maintain the global list of all joinable + * threads. Usage by a thread is allowed only if the thread acquired the + * 'joinMutex'.   */  TCL_DECLARE_MUTEX(joinMutex) -static JoinableThread* firstThreadPtr; - - +static JoinableThread *firstThreadPtr;  /*   *----------------------------------------------------------------------   *   * TclJoinThread --   * - *	This procedure waits for the exit of the thread with the specified - *	id and returns its result. + *	This procedure waits for the exit of the thread with the specified id + *	and returns its result.   *   * Results:   *	A standard tcl result signaling the overall success/failure of the @@ -74,135 +69,139 @@ static JoinableThread* firstThreadPtr;   *   * Side effects:   *	Deallocates the memory allocated by TclRememberJoinableThread. - *	Removes the data associated to the thread waited upon from the - *	list of joinable threads. + *	Removes the data associated to the thread waited upon from the list of + *	joinable threads.   *   *----------------------------------------------------------------------   */  int -TclJoinThread(id, result) -    Tcl_ThreadId id;     /* The id of the thread to wait upon. */ -    int*         result; /* Reference to a location for the result -			  * of the thread we are waiting upon. */ +TclJoinThread( +    Tcl_ThreadId id,		/* The id of the thread to wait upon. */ +    int *result)		/* Reference to a location for the result of +				 * the thread we are waiting upon. */  { -    /* Steps done here: +    JoinableThread *threadPtr; + +    /* +     * Steps done here:       * i.    Acquire the joinMutex and search for the thread.       * ii.   Error out if it could not be found.       * iii.  If found, switch from exclusive access to the list to exclusive -     *       access to the thread structure. +     *	     access to the thread structure.       * iv.   Error out if some other is already waiting.       * v.    Skip the waiting part of the thread is already done.       * vi.   Wait for the thread to exit, mark it as waited upon too. -     * vii.  Get the result form the structure,  +     * vii.  Get the result form the structure,       * viii. switch to exclusive access of the list,       * ix.   remove the structure from the list,       * x.    then switch back to exclusive access to the structure       * xi.   and delete it.       */ -    JoinableThread* threadPtr; - -    Tcl_MutexLock (&joinMutex); +    Tcl_MutexLock(&joinMutex); -    for (threadPtr = firstThreadPtr; -	 (threadPtr != (JoinableThread*) NULL) && (threadPtr->id != id); -	 threadPtr = threadPtr->nextThreadPtr) -        /* empty body */ -      ; +    threadPtr = firstThreadPtr; +    while (threadPtr!=NULL && threadPtr->id!=id) { +	threadPtr = threadPtr->nextThreadPtr; +    } -    if (threadPtr == (JoinableThread*) NULL) { -        /* Thread not found. Either not joinable, or already waited -	 * upon and exited. Whatever, an error is in order. +    if (threadPtr == NULL) { +	/* +	 * Thread not found. Either not joinable, or already waited upon and +	 * exited. Whatever, an error is in order.  	 */ -      Tcl_MutexUnlock (&joinMutex); -      return TCL_ERROR; +	Tcl_MutexUnlock(&joinMutex); +	return TCL_ERROR;      } -    /* [1] If we don't lock the structure before giving up exclusive access -     * to the list some other thread just completing its wait on the same -     * thread can delete the structure from under us, leaving us with a -     * dangling pointer. +    /* +     * [1] If we don't lock the structure before giving up exclusive access to +     * the list some other thread just completing its wait on the same thread +     * can delete the structure from under us, leaving us with a dangling +     * pointer.       */ -    Tcl_MutexLock   (&threadPtr->threadMutex); -    Tcl_MutexUnlock (&joinMutex); +    Tcl_MutexLock(&threadPtr->threadMutex); +    Tcl_MutexUnlock(&joinMutex); -    /* [2] Now that we have the structure mutex any other thread that just -     * tries to delete structure will wait at location [3] until we are -     * done with the structure. And in that case we are done with it -     * rather quickly as 'waitedUpon' will be set and we will have to -     * error out. +    /* +     * [2] Now that we have the structure mutex any other thread that just +     * tries to delete structure will wait at location [3] until we are done +     * with the structure. And in that case we are done with it rather quickly +     * as 'waitedUpon' will be set and we will have to error out.       */      if (threadPtr->waitedUpon) { -        Tcl_MutexUnlock (&threadPtr->threadMutex); +	Tcl_MutexUnlock(&threadPtr->threadMutex);  	return TCL_ERROR;      } -    /* We are waiting now, let other threads recognize this +    /* +     * We are waiting now, let other threads recognize this.       */      threadPtr->waitedUpon = 1;      while (!threadPtr->done) { -      Tcl_ConditionWait (&threadPtr->cond, &threadPtr->threadMutex, NULL); +	Tcl_ConditionWait(&threadPtr->cond, &threadPtr->threadMutex, NULL);      } -    /* We have to release the structure before trying to access the list -     * again or we can run into deadlock with a thread at [1] (see above) -     * because of us holding the structure and the other holding the list. -     * There is no problem with dangling pointers here as 'waitedUpon == 1' -     * is still valid and any other thread will error out and not come to -     * this place. IOW, the fact that we are here also means that no other -     * thread came here before us and is able to delete the structure. +    /* +     * We have to release the structure before trying to access the list again +     * or we can run into deadlock with a thread at [1] (see above) because of +     * us holding the structure and the other holding the list.  There is no +     * problem with dangling pointers here as 'waitedUpon == 1' is still valid +     * and any other thread will error out and not come to this place. IOW, +     * the fact that we are here also means that no other thread came here +     * before us and is able to delete the structure.       */ -    Tcl_MutexUnlock (&threadPtr->threadMutex); -    Tcl_MutexLock   (&joinMutex); +    Tcl_MutexUnlock(&threadPtr->threadMutex); +    Tcl_MutexLock(&joinMutex); -    /* We have to search the list again as its structure may (may, almost +    /* +     * We have to search the list again as its structure may (may, almost       * certainly) have changed while we were waiting. Especially now is the -     * time to compute the predecessor in the list. Any earlier result can -     * be dangling by now. +     * time to compute the predecessor in the list. Any earlier result can be +     * dangling by now.       */      if (firstThreadPtr == threadPtr) { -        firstThreadPtr = threadPtr->nextThreadPtr; +	firstThreadPtr = threadPtr->nextThreadPtr;      } else { -        JoinableThread* prevThreadPtr; - -	for (prevThreadPtr = firstThreadPtr; -	     prevThreadPtr->nextThreadPtr != threadPtr; -	     prevThreadPtr = prevThreadPtr->nextThreadPtr) -	    /* empty body */ -	  ; +	JoinableThread *prevThreadPtr = firstThreadPtr; +	while (prevThreadPtr->nextThreadPtr != threadPtr) { +	    prevThreadPtr = prevThreadPtr->nextThreadPtr; +	}  	prevThreadPtr->nextThreadPtr = threadPtr->nextThreadPtr;      } -    Tcl_MutexUnlock (&joinMutex); +    Tcl_MutexUnlock(&joinMutex); -    /* [3] Now that the structure is not part of the list anymore no other +    /* +     * [3] Now that the structure is not part of the list anymore no other       * thread can acquire its mutex from now on. But it is possible that -     * another thread is still holding the mutex though, see location [2]. -     * So we have to acquire the mutex one more time to wait for that thread -     * to finish. We can (and have to) release the mutex immediately. +     * another thread is still holding the mutex though, see location [2].  So +     * we have to acquire the mutex one more time to wait for that thread to +     * finish. We can (and have to) release the mutex immediately.       */ -    Tcl_MutexLock   (&threadPtr->threadMutex); -    Tcl_MutexUnlock (&threadPtr->threadMutex); +    Tcl_MutexLock(&threadPtr->threadMutex); +    Tcl_MutexUnlock(&threadPtr->threadMutex); -    /* Copy the result to us, finalize the synchronisation objects, then -     * free the structure and return. +    /* +     * Copy the result to us, finalize the synchronisation objects, then free +     * the structure and return.       */      *result = threadPtr->result; -    Tcl_ConditionFinalize (&threadPtr->cond); -    Tcl_MutexFinalize (&threadPtr->threadMutex); -    ckfree ((VOID*) threadPtr); +    Tcl_ConditionFinalize(&threadPtr->cond); +    Tcl_MutexFinalize(&threadPtr->threadMutex); +    ckfree(threadPtr);      return TCL_OK;  } @@ -213,39 +212,37 @@ TclJoinThread(id, result)   * TclRememberJoinableThread --   *   *	This procedure remebers a thread as joinable. Only a call to - *	TclJoinThread will remove the structre created (and initialized) - *	here. IOW, not waiting upon a joinable thread will cause memory - *	leaks. + *	TclJoinThread will remove the structre created (and initialized) here. + *	IOW, not waiting upon a joinable thread will cause memory leaks.   *   * Results:   *	None.   *   * Side effects: - *	Allocates memory, adds it to the global list of all joinable - *	threads. + *	Allocates memory, adds it to the global list of all joinable threads.   *   *----------------------------------------------------------------------   */ -VOID -TclRememberJoinableThread(id) -    Tcl_ThreadId id; /* The thread to remember as joinable */ +void +TclRememberJoinableThread( +    Tcl_ThreadId id)		/* The thread to remember as joinable */  { -    JoinableThread* threadPtr; +    JoinableThread *threadPtr; -    threadPtr = (JoinableThread*) ckalloc (sizeof (JoinableThread)); -    threadPtr->id          = id; -    threadPtr->done        = 0; -    threadPtr->waitedUpon  = 0; +    threadPtr = ckalloc(sizeof(JoinableThread)); +    threadPtr->id = id; +    threadPtr->done = 0; +    threadPtr->waitedUpon = 0;      threadPtr->threadMutex = (Tcl_Mutex) NULL; -    threadPtr->cond        = (Tcl_Condition) NULL; +    threadPtr->cond = (Tcl_Condition) NULL; -    Tcl_MutexLock (&joinMutex); +    Tcl_MutexLock(&joinMutex);      threadPtr->nextThreadPtr = firstThreadPtr; -    firstThreadPtr           = threadPtr; +    firstThreadPtr = threadPtr; -    Tcl_MutexUnlock (&joinMutex); +    Tcl_MutexUnlock(&joinMutex);  }  /* @@ -253,9 +250,9 @@ TclRememberJoinableThread(id)   *   * TclSignalExitThread --   * - *	This procedure signals that the specified thread is done with - *	its work. If the thread is joinable this signal is propagated - *	to the thread waiting upon it. + *	This procedure signals that the specified thread is done with its + *	work. If the thread is joinable this signal is propagated to the + *	thread waiting upon it.   *   * Results:   *	None. @@ -266,46 +263,54 @@ TclRememberJoinableThread(id)   *----------------------------------------------------------------------   */ -VOID -TclSignalExitThread(id,result) -    Tcl_ThreadId id;     /* Id of the thread signaling its exit */ -    int          result; /* The result from the thread */ +void +TclSignalExitThread( +    Tcl_ThreadId id,		/* Id of the thread signaling its exit. */ +    int result)			/* The result from the thread. */  { -    JoinableThread* threadPtr; +    JoinableThread *threadPtr; -    Tcl_MutexLock (&joinMutex); +    Tcl_MutexLock(&joinMutex); -    for (threadPtr = firstThreadPtr; -	 (threadPtr != (JoinableThread*) NULL) && (threadPtr->id != id); -	 threadPtr = threadPtr->nextThreadPtr) -        /* empty body */ -      ; +    threadPtr = firstThreadPtr; +    while ((threadPtr != NULL) && (threadPtr->id != id)) { +	threadPtr = threadPtr->nextThreadPtr; +    } -    if (threadPtr == (JoinableThread*) NULL) { -        /* Thread not found. Not joinable. No problem, nothing to do. +    if (threadPtr == NULL) { +	/* +	 * Thread not found. Not joinable. No problem, nothing to do.  	 */ -        Tcl_MutexUnlock (&joinMutex); +	Tcl_MutexUnlock(&joinMutex);  	return;      } -    /* Switch over the exclusive access from the list to the structure, -     * then store the result, set the flag and notify the waiting thread, -     * provided that it exists. The order of lock/unlock ensures that a -     * thread entering 'TclJoinThread' will not interfere with us. +    /* +     * Switch over the exclusive access from the list to the structure, then +     * store the result, set the flag and notify the waiting thread, provided +     * that it exists. The order of lock/unlock ensures that a thread entering +     * 'TclJoinThread' will not interfere with us.       */ -    Tcl_MutexLock   (&threadPtr->threadMutex); -    Tcl_MutexUnlock (&joinMutex); +    Tcl_MutexLock(&threadPtr->threadMutex); +    Tcl_MutexUnlock(&joinMutex); -    threadPtr->done   = 1; +    threadPtr->done = 1;      threadPtr->result = result;      if (threadPtr->waitedUpon) { -      Tcl_ConditionNotify (&threadPtr->cond); +	Tcl_ConditionNotify(&threadPtr->cond);      } -    Tcl_MutexUnlock (&threadPtr->threadMutex); +    Tcl_MutexUnlock(&threadPtr->threadMutex);  } - -#endif /* WIN32 || MAC_TCL */ +#endif /* _WIN32 */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ | 
