OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tcl/] [generic/] [tclAsync.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.