~ubuntu-branches/ubuntu/hardy/uim/hardy

« back to all changes in this revision

Viewing changes to sigscheme/src/continuation.c

  • Committer: Bazaar Package Importer
  • Author(s): Masahito Omote
  • Date: 2007-04-21 03:46:09 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20070421034609-gpcurkutp8vaysqj
Tags: 1:1.4.1-3
* Switch to dh_gtkmodules for the gtk 2.10 transition (Closes:
  #419318)
  - debian/control: Add ${misc:Depends} and remove libgtk2.0-bin on
    uim-gtk2.0.
  - debian/uim-gtk2.0.post{inst,rm}: Removed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*===========================================================================
 
2
 *  Filename : continuation.c
 
3
 *  About    : A Continuation implementation with setjmp/longjmp
 
4
 *
 
5
 *  Copyright (C) 2005      Kazuki Ohta <mover AT hct.zaq.ne.jp>
 
6
 *  Copyright (C) 2005-2006 Jun Inoue <jun.lambda AT gmail.com>
 
7
 *  Copyright (C) 2005-2006 YAMAMOTO Kengo <yamaken AT bp.iij4u.or.jp>
 
8
 *  Copyright (c) 2007 SigScheme Project <uim AT freedesktop.org>
 
9
 *
 
10
 *  All rights reserved.
 
11
 *
 
12
 *  Redistribution and use in source and binary forms, with or without
 
13
 *  modification, are permitted provided that the following conditions
 
14
 *  are met:
 
15
 *
 
16
 *  1. Redistributions of source code must retain the above copyright
 
17
 *     notice, this list of conditions and the following disclaimer.
 
18
 *  2. Redistributions in binary form must reproduce the above copyright
 
19
 *     notice, this list of conditions and the following disclaimer in the
 
20
 *     documentation and/or other materials provided with the distribution.
 
21
 *  3. Neither the name of authors nor the names of its contributors
 
22
 *     may be used to endorse or promote products derived from this software
 
23
 *     without specific prior written permission.
 
24
 *
 
25
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
 
26
 *  IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 
27
 *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
28
 *  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
 
29
 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
30
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
31
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 
32
 *  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
33
 *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 
34
 *  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
35
 *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
36
===========================================================================*/
 
37
 
 
38
#include <config.h>
 
39
 
 
40
#include <stdlib.h>
 
41
#include <setjmp.h>
 
42
 
 
43
#include "sigscheme.h"
 
44
#include "sigschemeinternal.h"
 
45
 
 
46
/*=======================================
 
47
  File Local Macro Definitions
 
48
=======================================*/
 
49
#define CONTINUATION_FRAME(cont)                                             \
 
50
    ((struct continuation_frame *)SCM_CONTINUATION_OPAQUE(cont))
 
51
#define CONTINUATION_SET_FRAME    SCM_CONTINUATION_SET_OPAQUE
 
52
 
 
53
/*=======================================
 
54
  File Local Type Definitions
 
55
=======================================*/
 
56
struct continuation_frame {
 
57
    /*
 
58
     * - To hint appropriate alignment on stack, a ScmObj is listed first
 
59
     * - GC marking for these ScmObj are implicitly performed by stack scanning
 
60
     */
 
61
    volatile ScmObj dyn_ext;
 
62
    volatile ScmObj ret_val;
 
63
#if SCM_USE_BACKTRACE
 
64
    volatile ScmObj trace_stack;
 
65
#endif
 
66
    jmp_buf c_env;
 
67
};
 
68
 
 
69
/*=======================================
 
70
  Variable Definitions
 
71
=======================================*/
 
72
SCM_GLOBAL_VARS_BEGIN(static_continuation);
 
73
#define static
 
74
static volatile ScmObj l_current_dynamic_extent;
 
75
static volatile ScmObj l_continuation_stack;
 
76
static volatile ScmObj l_trace_stack;
 
77
#undef static
 
78
SCM_GLOBAL_VARS_END(static_continuation);
 
79
#define l_current_dynamic_extent                                             \
 
80
    SCM_GLOBAL_VAR(static_continuation, l_current_dynamic_extent)
 
81
#define l_continuation_stack                                                 \
 
82
    SCM_GLOBAL_VAR(static_continuation, l_continuation_stack)
 
83
#define l_trace_stack                                                        \
 
84
    SCM_GLOBAL_VAR(static_continuation, l_trace_stack)
 
85
SCM_DEFINE_STATIC_VARS(static_continuation);
 
86
 
 
87
/*=======================================
 
88
  File Local Function Declarations
 
89
=======================================*/
 
90
/* dynamic extent */
 
91
static void initialize_dynamic_extent(void);
 
92
static void finalize_dynamic_extent(void);
 
93
static void wind_onto_dynamic_extent(ScmObj before, ScmObj after);
 
94
static void unwind_dynamic_extent(void);
 
95
static void enter_dynamic_extent(ScmObj dest);
 
96
static void exit_dynamic_extent(ScmObj dest);
 
97
 
 
98
/* continuation */
 
99
static void initialize_continuation_env(void);
 
100
static void finalize_continuation_env(void);
 
101
static void continuation_stack_push(ScmObj cont);
 
102
static ScmObj continuation_stack_pop(void);
 
103
static ScmObj continuation_stack_unwind(ScmObj dest_cont);
 
104
 
 
105
/*=======================================
 
106
  Function Definitions
 
107
=======================================*/
 
108
SCM_EXPORT void
 
109
scm_init_continuation(void)
 
110
{
 
111
    SCM_GLOBAL_VARS_INIT(static_continuation);
 
112
 
 
113
    initialize_dynamic_extent();
 
114
    initialize_continuation_env();
 
115
 
 
116
    scm_gc_protect_with_init((ScmObj *)&l_trace_stack, SCM_NULL);
 
117
}
 
118
 
 
119
SCM_EXPORT void
 
120
scm_fin_continuation(void)
 
121
{
 
122
    finalize_continuation_env();
 
123
    finalize_dynamic_extent();
 
124
 
 
125
    SCM_GLOBAL_VARS_FIN(static_continuation);
 
126
}
 
127
 
 
128
/*===========================================================================
 
129
  Dynamic Extent
 
130
===========================================================================*/
 
131
#define MAKE_DYNEXT_FRAME(before, after) CONS((before), (after))
 
132
#define DYNEXT_FRAME_BEFORE CAR
 
133
#define DYNEXT_FRAME_AFTER  CDR
 
134
 
 
135
static void
 
136
initialize_dynamic_extent(void)
 
137
{
 
138
    scm_gc_protect_with_init((ScmObj *)&l_current_dynamic_extent, SCM_NULL);
 
139
}
 
140
 
 
141
static void
 
142
finalize_dynamic_extent(void)
 
143
{
 
144
}
 
145
 
 
146
static void
 
147
wind_onto_dynamic_extent(ScmObj before, ScmObj after)
 
148
{
 
149
    ScmObj frame;
 
150
 
 
151
    frame = MAKE_DYNEXT_FRAME(before, after);
 
152
    l_current_dynamic_extent = CONS(frame, l_current_dynamic_extent);
 
153
}
 
154
 
 
155
static void
 
156
unwind_dynamic_extent(void)
 
157
{
 
158
    if (NULLP(l_current_dynamic_extent))
 
159
        PLAIN_ERR("corrupted dynamic extent");
 
160
 
 
161
    l_current_dynamic_extent = CDR(l_current_dynamic_extent);
 
162
}
 
163
 
 
164
/* enter a dynamic extent of another continuation (dest) */
 
165
static void
 
166
enter_dynamic_extent(ScmObj dest)
 
167
{
 
168
    ScmObj frame, unwound, retpath;
 
169
    DECLARE_INTERNAL_FUNCTION("enter_dynamic_extent");
 
170
 
 
171
    retpath = SCM_NULL;
 
172
    unwound = dest;
 
173
    while (!NULLP(unwound) && !EQ(unwound, l_current_dynamic_extent)) {
 
174
        frame = POP(unwound);
 
175
        retpath = CONS(frame, retpath);
 
176
    }
 
177
 
 
178
    FOR_EACH (frame, retpath)
 
179
        scm_call(DYNEXT_FRAME_BEFORE(frame), SCM_NULL);
 
180
}
 
181
 
 
182
/* exit to a dynamic extent of another continuation (dest) */
 
183
static void
 
184
exit_dynamic_extent(ScmObj dest)
 
185
{
 
186
    ScmObj frame;
 
187
    DECLARE_INTERNAL_FUNCTION("exit_dynamic_extent");
 
188
 
 
189
    while (!NULLP(l_current_dynamic_extent)
 
190
           && !EQ(l_current_dynamic_extent, dest))
 
191
    {
 
192
        frame = POP(l_current_dynamic_extent);
 
193
        scm_call(DYNEXT_FRAME_AFTER(frame), SCM_NULL);
 
194
    }
 
195
}
 
196
 
 
197
SCM_EXPORT ScmObj
 
198
scm_dynamic_wind(ScmObj before, ScmObj thunk, ScmObj after)
 
199
{
 
200
    ScmObj ret;
 
201
 
 
202
    scm_call(before, SCM_NULL);
 
203
 
 
204
    wind_onto_dynamic_extent(before, after);
 
205
    ret = scm_call(thunk, SCM_NULL);
 
206
    unwind_dynamic_extent();
 
207
 
 
208
    scm_call(after, SCM_NULL);
 
209
 
 
210
    return ret;
 
211
}
 
212
 
 
213
/*===========================================================================
 
214
  Continuation
 
215
===========================================================================*/
 
216
static void
 
217
initialize_continuation_env(void)
 
218
{
 
219
    scm_gc_protect_with_init((ScmObj *)&l_continuation_stack, SCM_NULL);
 
220
}
 
221
 
 
222
static void
 
223
finalize_continuation_env(void)
 
224
{
 
225
}
 
226
 
 
227
static void
 
228
continuation_stack_push(ScmObj cont)
 
229
{
 
230
    l_continuation_stack = CONS(cont, l_continuation_stack);
 
231
}
 
232
 
 
233
static ScmObj
 
234
continuation_stack_pop(void)
 
235
{
 
236
    DECLARE_INTERNAL_FUNCTION("continuation_stack_pop");
 
237
 
 
238
    return NULLP(l_continuation_stack) ? SCM_FALSE : POP(l_continuation_stack);
 
239
}
 
240
 
 
241
/* expire all descendant continuations and dest_cont */
 
242
static ScmObj
 
243
continuation_stack_unwind(ScmObj dest_cont)
 
244
{
 
245
    ScmObj cont;
 
246
 
 
247
    do {
 
248
        cont = continuation_stack_pop();
 
249
        if (FALSEP(cont))
 
250
            return SCM_FALSE;
 
251
        CONTINUATION_SET_FRAME(cont, INVALID_CONTINUATION_OPAQUE);
 
252
    } while (!EQ(dest_cont, cont));
 
253
 
 
254
    return dest_cont;
 
255
}
 
256
 
 
257
SCM_EXPORT void
 
258
scm_destruct_continuation(ScmObj cont)
 
259
{
 
260
    /* no object to be free(3) in this implementation */
 
261
}
 
262
 
 
263
SCM_EXPORT ScmObj
 
264
scm_call_with_current_continuation(ScmObj proc, ScmEvalState *eval_state)
 
265
{
 
266
    volatile ScmObj cont, ret;
 
267
    struct continuation_frame cont_frame;
 
268
 
 
269
    cont_frame.dyn_ext = l_current_dynamic_extent;
 
270
    cont_frame.ret_val = SCM_UNDEF;
 
271
#if SCM_USE_BACKTRACE
 
272
    cont_frame.trace_stack = l_trace_stack;
 
273
#endif
 
274
    cont = MAKE_CONTINUATION();
 
275
    CONTINUATION_SET_FRAME(cont, &cont_frame);
 
276
#if SCM_NESTED_CONTINUATION_ONLY
 
277
    continuation_stack_push(cont);
 
278
#endif
 
279
 
 
280
    if (setjmp(cont_frame.c_env)) {
 
281
        /* returned back to the original continuation */
 
282
        /* Don't refer cont because it may already be invalidated by
 
283
         * continuation_stack_unwind(). */
 
284
#if SCM_USE_BACKTRACE
 
285
        l_trace_stack = cont_frame.trace_stack;
 
286
#endif
 
287
 
 
288
        enter_dynamic_extent(cont_frame.dyn_ext);
 
289
 
 
290
        eval_state->ret_type = SCM_VALTYPE_AS_IS;
 
291
        return cont_frame.ret_val;
 
292
    } else {
 
293
#if SCM_NESTED_CONTINUATION_ONLY
 
294
        /* Call proc with current continutation as (proc cont): This call must
 
295
         * not be scm_values_applier, to preserve current stack until longjmp()
 
296
         * is called. And so this implementation is not properly recursive. */
 
297
        eval_state->ret_type = SCM_VALTYPE_AS_IS;
 
298
        ret = scm_call(proc, LIST_1(cont));
 
299
 
 
300
        /* the continuation expires when this function returned */
 
301
        continuation_stack_unwind(cont);
 
302
#else
 
303
        /* ONLY FOR TESTING: This call is properly recursible, but all
 
304
         * continuations are broken and cannot be called, if the continuation
 
305
         * is implemented by longjmp(). */
 
306
        ret = LIST_3(scm_values_applier, proc, cont);
 
307
#endif
 
308
 
 
309
        return ret;
 
310
    }
 
311
}
 
312
 
 
313
SCM_EXPORT void
 
314
scm_call_continuation(ScmObj cont, ScmObj ret)
 
315
{
 
316
    struct continuation_frame *frame;
 
317
#if SCM_NESTED_CONTINUATION_ONLY
 
318
    ScmObj dst;
 
319
#endif
 
320
    DECLARE_INTERNAL_FUNCTION("scm_call_continuation");
 
321
 
 
322
    frame = CONTINUATION_FRAME(cont);
 
323
 
 
324
    if (frame != INVALID_CONTINUATION_OPAQUE
 
325
#if SCM_NESTED_CONTINUATION_ONLY
 
326
        && (dst = continuation_stack_unwind(cont), CONTINUATIONP(dst))
 
327
#endif
 
328
        )
 
329
    {
 
330
        if (VALUEPACKETP(ret))
 
331
            ERR_OBJ("continuations take exactly one value but got", ret);
 
332
 
 
333
        /* Don't refer cont because it may already be invalidated by
 
334
         * continuation_stack_unwind(). */
 
335
        exit_dynamic_extent(frame->dyn_ext);
 
336
 
 
337
        frame->ret_val = ret;
 
338
        longjmp(frame->c_env, scm_true);
 
339
        /* NOTREACHED */
 
340
    } else {
 
341
        ERR("expired continuation");
 
342
    }
 
343
}
 
344
 
 
345
/*===========================================================================
 
346
  Trace Stack
 
347
===========================================================================*/
 
348
#if SCM_USE_BACKTRACE
 
349
SCM_EXPORT void
 
350
scm_push_trace_frame(ScmObj obj, ScmObj env)
 
351
{
 
352
    ScmObj frame;
 
353
 
 
354
    frame = MAKE_TRACE_FRAME(obj, env);
 
355
    l_trace_stack = CONS(frame, l_trace_stack);
 
356
}
 
357
 
 
358
SCM_EXPORT void
 
359
scm_pop_trace_frame(void)
 
360
{
 
361
    SCM_ASSERT(CONSP(l_trace_stack));
 
362
 
 
363
    l_trace_stack = CDR(l_trace_stack);
 
364
}
 
365
#endif /* SCM_USE_BACKTRACE */
 
366
 
 
367
SCM_EXPORT ScmObj
 
368
scm_trace_stack(void)
 
369
{
 
370
    return l_trace_stack;
 
371
}