From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,37f13de4a5a41a8 X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 2003-04-01 08:26:51 PST Path: archiver1.google.com!news1.google.com!newsfeed.stanford.edu!news-spur1.maxwell.syr.edu!news.maxwell.syr.edu!fu-berlin.de!uni-berlin.de!82-43-33-254.cable.ubr01.croy.blueyonder.co.UK!not-for-mail From: Nick Roberts Newsgroups: comp.lang.ada Subject: Re: Elegant 'abort' of sleeping task Date: Tue, 01 Apr 2003 17:26:46 +0100 Organization: ThoughtWing Computer Software Message-ID: References: <310b040f.0303310518.76dc9bf7@posting.google.com> NNTP-Posting-Host: 82-43-33-254.cable.ubr01.croy.blueyonder.co.uk (82.43.33.254) Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-15; format=flowed X-Trace: fu-berlin.de 1049214410 4026073 82.43.33.254 (16 [25716]) In-Reply-To: <310b040f.0303310518.76dc9bf7@posting.google.com> User-Agent: Opera7.03/Win32 M2 build 2670 Xref: archiver1.google.com comp.lang.ada:35866 Date: 2003-04-01T17:26:46+01:00 List-Id: On 31 Mar 2003 05:18:20 -0800, Simon Apperley wrote: > I'm looking at the design of a piece of server code which has to > handle calls that also pass a timeout value. The target system is > aerospace related, and dynamically creating tasks 'on the fly' just is > not an option. > > I want to be able to set up a single task to handle the timeout from > the head of a delta-queue of timeouts, but have found a problem. If I > have the timeout implemented as a task stuck in a 'delay' call, and a > more immediate timeout comes in, I want to wake up the sleeping task, > re-calculate the delta-queue and then sleep on the new, shorter, > delay. So far the only way I can see to do this is to use abort, and > set up the task again, which seems a bit of a brute force approach. > > Has anyone got any suggestions on how I can interrupt the sleep call, > without using a polling approach that would just consume CPU time at > the expense of the other code in the system. > > I could use direct calls to the underlying RTOS, but I'd rather keep > as much as possible within the Ada language. > > I did wonder about delay until TIME, and having another task change > TIME, but that seems rather un-safe to me as it starts making > assumptions about the underlying run-time implementation. Changing the parameter of a delay statement won't work! (Unless the Ada implementation is faulty.) I don't think there is likely to be any way of avoiding some sort of a polling solution to your problem, in practice, since presumably you want the server task to know if a timeout has occured, and the server must, in general, be doing 'something else' at most stages of its execution. The best solution I can think of is one where the server is given the opportunity to check for timeout expiry at convenient stages during its execution. In essence, we have the familiar 'service loop', with a delay statement whose tail performs the timeout checks and then does some work. Provided the delay is reasonably small, and each quantum of work is also reasonably quick, we get roughly the necessary behaviour. (Maybe too rough for some hard RT situations.) The server ticks round and round the loop, doing a bit of work and a bit of administration each iteration. My suggested (bare bones) solution makes use of a bank of buffers to contain the results of the server's work. These are protected objects, so each client can wait on a separate buffer, against its own timeout period, to get the result of its enquiry. The server task puts the results of its work into the buffers; it checks to see whether a client has given up and gone home, in which it (sensibly!) stops doing any more work for the client (but is able to continue undisturbed doing work for other clients). Depending on the exact details of your application, your mileage may significantly vary. === package Sampling_Management is type Sampling_Bottle is ...; subtype Sampling_Timeout is Duration range 0.0 .. 60.0; Sampling_Failure: exception; -- raised upon timeout expiry procedure Obtain_Sample (Bottle: in out Sampling_Bottle; Timeout: in Sampling_Timeout); ... end; ... package body Sampling_Management is Server_Heartbeat: constant Duration := 0.001; -- one millisecond type Buffer_Status is (Available, Pending_Sampling, Awaiting_Checkout); protected type Bottle_Buffer is entry Check_Out (Bottle: out Sampling_Bottle); procedure Cancel; private Result: Sampling_Bottle; Status: Buffer_Status := Available; end; type Buffer_Number is range 1..100; Buffers: array (Buffer_Number) of Bottle_Buffer; ... task Sampler_Task is entry Initiate_Sampling (Buffer: out Buffer_Number); ... end; ... procedure Obtain_Sample (Bottle: out Sampling_Bottle; Timeout: in Sampling_Timeout) is B: Buffer_Number; begin Sampler_Task.Initiate_Sampling(B); select Buffers(B).Check_Out(Bottle); or delay Timeout; Buffers(B).Cancel; raise Sampling_Failure; end select; end Obtain_Sample; ... protected body Bottle_Buffer is entry Check_Out (Bottle: out Sampling_Bottle) when Status /= Pending_Sampling is begin if Status /= Awaiting_Checkout then raise ...; end if; Bottle := Result; Status := Available; end; procedure Cancel is begin if Status = Available then raise ...; end if; Status := Available; end; end; ... task body Sampler_Task is ... begin loop select accept Initiate_Sampling (Buffer: out Buffer_Number) do ... -- allocate new buffer and assign number to Buffer end; or ... or delay Server_Heartbeat; -- Test for buffers whose client has timed out -- (its status will have changed to Available), -- and stop doing work for them: ... -- Do one quantum of work (unless there are no -- clients currently requiring work): ... end select; end loop; ... end Sampler_Task; ... end Sampling_Management; === Not elegant, of course, but practicable. I think there are quite a lot of design issues tangled up in this problem, some of them rather complex. -- Nick Roberts