os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclAsync.c
First public contribution.
4 * This file provides low-level support needed to invoke signal
5 * handlers in a safe way. The code here doesn't actually handle
6 * signals, though. This code is based on proposals made by
7 * Mark Diekhans and Don Libes.
9 * Copyright (c) 1993 The Regents of the University of California.
10 * Copyright (c) 1994 Sun Microsystems, Inc.
11 * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.
13 * See the file "license.terms" for information on usage and redistribution
14 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16 * RCS: @(#) $Id: tclAsync.c,v 1.6.12.1 2006/07/11 13:18:10 vasiljevic Exp $
21 #if defined(__SYMBIAN32__) && defined(__WINSCW__)
22 #include "tclSymbianGlobals.h"
23 #define dataKey getdataKey(1)
26 /* Forward declaration */
27 struct ThreadSpecificData;
30 * One of the following structures exists for each asynchronous
34 typedef struct AsyncHandler {
35 int ready; /* Non-zero means this handler should
36 * be invoked in the next call to
38 struct AsyncHandler *nextPtr; /* Next in list of all handlers for
40 Tcl_AsyncProc *proc; /* Procedure to call when handler
42 ClientData clientData; /* Value to pass to handler when it
44 struct ThreadSpecificData *originTsd;
45 /* Used in Tcl_AsyncMark to modify thread-
46 * specific data from outside the thread
47 * it is associated to. */
48 Tcl_ThreadId originThrdId; /* Origin thread where this token was
49 * created and where it will be
54 typedef struct ThreadSpecificData {
56 * The variables below maintain a list of all existing handlers
57 * specific to the calling thread.
59 AsyncHandler *firstHandler; /* First handler defined for process,
61 AsyncHandler *lastHandler; /* Last handler or NULL. */
64 * The variable below is set to 1 whenever a handler becomes ready and
65 * it is cleared to zero whenever Tcl_AsyncInvoke is called. It can be
66 * checked elsewhere in the application by calling Tcl_AsyncReady to see
67 * if Tcl_AsyncInvoke should be invoked.
73 * The variable below indicates whether Tcl_AsyncInvoke is currently
74 * working. If so then we won't set asyncReady again until
75 * Tcl_AsyncInvoke returns.
80 Tcl_Mutex asyncMutex; /* Thread-specific AsyncHandler linked-list lock */
83 #if !defined(__SYMBIAN32__) || !defined(__WINSCW__)
84 static Tcl_ThreadDataKey dataKey;
89 *----------------------------------------------------------------------
93 * Finalizes the mutex in the thread local data structure for the
100 * Forgets knowledge of the mutex should it have been created.
102 *----------------------------------------------------------------------
108 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
110 if (tsdPtr->asyncMutex != NULL) {
111 Tcl_MutexFinalize(&tsdPtr->asyncMutex);
116 *----------------------------------------------------------------------
120 * This procedure creates the data structures for an asynchronous
121 * handler, so that no memory has to be allocated when the handler
125 * The return value is a token for the handler, which can be used
126 * to activate it later on.
129 * Information about the handler is recorded.
131 *----------------------------------------------------------------------
134 EXPORT_C Tcl_AsyncHandler
135 Tcl_AsyncCreate(proc, clientData)
136 Tcl_AsyncProc *proc; /* Procedure to call when handler
138 ClientData clientData; /* Argument to pass to handler. */
140 AsyncHandler *asyncPtr;
141 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
143 asyncPtr = (AsyncHandler *) ckalloc(sizeof(AsyncHandler));
145 asyncPtr->nextPtr = NULL;
146 asyncPtr->proc = proc;
147 asyncPtr->clientData = clientData;
148 asyncPtr->originTsd = tsdPtr;
149 asyncPtr->originThrdId = Tcl_GetCurrentThread();
151 Tcl_MutexLock(&tsdPtr->asyncMutex);
152 if (tsdPtr->firstHandler == NULL) {
153 tsdPtr->firstHandler = asyncPtr;
155 tsdPtr->lastHandler->nextPtr = asyncPtr;
157 tsdPtr->lastHandler = asyncPtr;
158 Tcl_MutexUnlock(&tsdPtr->asyncMutex);
159 return (Tcl_AsyncHandler) asyncPtr;
163 *----------------------------------------------------------------------
167 * This procedure is called to request that an asynchronous handler
168 * be invoked as soon as possible. It's typically called from
169 * an interrupt handler, where it isn't safe to do anything that
170 * depends on or modifies application state.
176 * The handler gets marked for invocation later.
178 *----------------------------------------------------------------------
183 Tcl_AsyncHandler async; /* Token for handler. */
185 AsyncHandler *token = (AsyncHandler *) async;
187 Tcl_MutexLock(&token->originTsd->asyncMutex);
189 if (!token->originTsd->asyncActive) {
190 token->originTsd->asyncReady = 1;
191 Tcl_ThreadAlert(token->originThrdId);
193 Tcl_MutexUnlock(&token->originTsd->asyncMutex);
197 *----------------------------------------------------------------------
201 * This procedure is called at a "safe" time at background level
202 * to invoke any active asynchronous handlers.
205 * The return value is a normal Tcl result, which is intended to
206 * replace the code argument as the current completion code for
210 * Depends on the handlers that are active.
212 *----------------------------------------------------------------------
216 Tcl_AsyncInvoke(interp, code)
217 Tcl_Interp *interp; /* If invoked from Tcl_Eval just after
218 * completing a command, points to
219 * interpreter. Otherwise it is
221 int code; /* If interp is non-NULL, this gives
222 * completion code from command that
225 AsyncHandler *asyncPtr;
226 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
228 Tcl_MutexLock(&tsdPtr->asyncMutex);
230 if (tsdPtr->asyncReady == 0) {
231 Tcl_MutexUnlock(&tsdPtr->asyncMutex);
234 tsdPtr->asyncReady = 0;
235 tsdPtr->asyncActive = 1;
236 if (interp == NULL) {
241 * Make one or more passes over the list of handlers, invoking
242 * at most one handler in each pass. After invoking a handler,
243 * go back to the start of the list again so that (a) if a new
244 * higher-priority handler gets marked while executing a lower
245 * priority handler, we execute the higher-priority handler
246 * next, and (b) if a handler gets deleted during the execution
247 * of a handler, then the list structure may change so it isn't
248 * safe to continue down the list anyway.
252 for (asyncPtr = tsdPtr->firstHandler; asyncPtr != NULL;
253 asyncPtr = asyncPtr->nextPtr) {
254 if (asyncPtr->ready) {
258 if (asyncPtr == NULL) {
262 Tcl_MutexUnlock(&tsdPtr->asyncMutex);
263 code = (*asyncPtr->proc)(asyncPtr->clientData, interp, code);
264 Tcl_MutexLock(&tsdPtr->asyncMutex);
266 tsdPtr->asyncActive = 0;
267 Tcl_MutexUnlock(&tsdPtr->asyncMutex);
272 *----------------------------------------------------------------------
276 * Frees up all the state for an asynchronous handler. The handler
277 * should never be used again.
283 * The state associated with the handler is deleted.
285 *----------------------------------------------------------------------
289 Tcl_AsyncDelete(async)
290 Tcl_AsyncHandler async; /* Token for handler to delete. */
292 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
293 AsyncHandler *asyncPtr = (AsyncHandler *) async;
294 AsyncHandler *prevPtr;
297 * Conservatively check the existence of the linked list of
298 * registered handlers, as we may come at this point even
299 * when the TSD's for the current thread have been already
303 Tcl_MutexLock(&tsdPtr->asyncMutex);
304 if (tsdPtr->firstHandler != NULL ) {
305 if (tsdPtr->firstHandler == asyncPtr) {
306 tsdPtr->firstHandler = asyncPtr->nextPtr;
307 if (tsdPtr->firstHandler == NULL) {
308 tsdPtr->lastHandler = NULL;
311 prevPtr = tsdPtr->firstHandler;
312 while (prevPtr->nextPtr != asyncPtr) {
313 prevPtr = prevPtr->nextPtr;
315 prevPtr->nextPtr = asyncPtr->nextPtr;
316 if (tsdPtr->lastHandler == asyncPtr) {
317 tsdPtr->lastHandler = prevPtr;
321 Tcl_MutexUnlock(&tsdPtr->asyncMutex);
322 ckfree((char *) asyncPtr);
326 *----------------------------------------------------------------------
330 * This procedure can be used to tell whether Tcl_AsyncInvoke
331 * needs to be called. This procedure is the external interface
332 * for checking the thread-specific asyncReady variable.
335 * The return value is 1 whenever a handler is ready and is 0
336 * when no handlers are ready.
341 *----------------------------------------------------------------------
347 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
348 return tsdPtr->asyncReady;