os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclAsync.c
changeset 0 bde4ae8d615e
     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 +}