/[dtapublic]/projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tclasync.c
ViewVC logotype

Contents of /projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tclasync.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 71 - (show annotations) (download)
Sat Nov 5 11:07:06 2016 UTC (7 years, 4 months ago) by dashley
File MIME type: text/plain
File size: 7493 byte(s)
Set EOL properties appropriately to facilitate simultaneous Linux and Windows development.
1 /* $Header$ */
2 /*
3 * tclAsync.c --
4 *
5 * This file provides low-level support needed to invoke signal
6 * handlers in a safe way. The code here doesn't actually handle
7 * signals, though. This code is based on proposals made by
8 * Mark Diekhans and Don Libes.
9 *
10 * Copyright (c) 1993 The Regents of the University of California.
11 * Copyright (c) 1994 Sun Microsystems, Inc.
12 *
13 * See the file "license.terms" for information on usage and redistribution
14 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15 *
16 * RCS: @(#) $Id: tclasync.c,v 1.1.1.1 2001/06/13 04:33:03 dtashley Exp $
17 */
18
19 #include "tclInt.h"
20 #include "tclPort.h"
21
22 /*
23 * One of the following structures exists for each asynchronous
24 * handler:
25 */
26
27 typedef struct AsyncHandler {
28 int ready; /* Non-zero means this handler should
29 * be invoked in the next call to
30 * Tcl_AsyncInvoke. */
31 struct AsyncHandler *nextPtr; /* Next in list of all handlers for
32 * the process. */
33 Tcl_AsyncProc *proc; /* Procedure to call when handler
34 * is invoked. */
35 ClientData clientData; /* Value to pass to handler when it
36 * is invoked. */
37 } AsyncHandler;
38
39 /*
40 * The variables below maintain a list of all existing handlers.
41 */
42
43 static AsyncHandler *firstHandler; /* First handler defined for process,
44 * or NULL if none. */
45 static AsyncHandler *lastHandler; /* Last handler or NULL. */
46
47 TCL_DECLARE_MUTEX(asyncMutex) /* Process-wide async handler lock */
48
49 /*
50 * The variable below is set to 1 whenever a handler becomes ready and
51 * it is cleared to zero whenever Tcl_AsyncInvoke is called. It can be
52 * checked elsewhere in the application by calling Tcl_AsyncReady to see
53 * if Tcl_AsyncInvoke should be invoked.
54 */
55
56 static int asyncReady = 0;
57
58 /*
59 * The variable below indicates whether Tcl_AsyncInvoke is currently
60 * working. If so then we won't set asyncReady again until
61 * Tcl_AsyncInvoke returns.
62 */
63
64 static int asyncActive = 0;
65
66 /*
67 *----------------------------------------------------------------------
68 *
69 * Tcl_AsyncCreate --
70 *
71 * This procedure creates the data structures for an asynchronous
72 * handler, so that no memory has to be allocated when the handler
73 * is activated.
74 *
75 * Results:
76 * The return value is a token for the handler, which can be used
77 * to activate it later on.
78 *
79 * Side effects:
80 * Information about the handler is recorded.
81 *
82 *----------------------------------------------------------------------
83 */
84
85 Tcl_AsyncHandler
86 Tcl_AsyncCreate(proc, clientData)
87 Tcl_AsyncProc *proc; /* Procedure to call when handler
88 * is invoked. */
89 ClientData clientData; /* Argument to pass to handler. */
90 {
91 AsyncHandler *asyncPtr;
92
93 asyncPtr = (AsyncHandler *) ckalloc(sizeof(AsyncHandler));
94 asyncPtr->ready = 0;
95 asyncPtr->nextPtr = NULL;
96 asyncPtr->proc = proc;
97 asyncPtr->clientData = clientData;
98 Tcl_MutexLock(&asyncMutex);
99 if (firstHandler == NULL) {
100 firstHandler = asyncPtr;
101 } else {
102 lastHandler->nextPtr = asyncPtr;
103 }
104 lastHandler = asyncPtr;
105 Tcl_MutexUnlock(&asyncMutex);
106 return (Tcl_AsyncHandler) asyncPtr;
107 }
108
109 /*
110 *----------------------------------------------------------------------
111 *
112 * Tcl_AsyncMark --
113 *
114 * This procedure is called to request that an asynchronous handler
115 * be invoked as soon as possible. It's typically called from
116 * an interrupt handler, where it isn't safe to do anything that
117 * depends on or modifies application state.
118 *
119 * Results:
120 * None.
121 *
122 * Side effects:
123 * The handler gets marked for invocation later.
124 *
125 *----------------------------------------------------------------------
126 */
127
128 void
129 Tcl_AsyncMark(async)
130 Tcl_AsyncHandler async; /* Token for handler. */
131 {
132 Tcl_MutexLock(&asyncMutex);
133 ((AsyncHandler *) async)->ready = 1;
134 if (!asyncActive) {
135 asyncReady = 1;
136 TclpAsyncMark(async);
137 }
138 Tcl_MutexUnlock(&asyncMutex);
139 }
140
141 /*
142 *----------------------------------------------------------------------
143 *
144 * Tcl_AsyncInvoke --
145 *
146 * This procedure is called at a "safe" time at background level
147 * to invoke any active asynchronous handlers.
148 *
149 * Results:
150 * The return value is a normal Tcl result, which is intended to
151 * replace the code argument as the current completion code for
152 * interp.
153 *
154 * Side effects:
155 * Depends on the handlers that are active.
156 *
157 *----------------------------------------------------------------------
158 */
159
160 int
161 Tcl_AsyncInvoke(interp, code)
162 Tcl_Interp *interp; /* If invoked from Tcl_Eval just after
163 * completing a command, points to
164 * interpreter. Otherwise it is
165 * NULL. */
166 int code; /* If interp is non-NULL, this gives
167 * completion code from command that
168 * just completed. */
169 {
170 AsyncHandler *asyncPtr;
171 Tcl_MutexLock(&asyncMutex);
172
173 if (asyncReady == 0) {
174 Tcl_MutexUnlock(&asyncMutex);
175 return code;
176 }
177 asyncReady = 0;
178 asyncActive = 1;
179 if (interp == NULL) {
180 code = 0;
181 }
182
183 /*
184 * Make one or more passes over the list of handlers, invoking
185 * at most one handler in each pass. After invoking a handler,
186 * go back to the start of the list again so that (a) if a new
187 * higher-priority handler gets marked while executing a lower
188 * priority handler, we execute the higher-priority handler
189 * next, and (b) if a handler gets deleted during the execution
190 * of a handler, then the list structure may change so it isn't
191 * safe to continue down the list anyway.
192 */
193
194 while (1) {
195 for (asyncPtr = firstHandler; asyncPtr != NULL;
196 asyncPtr = asyncPtr->nextPtr) {
197 if (asyncPtr->ready) {
198 break;
199 }
200 }
201 if (asyncPtr == NULL) {
202 break;
203 }
204 asyncPtr->ready = 0;
205 Tcl_MutexUnlock(&asyncMutex);
206 code = (*asyncPtr->proc)(asyncPtr->clientData, interp, code);
207 Tcl_MutexLock(&asyncMutex);
208 }
209 asyncActive = 0;
210 Tcl_MutexUnlock(&asyncMutex);
211 return code;
212 }
213
214 /*
215 *----------------------------------------------------------------------
216 *
217 * Tcl_AsyncDelete --
218 *
219 * Frees up all the state for an asynchronous handler. The handler
220 * should never be used again.
221 *
222 * Results:
223 * None.
224 *
225 * Side effects:
226 * The state associated with the handler is deleted.
227 *
228 *----------------------------------------------------------------------
229 */
230
231 void
232 Tcl_AsyncDelete(async)
233 Tcl_AsyncHandler async; /* Token for handler to delete. */
234 {
235 AsyncHandler *asyncPtr = (AsyncHandler *) async;
236 AsyncHandler *prevPtr;
237
238 Tcl_MutexLock(&asyncMutex);
239 if (firstHandler == asyncPtr) {
240 firstHandler = asyncPtr->nextPtr;
241 if (firstHandler == NULL) {
242 lastHandler = NULL;
243 }
244 } else {
245 prevPtr = firstHandler;
246 while (prevPtr->nextPtr != asyncPtr) {
247 prevPtr = prevPtr->nextPtr;
248 }
249 prevPtr->nextPtr = asyncPtr->nextPtr;
250 if (lastHandler == asyncPtr) {
251 lastHandler = prevPtr;
252 }
253 }
254 Tcl_MutexUnlock(&asyncMutex);
255 ckfree((char *) asyncPtr);
256 }
257
258 /*
259 *----------------------------------------------------------------------
260 *
261 * Tcl_AsyncReady --
262 *
263 * This procedure can be used to tell whether Tcl_AsyncInvoke
264 * needs to be called. This procedure is the external interface
265 * for checking the internal asyncReady variable.
266 *
267 * Results:
268 * The return value is 1 whenever a handler is ready and is 0
269 * when no handlers are ready.
270 *
271 * Side effects:
272 * None.
273 *
274 *----------------------------------------------------------------------
275 */
276
277 int
278 Tcl_AsyncReady()
279 {
280 return asyncReady;
281 }
282
283 /* End of tclasync.c */

Properties

Name Value
svn:eol-style native
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25