unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* Long-lived Guile scripts in a mono-threaded game engine
@ 2008-05-26 21:19 Sylvain Beucler
  2008-05-27  7:58 ` Ludovic Courtès
  0 siblings, 1 reply; 11+ messages in thread
From: Sylvain Beucler @ 2008-05-26 21:19 UTC (permalink / raw
  To: guile-user

i,

I'm contemplating adding Guile support in GNU FreeDink, which is a
game engine for Dink Smallwood, a 2D scripted game.

Currently there's a "manually coded" scripting engine which is pretty
limited and buggy, though it works decently enough and was already
used for large extensions.

I'd like to add Guile as an alternative :)


Currently I'm facing several issues, the main one is how to manage
long-lived scripts:

The engine runs in a single thread, and the game loop essentially:

- passes over all sprites in a screen, and runs the scripts attached
  to those sprites

- detect collisions and run associated scripted hooks

- perform other non-scripted transformations such as sprite
  progressive moves, update the status bar, etc.

- the game screen is then refreshed with the new game state

- repeat


Scripts last more than a single game loop. They are not basic scripts
that describe what happens in a single engine step; instead they
describe what happens in the story.

For example, a game introduction will create sprites on the screen,
move them around, make them say lines that the user can read (or pass
using [space]), etc.

That script can also change the current screen (which kills all other
scripts in the current script).

Multiple scripts can run in a single screen, but they run the one
after the other, not in parallel. The order/priority is known.

Scripting is essentially frozen during the screen refresh. This avoids
putting mutexes everywhere.




How could I do something similar with Guile? I didn't find a way to
make a guile script pause (and return to the caller).

I guess one possibility is to run all scripts as independent threads,
and make them lock on a global mutex. However, as emphasized in this
article
http://harkal.sylphis3d.com/2005/08/10/multithreaded-game-scripting-with-stackless-python/
I would appreciate non-preemtiveness, for simplicity.

I think what I'm looking for is similar to Lua's coroutines
(a.k.a. fake threads - one coroutine at a time)
http://lua-users.org/wiki/CoroutinesTutorial

It's also important that running scripts can be terminated by the game
engine if need be.


How would you do this with Guile? :)

Thanks,

-- 
Sylvain




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Long-lived Guile scripts in a mono-threaded game engine
  2008-05-26 21:19 Long-lived Guile scripts in a mono-threaded game engine Sylvain Beucler
@ 2008-05-27  7:58 ` Ludovic Courtès
  2008-05-27  8:33   ` Sylvain Beucler
  0 siblings, 1 reply; 11+ messages in thread
From: Ludovic Courtès @ 2008-05-27  7:58 UTC (permalink / raw
  To: guile-user

Hi Sylvain,

Sylvain Beucler <beuc@beuc.net> writes:

> I'm contemplating adding Guile support in GNU FreeDink, which is a
> game engine for Dink Smallwood, a 2D scripted game.

Nice.  :-)

> Scripts last more than a single game loop. They are not basic scripts
> that describe what happens in a single engine step; instead they
> describe what happens in the story.
>
> For example, a game introduction will create sprites on the screen,
> move them around, make them say lines that the user can read (or pass
> using [space]), etc.
>
> That script can also change the current screen (which kills all other
> scripts in the current script).
>
> Multiple scripts can run in a single screen, but they run the one
> after the other, not in parallel. The order/priority is known.
>
> Scripting is essentially frozen during the screen refresh. This avoids
> putting mutexes everywhere.
>
>
>
>
> How could I do something similar with Guile? I didn't find a way to
> make a guile script pause (and return to the caller).

IIUC, "scripts" are only invoked via hooks, e.g., the engine wants to
ask them to do something specific.  If that is the case, it suffices to
not invoke the script.

Surely you can implement coroutine-like behavior, either using `call/cc'
(but that is going to be prohibitively expensive), or using explicit
continuation-passing style or similar.  For instance, when a hook is
called by the engine, it would systematically return a thunk (a
zero-argument procedure) that the engine would later invoke.  Example:

  (define (my-hook action)
    (let ((stuff (do-some-computation action)))
      (lambda ()
        ;; This will be executed at some later point, when the engine
        ;; feels like invoking it.
        (do-the-remaining-computation stuff))))

Does this help?

Thanks,
Ludovic.





^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Long-lived Guile scripts in a mono-threaded game engine
  2008-05-27  7:58 ` Ludovic Courtès
@ 2008-05-27  8:33   ` Sylvain Beucler
  2008-05-27 13:20     ` Ludovic Courtès
  2008-05-27 13:42     ` Paul Emsley
  0 siblings, 2 replies; 11+ messages in thread
From: Sylvain Beucler @ 2008-05-27  8:33 UTC (permalink / raw
  To: Ludovic Courtès; +Cc: guile-user

Hi,

On Tue, May 27, 2008 at 09:58:46AM +0200, Ludovic Courtès wrote:
> > Scripts last more than a single game loop. They are not basic scripts
> > that describe what happens in a single engine step; instead they
> > describe what happens in the story.
> >
> > For example, a game introduction will create sprites on the screen,
> > move them around, make them say lines that the user can read (or pass
> > using [space]), etc.
> >
> > That script can also change the current screen (which kills all other
> > scripts in the current script).
> >
> > Multiple scripts can run in a single screen, but they run the one
> > after the other, not in parallel. The order/priority is known.
> >
> > Scripting is essentially frozen during the screen refresh. This avoids
> > putting mutexes everywhere.
> >
> >
> >
> >
> > How could I do something similar with Guile? I didn't find a way to
> > make a guile script pause (and return to the caller).
> 
> IIUC, "scripts" are only invoked via hooks, e.g., the engine wants to
> ask them to do something specific.  If that is the case, it suffices to
> not invoke the script.
> 
> Surely you can implement coroutine-like behavior, either using `call/cc'
> (but that is going to be prohibitively expensive), or using explicit
> continuation-passing style or similar.  For instance, when a hook is
> called by the engine, it would systematically return a thunk (a
> zero-argument procedure) that the engine would later invoke.  Example:
> 
>   (define (my-hook action)
>     (let ((stuff (do-some-computation action)))
>       (lambda ()
>         ;; This will be executed at some later point, when the engine
>         ;; feels like invoking it.
>         (do-the-remaining-computation stuff))))
> 
> Does this help?

Ok, so what I'm looking for isn't supported natively :/


Here's a sample script (very close to the C bindings, for a start):

(define (hit)
  (if (> (sp_gethitpoints (current_sprite)) 10)
    (begin
      (sp_sethitpoints (current_sprite) (- (sp_hitpoints (current_sprite)) 10))
      (dialog1))
    (begin
      (say_stop "ARRRRrr.." (current_sprite))
      (sp_kill (current_sprite) 0)
      (say_stop "Uh, I was supposed to protect him, not kill him!" 1)))
  (set_honour! (- (get_honour) 1)))

(define (dialog1)
  (say_stop "Why are you hitting me, player?" (current_sprite))
  (say_stop "Uh, sorry I won't do that again" 1))


Now every time we see a (say_stop), the script will pause for 2
seconds, so the player can read the text.


If I use CPS, this means I'll have to rewrite all my scripts in CPS
style. This would be pretty cumbersome. This is supposed to introduce
people to the beautiful world of scheme, not scare them to death ;)


call/cc has another issue: how do I return? Let's say I'm in the
middle of (dialog1) and I need to stop the script. Maybe with a set of
double continuations: one continuation at the top level to return to
the point before I called the initial procedure (which would stops the
script); and another one that is set at each (say_stop) to return to
the following line (to resume the script). Hopefully this is not as
inefficient as you suggested.


Maybe I'm missing a more simple solution?

-- 
Sylvain




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Long-lived Guile scripts in a mono-threaded game engine
  2008-05-27  8:33   ` Sylvain Beucler
@ 2008-05-27 13:20     ` Ludovic Courtès
  2008-05-27 16:14       ` Sylvain Beucler
  2008-05-27 13:42     ` Paul Emsley
  1 sibling, 1 reply; 11+ messages in thread
From: Ludovic Courtès @ 2008-05-27 13:20 UTC (permalink / raw
  To: guile-user

Salut,

Sylvain Beucler <beuc@beuc.net> writes:

> Here's a sample script (very close to the C bindings, for a start):
>
> (define (hit)
>   (if (> (sp_gethitpoints (current_sprite)) 10)
>     (begin
>       (sp_sethitpoints (current_sprite) (- (sp_hitpoints (current_sprite)) 10))
>       (dialog1))
>     (begin
>       (say_stop "ARRRRrr.." (current_sprite))
>       (sp_kill (current_sprite) 0)
>       (say_stop "Uh, I was supposed to protect him, not kill him!" 1)))
>   (set_honour! (- (get_honour) 1)))
>
> (define (dialog1)
>   (say_stop "Why are you hitting me, player?" (current_sprite))
>   (say_stop "Uh, sorry I won't do that again" 1))
>
>
> Now every time we see a (say_stop), the script will pause for 2
> seconds, so the player can read the text.

IOW, `say_stop' does a `(sleep 2)' (or `sleep (2)'), or waits for some
UI event, is that right?

> If I use CPS, this means I'll have to rewrite all my scripts in CPS
> style.

Yes, but you said this was work-in-progress, so I suppose there's no
backward compatibility concern.  ;-)

> This would be pretty cumbersome. This is supposed to introduce
> people to the beautiful world of scheme, not scare them to death ;)

Well, it's not necessarily that scary, and it depends on how often you'd
have to use it.

> call/cc has another issue: how do I return? Let's say I'm in the
> middle of (dialog1) and I need to stop the script. Maybe with a set of
> double continuations: one continuation at the top level to return to
> the point before I called the initial procedure (which would stops the
> script); and another one that is set at each (say_stop) to return to
> the following line (to resume the script).

Yes, something like that: a continuation to invoke the "scheduler" (the
engine), which would be passed the continuation within `dialog1' that
needs to be resumed eventually.

> Hopefully this is not as inefficient as you suggested.

Depends on how often (and when) you do it, but expect it to be
inefficient as it copies the stack (see the "Continuations" node in the
manual).

It may actually be simpler to run the Scheme code in a separate POSIX
thread, and have it woken up by the engine when it should start working.

Thanks,
Ludovic.





^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Long-lived Guile scripts in a mono-threaded game engine
  2008-05-27  8:33   ` Sylvain Beucler
  2008-05-27 13:20     ` Ludovic Courtès
@ 2008-05-27 13:42     ` Paul Emsley
  1 sibling, 0 replies; 11+ messages in thread
From: Paul Emsley @ 2008-05-27 13:42 UTC (permalink / raw
  To: guile-user, beuc

Sylvain Beucler wrote:
> Hi,
>
> On Tue, May 27, 2008 at 09:58:46AM +0200, Ludovic Courtès wrote:
>   
>>> Scripts last more than a single game loop. They are not basic scripts
>>> that describe what happens in a single engine step; instead they
>>> describe what happens in the story.
>>>
>>> For example, a game introduction will create sprites on the screen,
>>> move them around, make them say lines that the user can read (or pass
>>> using [space]), etc.
>>>
>>> That script can also change the current screen (which kills all other
>>> scripts in the current script).
>>>
>>> Multiple scripts can run in a single screen, but they run the one
>>> after the other, not in parallel. The order/priority is known.
>>>
>>> Scripting is essentially frozen during the screen refresh. This avoids
>>> putting mutexes everywhere.
>>>
>>>
>>>
>>>
>>> How could I do something similar with Guile? I didn't find a way to
>>> make a guile script pause (and return to the caller).
>>>       
>> IIUC, "scripts" are only invoked via hooks, e.g., the engine wants to
>> ask them to do something specific.  If that is the case, it suffices to
>> not invoke the script.
>>
>> Surely you can implement coroutine-like behavior, either using `call/cc'
>> (but that is going to be prohibitively expensive), or using explicit
>> continuation-passing style or similar.  For instance, when a hook is
>> called by the engine, it would systematically return a thunk (a
>> zero-argument procedure) that the engine would later invoke.  Example:
>>
>>   (define (my-hook action)
>>     (let ((stuff (do-some-computation action)))
>>       (lambda ()
>>         ;; This will be executed at some later point, when the engine
>>         ;; feels like invoking it.
>>         (do-the-remaining-computation stuff))))
>>
>> Does this help?
>>     
>
> Ok, so what I'm looking for isn't supported natively :/
>
>
> Here's a sample script (very close to the C bindings, for a start):
>
> [snip script]
>
> Now every time we see a (say_stop), the script will pause for 2
> seconds, so the player can read the text.
>   

what is the nature of the pause? (I think that that might be 
important.)  How do you interrupt the tight little say_stop sleep loop 
(if that's what it is) when you are using C bindings?

> Maybe I'm missing a more simple solution?
>
>   

Maybe.






^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Long-lived Guile scripts in a mono-threaded game engine
  2008-05-27 13:20     ` Ludovic Courtès
@ 2008-05-27 16:14       ` Sylvain Beucler
  2008-05-27 18:08         ` Ludovic Courtès
  2008-05-27 18:19         ` Clinton Ebadi
  0 siblings, 2 replies; 11+ messages in thread
From: Sylvain Beucler @ 2008-05-27 16:14 UTC (permalink / raw
  To: Ludovic Courtès; +Cc: guile-user

Hi,

On Tue, May 27, 2008 at 03:20:55PM +0200, Ludovic Courtès wrote:
> Sylvain Beucler <beuc@beuc.net> writes:
> 
> > Here's a sample script (very close to the C bindings, for a start):
> >
> > (define (hit)
> >   (if (> (sp_gethitpoints (current_sprite)) 10)
> >     (begin
> >       (sp_sethitpoints (current_sprite) (- (sp_hitpoints (current_sprite)) 10))
> >       (dialog1))
> >     (begin
> >       (say_stop "ARRRRrr.." (current_sprite))
> >       (sp_kill (current_sprite) 0)
> >       (say_stop "Uh, I was supposed to protect him, not kill him!" 1)))
> >   (set_honour! (- (get_honour) 1)))
> >
> > (define (dialog1)
> >   (say_stop "Why are you hitting me, player?" (current_sprite))
> >   (say_stop "Uh, sorry I won't do that again" 1))
> >
> >
> > Now every time we see a (say_stop), the script will pause for 2
> > seconds, so the player can read the text.

> IOW, `say_stop' does a `(sleep 2)' (or `sleep (2)'), or waits for some
> UI event, is that right?
---
> what is the nature of the pause? (I think that that might be important.)
> How do you interrupt the tight little say_stop sleep loop (if that's what
> it is) when you are using C bindings?

Basically, a timestamp (for 'say_stop' and 'wait') or more generally a
goal (coordinates for 'move_stop') is attached to the script. The game
loop, before refreshing the screen, passes on each active script and
see if it needs to be resumed.

If at a point the engine needs 3s to load a bunch of graphics and
sounds from the disk (e.g. during a screen change), the paused script
won't wake up during that, but instead will be awaken by the engine
when it's done with the loading.

So the script does not (sleep). In this game, the engine is a mini-OS
with a non-preemptive process model. This is often used in games for
efficiency and ease of debugging (no concurrency). In my case this is
because the code was like this before I put my hands on it :)

Currently when the script engine interprets 'say_stop("Hello");', it
will set the timestamp at now+2s, save the script resume point, and
return to the main game loop.


> > This would be pretty cumbersome. This is supposed to introduce
> > people to the beautiful world of scheme, not scare them to death ;)
> 
> Well, it's not necessarily that scary, and it depends on how often you'd
> have to use it.

Let's precise the audience: most often, 15-20 years-old with little
programming skills. If we get them to try out Scheme despite Lots of
Irritating Superfluous Parentheses, that will already be a success ;)

Maybe Guile support could then be reserved for Real Programmers, but
to answer your question scripting is used very often in this engine,
so I doubt CPS will please them.


> > call/cc has another issue: how do I return? Let's say I'm in the
> > middle of (dialog1) and I need to stop the script. Maybe with a set of
> > double continuations: one continuation at the top level to return to
> > the point before I called the initial procedure (which would stops the
> > script); and another one that is set at each (say_stop) to return to
> > the following line (to resume the script).
> 
> Yes, something like that: a continuation to invoke the "scheduler" (the
> engine), which would be passed the continuation within `dialog1' that
> needs to be resumed eventually.

Well, I don't think the engine should be called _by_ Guile. Rather the
opposite: the engine calls Guile, and does it one time per active
script or hook.


> It may actually be simpler to run the Scheme code in a separate POSIX
> thread, and have it woken up by the engine when it should start working.

Yeah, I was trying to avoid introducing threads in the engine :)
But it sounds like the only usable solution as of now.

Ideally Guile would offer a '(pause)' function that would return from
'scm_eval_string' or similar, with another 'scm_resume()' function
that would unfreeze it :)

-- 
Sylvain




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Long-lived Guile scripts in a mono-threaded game engine
  2008-05-27 16:14       ` Sylvain Beucler
@ 2008-05-27 18:08         ` Ludovic Courtès
  2008-05-27 19:57           ` Sylvain Beucler
  2008-05-27 18:19         ` Clinton Ebadi
  1 sibling, 1 reply; 11+ messages in thread
From: Ludovic Courtès @ 2008-05-27 18:08 UTC (permalink / raw
  To: guile-user

Hi,

Sylvain Beucler <beuc@beuc.net> writes:

> So the script does not (sleep). In this game, the engine is a mini-OS
> with a non-preemptive process model.

So "scripts" are supposed to be cooperative, and invoking `say_stop'
amounts to doing a `yield', right?

Then your question boils down to how to implement `yield'.  Using
continuations, that would be something like this:

  (define (my-hook schedule)
    (define (yield)
      (call/cc schedule))

    ;; do stuff...

    (yield)

    ;; do more stuff
    )

Where `my-hook' is invoked by the engine and SCHEDULE is a continuation
to invoke the engine, which may in turn schedule another co-routine, and
so on.

You could save one `call/cc' by abusing exceptions (which do not involve
stack copying, unlike `call/cc'):

  (define (my-hook)
    (define (yield)
      (call/cc
        (lambda (resume)
          (throw 'yield-to-scheduler resume))))

    ;; do stuff...

    (yield)

    ;; do more stuff
    )

... where the `yield-to-scheduler' exception would be caught by the
engine.  With a bit of syntactic sugar, this could be hidden from
programmers.

But again, I would avoid `call/cc' at all because of its performance
hit.  Avoiding it would require explicit CPS, which may admittedly be
unsuitable given the audience:

  (define (my-hook)
    (define (yield resume)
      (throw 'yield-to-scheduler resume))

    ;; do stuff...

    (yield (lambda ()
             ;; do more stuff
             )))

Given the drawbacks of these solutions, evaluating scripts in a separate
pthread looks like a good solution.  :-)

> Yeah, I was trying to avoid introducing threads in the engine :)
> But it sounds like the only usable solution as of now.

It's actually not silly now that we've entered the multicore era.

> Ideally Guile would offer a '(pause)' function that would return from
> 'scm_eval_string' or similar, with another 'scm_resume()' function
> that would unfreeze it :)

That would most likely have to be implemented in terms of `call/cc' as
shown above, so it wouldn't help much.

Thanks,
Ludovic





^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Long-lived Guile scripts in a mono-threaded game engine
  2008-05-27 16:14       ` Sylvain Beucler
  2008-05-27 18:08         ` Ludovic Courtès
@ 2008-05-27 18:19         ` Clinton Ebadi
  2008-05-27 21:49           ` Neil Jerram
  1 sibling, 1 reply; 11+ messages in thread
From: Clinton Ebadi @ 2008-05-27 18:19 UTC (permalink / raw
  To: Sylvain Beucler; +Cc: guile-user

Sylvain Beucler <beuc@beuc.net> writes:

>> IOW, `say_stop' does a `(sleep 2)' (or `sleep (2)'), or waits for some
>> UI event, is that right?
> ---
>> what is the nature of the pause? (I think that that might be important.)
>> How do you interrupt the tight little say_stop sleep loop (if that's what
>> it is) when you are using C bindings?
>
> Basically, a timestamp (for 'say_stop' and 'wait') or more generally a
> goal (coordinates for 'move_stop') is attached to the script. The game
> loop, before refreshing the screen, passes on each active script and
> see if it needs to be resumed.
>
> If at a point the engine needs 3s to load a bunch of graphics and
> sounds from the disk (e.g. during a screen change), the paused script
> won't wake up during that, but instead will be awaken by the engine
> when it's done with the loading.
>
> So the script does not (sleep). In this game, the engine is a mini-OS
> with a non-preemptive process model. This is often used in games for
> efficiency and ease of debugging (no concurrency). In my case this is
> because the code was like this before I put my hands on it :)
>
> Currently when the script engine interprets 'say_stop("Hello");', it
> will set the timestamp at now+2s, save the script resume point, and
> return to the main game loop.

You are pretty much doing what call/cc does, and so could
straightforwardly rewrite the functions that cause scripts to freeze
to capture the current continuation and schedule an event to resume
this continuation when needed. So something like:

(define (say-stop message)
  (call/cc (lambda (k)
	     (%say-stop message k))))

This might be worth trying and might perform well enough, but Guile's
call/cc is fairly slow and heavyweight as it must copy the entire C
stack.

An alternative approach could use a thread per script. You'd stash the
thread you want to resume into the event, put it to sleep immediately,
and awaken it again when the event triggers. This would probably be
fairly easy to implement using condition variables. The disadvantage
here is that now every script has a thread which could become
problematic if enough scripts are loaded.

-- 
                   It's no contest, but we still race there                   
                Like the saintly tortoise and the godless hare                




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Long-lived Guile scripts in a mono-threaded game engine
  2008-05-27 18:08         ` Ludovic Courtès
@ 2008-05-27 19:57           ` Sylvain Beucler
  2008-05-27 20:30             ` Clinton Ebadi
  0 siblings, 1 reply; 11+ messages in thread
From: Sylvain Beucler @ 2008-05-27 19:57 UTC (permalink / raw
  To: Ludovic Courtès; +Cc: guile-user

Hi,

Thanks for your answers Ludovic and Clinton.


> An alternative approach could use a thread per script.

By the way, I have a question about threads: is there a way to kill a
running thread? For example when the current game screen changes, all
current scripts are terminated. Or does this need to be implemented
manually?


> > Yeah, I was trying to avoid introducing threads in the engine :)
> > But it sounds like the only usable solution as of now.
> 
> It's actually not silly now that we've entered the multicore era.

That's a pro, but there are cons too :/
- this kind of game engine has hardly anything runnable in parallel
- all the game globals need to be properly mutex'd
- or threads executions need to be serialized which defeats the point
Another pro though is that all of us masochists love debugging
multithread programs ;)


I'll try these solutions with my toy project and see how they fair
with performances/complexity :)

Thanks,

-- 
Sylvain




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Long-lived Guile scripts in a mono-threaded game engine
  2008-05-27 19:57           ` Sylvain Beucler
@ 2008-05-27 20:30             ` Clinton Ebadi
  0 siblings, 0 replies; 11+ messages in thread
From: Clinton Ebadi @ 2008-05-27 20:30 UTC (permalink / raw
  To: Sylvain Beucler; +Cc: guile-user

Sylvain Beucler <beuc@beuc.net> writes:

> Hi,
>
> Thanks for your answers Ludovic and Clinton.
>
>
>> An alternative approach could use a thread per script.
>
> By the way, I have a question about threads: is there a way to kill a
> running thread? For example when the current game screen changes, all
> current scripts are terminated. Or does this need to be implemented
> manually?

cancel-thread / scm_cancel_thread should do what you want

-- 
<captain_krunk> ntk is currently using "telnet fyodor 25" to send email




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Long-lived Guile scripts in a mono-threaded game engine
  2008-05-27 18:19         ` Clinton Ebadi
@ 2008-05-27 21:49           ` Neil Jerram
  0 siblings, 0 replies; 11+ messages in thread
From: Neil Jerram @ 2008-05-27 21:49 UTC (permalink / raw
  To: Clinton Ebadi; +Cc: guile-user

[-- Attachment #1: Type: text/plain, Size: 1523 bytes --]

2008/5/27 Clinton Ebadi <clinton@unknownlamer.org>:

> You are pretty much doing what call/cc does, and so could
> straightforwardly rewrite the functions that cause scripts to freeze
> to capture the current continuation and schedule an event to resume
> this continuation when needed. So something like:
>
> (define (say-stop message)
>  (call/cc (lambda (k)
>             (%say-stop message k))))
>
> This might be worth trying and might perform well enough, but Guile's
> call/cc is fairly slow and heavyweight as it must copy the entire C
> stack.


The amount of the stack that needs copying could be reduced, though, by
putting a continuation barrier (scm_c_with_continuation_barrier) in the C
code shortly before it calls out to Guile.

Personally, I'd try the continuation approach.  I did something just like
this for a dayjob-related project, where a key objective was to make the
Scheme scripts as friendly-looking as possible to non-Scheme people.  I used
continuations to make it possible to write a script as a sequence of
apparently synchronous operations that were really asynchronous (i.e. send a
request somewhere, and wait for an asynchronous response).  It can be done
in such a way that the call/cc is hidden down in the infrastructure, and
script-writers never need to see it.

A complication in my case was that the C code was sensitive to unusual
return patterns.  So I also needed to use a continuation to protect the C
code; I can provide more detail about that if needed.

Regards,
        Neil

[-- Attachment #2: Type: text/html, Size: 1917 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2008-05-27 21:49 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-26 21:19 Long-lived Guile scripts in a mono-threaded game engine Sylvain Beucler
2008-05-27  7:58 ` Ludovic Courtès
2008-05-27  8:33   ` Sylvain Beucler
2008-05-27 13:20     ` Ludovic Courtès
2008-05-27 16:14       ` Sylvain Beucler
2008-05-27 18:08         ` Ludovic Courtès
2008-05-27 19:57           ` Sylvain Beucler
2008-05-27 20:30             ` Clinton Ebadi
2008-05-27 18:19         ` Clinton Ebadi
2008-05-27 21:49           ` Neil Jerram
2008-05-27 13:42     ` Paul Emsley

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).