Freeze and Resume execution

M

Miki Tebeka

Hello All,

I'm looking for a way to "yield" an exception.

Background: I'm writing a hardware simulator. I have an output buffer
and need to freeze when it's full and then when called again to resume
execution from the point where it stopped.

Currently all I can think of is to use a class and save the state when
throwing an exception. However this required manual book keeping of the
current state (and it is complicated).

I'd like to use generators but can't see any "nice" way of doing it.
What I'd like it to throw an exception when the buffer is full and then
next time the generator is called to continue execution as after a
"yield".

Is this possible?
Can you recommend a good way of doing this? Any state machine?

Thanks.
Bye.
 
P

Peter Hansen

Miki said:
I'm looking for a way to "yield" an exception.

Background: I'm writing a hardware simulator. I have an output buffer
and need to freeze when it's full and then when called again to resume
execution from the point where it stopped.

I think the very nature of exceptions prevents this in the
sense you are thinking. The whole point is that something
unusual has occurred and the current flow of control should
be interrupted and not resumed.
I'd like to use generators but can't see any "nice" way of doing it.

That would be the approach I would take. What can't you see
with using yield this way?
What I'd like it to throw an exception when the buffer is full and then
next time the generator is called to continue execution as after a
"yield".

Unlike the exception, the nature of yield is that execution *will*
continue afterwards, so my only advice is to try to find a way to
use generators as you initially thought.

-Peter
 
B

Brian Kelley

Miki said:
Hello All,

I'm looking for a way to "yield" an exception.

Background: I'm writing a hardware simulator. I have an output buffer
and need to freeze when it's full and then when called again to resume
execution from the point where it stopped.

Currently all I can think of is to use a class and save the state when
throwing an exception. However this required manual book keeping of the
current state (and it is complicated).

I'd like to use generators but can't see any "nice" way of doing it.
What I'd like it to throw an exception when the buffer is full and then
next time the generator is called to continue execution as after a
"yield".

I'm not sure if this helps or not, but as Peter was saying, throwing an
exception is counter to resuming a state machine as raising an exception
will halt execution.

You can however, yield exceptions through a generator, not raise them.
I do this occasionally in threaded GUI work. Here is a simple
micro-thread inspired interrupt. Note however, that the exception is
syntactic sugar, you can (and maybe should) use your own class for
managing your simulated hardware interrupts.

def work(res, length=10):
while 1:
if len(res) > length:
# oops, need an interrupt to handle the
# global state, the buffer is full
yield ValueError("length > %s"%length)
else:
res.append(1)

l = []
g = iter(work(l, 10))

while 1:
# work until an interrupt
err = g.next()
try:
raise err
except ValueError:
print "clearing the list"
del l[0:10]
 
H

Hung Jung Lu

Miki Tebeka said:
I'm looking for a way to "yield" an exception.
...
I'd like to use generators but can't see any "nice" way of doing it.
What I'd like it to throw an exception when the buffer is full and then
next time the generator is called to continue execution as after a
"yield".

Generators are yielding in the wrong direction, though.

I will assume that you do not have to roll-back changes. (When there
is a roll-back requirement, things get complicated, and
prototype-based languages are more suitable for that purpose.)

while 1:
try:
write_output()
break
except BufferFullException:
request_user_intervention()

Would something like that suit your purpose? (The
request_user_intervention() method could be a callback.)
Is this possible?
Can you recommend a good way of doing this? Any state machine?

Yes, of course it's possible. IDEs like VB6 and Visual C++ all have
edit-and-continue features. When a bug happens, the program stops. You
have chance to modify some variables, then resume execution from the
point of failure. Similarly, in transaction-enabled software (like
databases), when failures occur, you can even rollback the whole thing
as if nothing has happened.

It all depends on the details of your requirements. The simplest
solution is the one shown above. If that does not meet your
requirements, could you please post further details?

If you do require roll-back, the solution could be very different.
Prototype-based languages are the natural platform for dealing with
this type of problem. But if you do not use PB-OOP, you will have to
create sandbox objects manually, and do the commitment/roll-back by
hand.

State machines are OK, too. (With a workspace object often known as
REQUEST.) But the problem is how granular you want to define your
states. It's a pain when the level of granularity changes. I'd try the
callback approach shown above, before anything else.

The approach shown above can be further refined upon usage of
aspect-oriented-ish mechanics and/or codeblocks. There are many tools
to attack the problem. It all depends on your specific needs.

regards,

Hung Jung
 
S

Slawomir Nowaczyk

On Sun, 23 May 2004 12:16:20 +0200

#>>> I'd like to use generators but can't see any "nice" way of doing
#>>> it.

#>> That would be the approach I would take. What can't you see with
#>> using yield this way?

#> The output function is way down the call stack. The function that
#> handles the "freezing" and need to be saved is about 3-5 stack
#> frames up (depends on the scenario).

#> Propagating the output return value all the way back is tedious and
#> error prone. This is why I'd like to use raise/catch and not "if
#> error ..."

I must admit I don't really understand what your problem is, so my
solution may not be what you are looking for. However, maybe it will
be useful:

**********************************************************************

def generator():
i = 0
while 1:
i += 1
yield i

class A:
def __init__(self):
self.gen = generator()
def work(self):
i = 0
while True:
print self.gen.next()
i += 1
if i > 5:
raise ValueError

a = A()

def x():
a.work()

def y():
x()

def z():
for i in range(5):
try:
y()
except ValueError:
print "do something with this exception"

**********************************************************************

--
Best wishes,
Slawomir Nowaczyk
( (e-mail address removed) )

Get the facts first - you can distort them later!
 
M

Miki Tebeka

Hello All,

Thanks for all the input.
That would be the approach I would take. What can't you see
with using yield this way?
The output function is way down the call stack. The function that handles
the "freezing" and need to be saved is about 3-5 stack frames up
(depends on the scenario).

Propagating the output return value all the way back is tedious and
error prone. This is why I'd like to use raise/catch and not "if error
...."


Bye.
 
P

Peter Hansen

Miki said:
The output function is way down the call stack. The function that handles
the "freezing" and need to be saved is about 3-5 stack frames up
(depends on the scenario).

Propagating the output return value all the way back is tedious and
error prone. This is why I'd like to use raise/catch and not "if error
..."

I start to understand, a bit. Sounds like the suggestions to
use Stackless (and tasklets) are on the right track.

Alternatively, could you just use threads and have the output function
block (and force a context switch) when the buffer is full?

If you can't use threads, and you can't use Stackless, and if
exceptions don't allow restarting, and if generators preserve
only the current frame and not the entire stack (i.e. you can't
hand the generator state up to a higher level function, then
resume from there, which would be more like a coroutine I guess),
then it looks like handling this with classes/state machines is
your only option.

-Peter
 
M

Miki Tebeka

Hello Slawomir,
I must admit I don't really understand what your problem is, so my
solution may not be what you are looking for. However, maybe it will
be useful:

**********************************************************************

def generator():
i = 0
while 1:
i += 1
yield i

class A:
def __init__(self):
self.gen = generator()
def work(self):
i = 0
while True:
print self.gen.next()
i += 1
if i > 5:
raise ValueError

My problem is that the one raising the error is the generator. And I'd
like to resume the generator just after the exception was raised.
Something in the lines of:

class BufferFull(Exception):
pass

def send_one_bit(bit):
pass

OUT_BUFFER_SIZE = 10
def output(bits):
size = 0
for bit in bits:
send_one_bit(bit) # HW call
size += 1
if size == OUT_BUFFER_SIZE:
raise BufferFull # I'd like to resume just after this point
size = 0

Note that the output buffer is called about 3-5 stack frames down from
the function catching the exception.

Bye.
 
M

Miki Tebeka

Hello Peter,
If you can't use threads, and you can't use Stackless, and if
exceptions don't allow restarting, and if generators preserve
only the current frame and not the entire stack (i.e. you can't
hand the generator state up to a higher level function, then
resume from there, which would be more like a coroutine I guess),
then it looks like handling this with classes/state machines is
your only option.
<sigh> I'm afraid that's what I'll do. Don't have time to play with
stackless now although continuations seems like the right solution.
BTW: I never had a good grasp on continuations in my Schemeing days.
Generators are *way* simpler to understand and use.

Bye.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top