2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: tclAsync.c /main/2 1996/08/08 14:42:49 cde-hp $ */
27 * This file provides low-level support needed to invoke signal
28 * handlers in a safe way. The code here doesn't actually handle
29 * signals, though. This code is based on proposals made by
30 * Mark Diekhans and Don Libes.
32 * Copyright (c) 1993 The Regents of the University of California.
33 * Copyright (c) 1994 Sun Microsystems, Inc.
35 * See the file "license.terms" for information on usage and redistribution
36 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
38 * SCCS: @(#) tclAsync.c 1.6 96/02/15 11:46:15
44 * One of the following structures exists for each asynchronous
48 typedef struct AsyncHandler {
49 int ready; /* Non-zero means this handler should
50 * be invoked in the next call to
52 struct AsyncHandler *nextPtr; /* Next in list of all handlers for
54 Tcl_AsyncProc *proc; /* Procedure to call when handler
56 ClientData clientData; /* Value to pass to handler when it
61 * The variables below maintain a list of all existing handlers.
64 static AsyncHandler *firstHandler; /* First handler defined for process,
66 static AsyncHandler *lastHandler; /* Last handler or NULL. */
69 * The variable below is set to 1 whenever a handler becomes ready and
70 * it is cleared to zero whenever Tcl_AsyncInvoke is called. It can be
71 * checked elsewhere in the application by calling Tcl_AsyncReady to see
72 * if Tcl_AsyncInvoke should be invoked.
75 static int asyncReady = 0;
78 * The variable below indicates whether Tcl_AsyncInvoke is currently
79 * working. If so then we won't set asyncReady again until
80 * Tcl_AsyncInvoke returns.
83 static int asyncActive = 0;
86 *----------------------------------------------------------------------
90 * This procedure creates the data structures for an asynchronous
91 * handler, so that no memory has to be allocated when the handler
95 * The return value is a token for the handler, which can be used
96 * to activate it later on.
99 * Information about the handler is recorded.
101 *----------------------------------------------------------------------
105 Tcl_AsyncCreate(proc, clientData)
106 Tcl_AsyncProc *proc; /* Procedure to call when handler
108 ClientData clientData; /* Argument to pass to handler. */
110 AsyncHandler *asyncPtr;
112 asyncPtr = (AsyncHandler *) ckalloc(sizeof(AsyncHandler));
114 asyncPtr->nextPtr = NULL;
115 asyncPtr->proc = proc;
116 asyncPtr->clientData = clientData;
117 if (firstHandler == NULL) {
118 firstHandler = asyncPtr;
120 lastHandler->nextPtr = asyncPtr;
122 lastHandler = asyncPtr;
123 return (Tcl_AsyncHandler) asyncPtr;
127 *----------------------------------------------------------------------
131 * This procedure is called to request that an asynchronous handler
132 * be invoked as soon as possible. It's typically called from
133 * an interrupt handler, where it isn't safe to do anything that
134 * depends on or modifies application state.
140 * The handler gets marked for invocation later.
142 *----------------------------------------------------------------------
147 Tcl_AsyncHandler async; /* Token for handler. */
149 ((AsyncHandler *) async)->ready = 1;
156 *----------------------------------------------------------------------
160 * This procedure is called at a "safe" time at background level
161 * to invoke any active asynchronous handlers.
164 * The return value is a normal Tcl result, which is intended to
165 * replace the code argument as the current completion code for
169 * Depends on the handlers that are active.
171 *----------------------------------------------------------------------
175 Tcl_AsyncInvoke(interp, code)
176 Tcl_Interp *interp; /* If invoked from Tcl_Eval just after
177 * completing a command, points to
178 * interpreter. Otherwise it is
180 int code; /* If interp is non-NULL, this gives
181 * completion code from command that
184 AsyncHandler *asyncPtr;
186 if (asyncReady == 0) {
191 if (interp == NULL) {
196 * Make one or more passes over the list of handlers, invoking
197 * at most one handler in each pass. After invoking a handler,
198 * go back to the start of the list again so that (a) if a new
199 * higher-priority handler gets marked while executing a lower
200 * priority handler, we execute the higher-priority handler
201 * next, and (b) if a handler gets deleted during the execution
202 * of a handler, then the list structure may change so it isn't
203 * safe to continue down the list anyway.
207 for (asyncPtr = firstHandler; asyncPtr != NULL;
208 asyncPtr = asyncPtr->nextPtr) {
209 if (asyncPtr->ready) {
213 if (asyncPtr == NULL) {
217 code = (*asyncPtr->proc)(asyncPtr->clientData, interp, code);
224 *----------------------------------------------------------------------
228 * Frees up all the state for an asynchronous handler. The handler
229 * should never be used again.
235 * The state associated with the handler is deleted.
237 *----------------------------------------------------------------------
241 Tcl_AsyncDelete(async)
242 Tcl_AsyncHandler async; /* Token for handler to delete. */
244 AsyncHandler *asyncPtr = (AsyncHandler *) async;
245 AsyncHandler *prevPtr;
247 if (firstHandler == asyncPtr) {
248 firstHandler = asyncPtr->nextPtr;
249 if (firstHandler == NULL) {
253 prevPtr = firstHandler;
254 while (prevPtr->nextPtr != asyncPtr) {
255 prevPtr = prevPtr->nextPtr;
257 prevPtr->nextPtr = asyncPtr->nextPtr;
258 if (lastHandler == asyncPtr) {
259 lastHandler = prevPtr;
262 ckfree((char *) asyncPtr);
266 *----------------------------------------------------------------------
270 * This procedure can be used to tell whether Tcl_AsyncInvoke
271 * needs to be called. This procedure is the external interface
272 * for checking the internal asyncReady variable.
275 * The return value is 1 whenever a handler is ready and is 0
276 * when no handlers are ready.
281 *----------------------------------------------------------------------