os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclAsync.c
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclAsync.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,349 @@
1.4 +/*
1.5 + * tclAsync.c --
1.6 + *
1.7 + * This file provides low-level support needed to invoke signal
1.8 + * handlers in a safe way. The code here doesn't actually handle
1.9 + * signals, though. This code is based on proposals made by
1.10 + * Mark Diekhans and Don Libes.
1.11 + *
1.12 + * Copyright (c) 1993 The Regents of the University of California.
1.13 + * Copyright (c) 1994 Sun Microsystems, Inc.
1.14 + * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.
1.15 + *
1.16 + * See the file "license.terms" for information on usage and redistribution
1.17 + * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
1.18 + *
1.19 + * RCS: @(#) $Id: tclAsync.c,v 1.6.12.1 2006/07/11 13:18:10 vasiljevic Exp $
1.20 + */
1.21 +
1.22 +#include "tclInt.h"
1.23 +#include "tclPort.h"
1.24 +#if defined(__SYMBIAN32__) && defined(__WINSCW__)
1.25 +#include "tclSymbianGlobals.h"
1.26 +#define dataKey getdataKey(1)
1.27 +#endif
1.28 +
1.29 +/* Forward declaration */
1.30 +struct ThreadSpecificData;
1.31 +
1.32 +/*
1.33 + * One of the following structures exists for each asynchronous
1.34 + * handler:
1.35 + */
1.36 +
1.37 +typedef struct AsyncHandler {
1.38 + int ready; /* Non-zero means this handler should
1.39 + * be invoked in the next call to
1.40 + * Tcl_AsyncInvoke. */
1.41 + struct AsyncHandler *nextPtr; /* Next in list of all handlers for
1.42 + * the process. */
1.43 + Tcl_AsyncProc *proc; /* Procedure to call when handler
1.44 + * is invoked. */
1.45 + ClientData clientData; /* Value to pass to handler when it
1.46 + * is invoked. */
1.47 + struct ThreadSpecificData *originTsd;
1.48 + /* Used in Tcl_AsyncMark to modify thread-
1.49 + * specific data from outside the thread
1.50 + * it is associated to. */
1.51 + Tcl_ThreadId originThrdId; /* Origin thread where this token was
1.52 + * created and where it will be
1.53 + * yielded. */
1.54 +} AsyncHandler;
1.55 +
1.56 +
1.57 +typedef struct ThreadSpecificData {
1.58 + /*
1.59 + * The variables below maintain a list of all existing handlers
1.60 + * specific to the calling thread.
1.61 + */
1.62 + AsyncHandler *firstHandler; /* First handler defined for process,
1.63 + * or NULL if none. */
1.64 + AsyncHandler *lastHandler; /* Last handler or NULL. */
1.65 +
1.66 + /*
1.67 + * The variable below is set to 1 whenever a handler becomes ready and
1.68 + * it is cleared to zero whenever Tcl_AsyncInvoke is called. It can be
1.69 + * checked elsewhere in the application by calling Tcl_AsyncReady to see
1.70 + * if Tcl_AsyncInvoke should be invoked.
1.71 + */
1.72 +
1.73 + int asyncReady;
1.74 +
1.75 + /*
1.76 + * The variable below indicates whether Tcl_AsyncInvoke is currently
1.77 + * working. If so then we won't set asyncReady again until
1.78 + * Tcl_AsyncInvoke returns.
1.79 + */
1.80 +
1.81 + int asyncActive;
1.82 +
1.83 + Tcl_Mutex asyncMutex; /* Thread-specific AsyncHandler linked-list lock */
1.84 +
1.85 +} ThreadSpecificData;
1.86 +#if !defined(__SYMBIAN32__) || !defined(__WINSCW__)
1.87 +static Tcl_ThreadDataKey dataKey;
1.88 +#endif
1.89 +
1.90 +
1.91 +/*
1.92 + *----------------------------------------------------------------------
1.93 + *
1.94 + * TclFinalizeAsync --
1.95 + *
1.96 + * Finalizes the mutex in the thread local data structure for the
1.97 + * async subsystem.
1.98 + *
1.99 + * Results:
1.100 + * None.
1.101 + *
1.102 + * Side effects:
1.103 + * Forgets knowledge of the mutex should it have been created.
1.104 + *
1.105 + *----------------------------------------------------------------------
1.106 + */
1.107 +
1.108 +void
1.109 +TclFinalizeAsync()
1.110 +{
1.111 + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
1.112 +
1.113 + if (tsdPtr->asyncMutex != NULL) {
1.114 + Tcl_MutexFinalize(&tsdPtr->asyncMutex);
1.115 + }
1.116 +}
1.117 +
1.118 +/*
1.119 + *----------------------------------------------------------------------
1.120 + *
1.121 + * Tcl_AsyncCreate --
1.122 + *
1.123 + * This procedure creates the data structures for an asynchronous
1.124 + * handler, so that no memory has to be allocated when the handler
1.125 + * is activated.
1.126 + *
1.127 + * Results:
1.128 + * The return value is a token for the handler, which can be used
1.129 + * to activate it later on.
1.130 + *
1.131 + * Side effects:
1.132 + * Information about the handler is recorded.
1.133 + *
1.134 + *----------------------------------------------------------------------
1.135 + */
1.136 +
1.137 +EXPORT_C Tcl_AsyncHandler
1.138 +Tcl_AsyncCreate(proc, clientData)
1.139 + Tcl_AsyncProc *proc; /* Procedure to call when handler
1.140 + * is invoked. */
1.141 + ClientData clientData; /* Argument to pass to handler. */
1.142 +{
1.143 + AsyncHandler *asyncPtr;
1.144 + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
1.145 +
1.146 + asyncPtr = (AsyncHandler *) ckalloc(sizeof(AsyncHandler));
1.147 + asyncPtr->ready = 0;
1.148 + asyncPtr->nextPtr = NULL;
1.149 + asyncPtr->proc = proc;
1.150 + asyncPtr->clientData = clientData;
1.151 + asyncPtr->originTsd = tsdPtr;
1.152 + asyncPtr->originThrdId = Tcl_GetCurrentThread();
1.153 +
1.154 + Tcl_MutexLock(&tsdPtr->asyncMutex);
1.155 + if (tsdPtr->firstHandler == NULL) {
1.156 + tsdPtr->firstHandler = asyncPtr;
1.157 + } else {
1.158 + tsdPtr->lastHandler->nextPtr = asyncPtr;
1.159 + }
1.160 + tsdPtr->lastHandler = asyncPtr;
1.161 + Tcl_MutexUnlock(&tsdPtr->asyncMutex);
1.162 + return (Tcl_AsyncHandler) asyncPtr;
1.163 +}
1.164 +
1.165 +/*
1.166 + *----------------------------------------------------------------------
1.167 + *
1.168 + * Tcl_AsyncMark --
1.169 + *
1.170 + * This procedure is called to request that an asynchronous handler
1.171 + * be invoked as soon as possible. It's typically called from
1.172 + * an interrupt handler, where it isn't safe to do anything that
1.173 + * depends on or modifies application state.
1.174 + *
1.175 + * Results:
1.176 + * None.
1.177 + *
1.178 + * Side effects:
1.179 + * The handler gets marked for invocation later.
1.180 + *
1.181 + *----------------------------------------------------------------------
1.182 + */
1.183 +
1.184 +EXPORT_C void
1.185 +Tcl_AsyncMark(async)
1.186 + Tcl_AsyncHandler async; /* Token for handler. */
1.187 +{
1.188 + AsyncHandler *token = (AsyncHandler *) async;
1.189 +
1.190 + Tcl_MutexLock(&token->originTsd->asyncMutex);
1.191 + token->ready = 1;
1.192 + if (!token->originTsd->asyncActive) {
1.193 + token->originTsd->asyncReady = 1;
1.194 + Tcl_ThreadAlert(token->originThrdId);
1.195 + }
1.196 + Tcl_MutexUnlock(&token->originTsd->asyncMutex);
1.197 +}
1.198 +
1.199 +/*
1.200 + *----------------------------------------------------------------------
1.201 + *
1.202 + * Tcl_AsyncInvoke --
1.203 + *
1.204 + * This procedure is called at a "safe" time at background level
1.205 + * to invoke any active asynchronous handlers.
1.206 + *
1.207 + * Results:
1.208 + * The return value is a normal Tcl result, which is intended to
1.209 + * replace the code argument as the current completion code for
1.210 + * interp.
1.211 + *
1.212 + * Side effects:
1.213 + * Depends on the handlers that are active.
1.214 + *
1.215 + *----------------------------------------------------------------------
1.216 + */
1.217 +
1.218 +EXPORT_C int
1.219 +Tcl_AsyncInvoke(interp, code)
1.220 + Tcl_Interp *interp; /* If invoked from Tcl_Eval just after
1.221 + * completing a command, points to
1.222 + * interpreter. Otherwise it is
1.223 + * NULL. */
1.224 + int code; /* If interp is non-NULL, this gives
1.225 + * completion code from command that
1.226 + * just completed. */
1.227 +{
1.228 + AsyncHandler *asyncPtr;
1.229 + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
1.230 +
1.231 + Tcl_MutexLock(&tsdPtr->asyncMutex);
1.232 +
1.233 + if (tsdPtr->asyncReady == 0) {
1.234 + Tcl_MutexUnlock(&tsdPtr->asyncMutex);
1.235 + return code;
1.236 + }
1.237 + tsdPtr->asyncReady = 0;
1.238 + tsdPtr->asyncActive = 1;
1.239 + if (interp == NULL) {
1.240 + code = 0;
1.241 + }
1.242 +
1.243 + /*
1.244 + * Make one or more passes over the list of handlers, invoking
1.245 + * at most one handler in each pass. After invoking a handler,
1.246 + * go back to the start of the list again so that (a) if a new
1.247 + * higher-priority handler gets marked while executing a lower
1.248 + * priority handler, we execute the higher-priority handler
1.249 + * next, and (b) if a handler gets deleted during the execution
1.250 + * of a handler, then the list structure may change so it isn't
1.251 + * safe to continue down the list anyway.
1.252 + */
1.253 +
1.254 + while (1) {
1.255 + for (asyncPtr = tsdPtr->firstHandler; asyncPtr != NULL;
1.256 + asyncPtr = asyncPtr->nextPtr) {
1.257 + if (asyncPtr->ready) {
1.258 + break;
1.259 + }
1.260 + }
1.261 + if (asyncPtr == NULL) {
1.262 + break;
1.263 + }
1.264 + asyncPtr->ready = 0;
1.265 + Tcl_MutexUnlock(&tsdPtr->asyncMutex);
1.266 + code = (*asyncPtr->proc)(asyncPtr->clientData, interp, code);
1.267 + Tcl_MutexLock(&tsdPtr->asyncMutex);
1.268 + }
1.269 + tsdPtr->asyncActive = 0;
1.270 + Tcl_MutexUnlock(&tsdPtr->asyncMutex);
1.271 + return code;
1.272 +}
1.273 +
1.274 +/*
1.275 + *----------------------------------------------------------------------
1.276 + *
1.277 + * Tcl_AsyncDelete --
1.278 + *
1.279 + * Frees up all the state for an asynchronous handler. The handler
1.280 + * should never be used again.
1.281 + *
1.282 + * Results:
1.283 + * None.
1.284 + *
1.285 + * Side effects:
1.286 + * The state associated with the handler is deleted.
1.287 + *
1.288 + *----------------------------------------------------------------------
1.289 + */
1.290 +
1.291 +EXPORT_C void
1.292 +Tcl_AsyncDelete(async)
1.293 + Tcl_AsyncHandler async; /* Token for handler to delete. */
1.294 +{
1.295 + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
1.296 + AsyncHandler *asyncPtr = (AsyncHandler *) async;
1.297 + AsyncHandler *prevPtr;
1.298 +
1.299 + /*
1.300 + * Conservatively check the existence of the linked list of
1.301 + * registered handlers, as we may come at this point even
1.302 + * when the TSD's for the current thread have been already
1.303 + * garbage-collected.
1.304 + */
1.305 +
1.306 + Tcl_MutexLock(&tsdPtr->asyncMutex);
1.307 + if (tsdPtr->firstHandler != NULL ) {
1.308 + if (tsdPtr->firstHandler == asyncPtr) {
1.309 + tsdPtr->firstHandler = asyncPtr->nextPtr;
1.310 + if (tsdPtr->firstHandler == NULL) {
1.311 + tsdPtr->lastHandler = NULL;
1.312 + }
1.313 + } else {
1.314 + prevPtr = tsdPtr->firstHandler;
1.315 + while (prevPtr->nextPtr != asyncPtr) {
1.316 + prevPtr = prevPtr->nextPtr;
1.317 + }
1.318 + prevPtr->nextPtr = asyncPtr->nextPtr;
1.319 + if (tsdPtr->lastHandler == asyncPtr) {
1.320 + tsdPtr->lastHandler = prevPtr;
1.321 + }
1.322 + }
1.323 + }
1.324 + Tcl_MutexUnlock(&tsdPtr->asyncMutex);
1.325 + ckfree((char *) asyncPtr);
1.326 +}
1.327 +
1.328 +/*
1.329 + *----------------------------------------------------------------------
1.330 + *
1.331 + * Tcl_AsyncReady --
1.332 + *
1.333 + * This procedure can be used to tell whether Tcl_AsyncInvoke
1.334 + * needs to be called. This procedure is the external interface
1.335 + * for checking the thread-specific asyncReady variable.
1.336 + *
1.337 + * Results:
1.338 + * The return value is 1 whenever a handler is ready and is 0
1.339 + * when no handlers are ready.
1.340 + *
1.341 + * Side effects:
1.342 + * None.
1.343 + *
1.344 + *----------------------------------------------------------------------
1.345 + */
1.346 +
1.347 +EXPORT_C int
1.348 +Tcl_AsyncReady()
1.349 +{
1.350 + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
1.351 + return tsdPtr->asyncReady;
1.352 +}