Nikodemus Siivola wrote:
> Brian Mastenbrook wrote:
>> Nikodemus Siivola wrote:
>>> * We can, however, gain a synchronous timeout ability by making various
>>> blocking functions have not just a :TIMEOUT parameter, but by making
>>> them also respect a global *DEADLINE*. I hesitate to say anything
>>> about properties of such synchronous timeouts, though.
>> What is your concern here about the properties of such timeouts?
> Just my ability to get details of stuff like this wrong the first time.
> I would like to say that they are well-behaved and can be unwound from
> safely, but I have no proof either way right now.
These synchronous timeouts should all be triggered after return into
Lisp, when the code calling the foreign function checks the return value
and determines that it returned due to an expired timeout. Thus unwind
will be safe as it will be triggered from Lisp code, and not from a
signal handler running in the middle of an allocation (or any other
>> Regardless of whether async unwinds can be made safe, I think what you
>> describe is good global policy. For applications which call a number
>> of blocking APIs but are unconcerned with entering an infinite loop in
>> Lisp code, this is all the timeout machinery which is necessary. It
>> would probably be a good idea to expose the API used here so that FFI
>> users can respect these timeouts as well. I've a few thoughts here if
>> others are interested.
> I am!
... they don't necessarily have to unwind. TIMEOUT should be signaled as
a condition, and a restart made available to continue execution.
Consider an application working with SIP messaging over UDP: it must
explicitly retry certain transactions if no response is received, but in
the meantime it may be off trying to contact another host. In this case,
the response to the timeout should be to retry the message send and
return to whatever else may be processing.
*DEADLINE* is probably too simple as well. Applications like the one I
mentioned above will need to have a set of timeouts active and trigger
different responses depending on which timeout is expiring. Also,
timeout response will usually not need to be taken (as usually the
remote host will be there) and so the application should be given some
way of canceling a timeout. Put this way, a deadline is more of a
computed function from which timeouts are currently active than a single
global value. This function can be computed when timeouts are added to
and removed from the set of active timeouts, so the code surrounding
each blocking foreign call will still be relatively cheap.
I think the interface which is needed here is:
* A function to return the current deadline based on the current
* A function to trigger appropriate timeout actions when the deadline
* A function to register a timeout, which is given an instance of a
condition class to be signaled when the timeout expires
* A function to cancel a timeout, which is given the condition class
instance to find in the queue and cancel
There are still a few rough edges here that need to be ironed out: for
instance, when a blocking call returns successfully but the deadline has
passed, do we still invoke timeout handlers? If a timeout handler
chooses to unwind, but other timeouts active in the queue are ready to
expire, when do they fire?
It would probably be interesting to have SB-EVAL check the timeout
periodically as well.