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=-0.3 required=5.0 tests=BAYES_00, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 X-Google-Thread: 103376,d495ab2e69ad1962 X-Google-Attributes: gid103376,public,usenet X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news2.google.com!news3.google.com!feeder1-2.proxad.net!proxad.net!feeder1-1.proxad.net!ecngs!feeder2.ecngs.de!newsfeed.freenet.de!newsfeed01.chello.at!newsfeed.arcor.de!newsspool1.arcor-online.net!news.arcor.de.POSTED!not-for-mail From: "Dmitry A. Kazakov" Subject: Re: Ravenscar-compliant bounded buffer Newsgroups: comp.lang.ada User-Agent: 40tude_Dialog/2.0.15.1 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Reply-To: mailbox@dmitry-kazakov.de Organization: cbb software GmbH References: <1188914005.607732.277400@57g2000hsv.googlegroups.com> Date: Wed, 5 Sep 2007 09:46:39 +0200 Message-ID: <1xnpics66h1c9.js3eyt5bsx1e.dlg@40tude.net> NNTP-Posting-Date: 05 Sep 2007 09:46:10 CEST NNTP-Posting-Host: b636fed2.newsspool1.arcor-online.net X-Trace: DXC=@4UW4b\a9\_@>[RYkFXOIPic==]BZ:af^4Fo<]lROoRQ4nDHegD_]RUF4B8C3n6W8PDNcfSJ;bb[UIRnRBaCd On Tue, 4 Sep 2007 20:00:13 -0700, Steve wrote: > While I don't know much about the Ravenscar profile (other than what it is) > I am famialar with the use of protected types. > > The sample code is a good illustration of "abstraction inversion". I know > this because I posted similar code on this group several years ago and that > is how it was described. > > The code uses a high level abstraction "protected type" to create a low leve > abstraction "Binary_Semaphore". The code uses two semaphores to restrict > access to the bounded buffer. In this simple example it is easy to follow, > but in a more complex example pairing Acquire's and Release's can be a > chore. That is because of the Ravenscar limitation of one entry per protected object. The solution Maciej presented is based on splitting one protected object of two entries into two, each controlling access to its end of FIFO. Protected objects don't compose so the result. Worse it will be with FIFO size > 1. Here is a solution based on event + requeue rather than mutexes. Requeue is implicit of course, because Ravenscar forbids requeue statements. pragma Profile (Ravenscar); package Bounded_Buffer is subtype Multiple is Positive range 2..Positive'Last; type Buffer_Type (Size : Multiple) is limited private; procedure Get (Buffer : in out Buffer_Type; Item : out Integer); procedure Put (Buffer : in out Buffer_Type; Item : Integer); private type Storage_Data is array (Positive range <>) of Integer; protected type Buffer_Type (Size : Multiple) is entry Wait; procedure Get (Item : out Integer; Success : out Boolean); procedure Put (Item : Integer; Success : out Boolean); private Storage : Storage_Data (1..Size); First_In : Positive := 1; First_Out : Positive := 1; Empty : Boolean := True; Free : Boolean := False; -- In /= Out explicitly end Buffer_Type; end Bounded_Buffer; Notes: 1. First_In /= First_Out is a complex barrier, so we need it explicitly as Free. 2. With buffer size 1 this implementation would do busy waiting, for this reason the minimal buffer size is 2. package body Bounded_Buffer is protected body Buffer_Type is entry Wait when Free is begin null; end Wait; procedure Put (Item : in Integer; Success : out Boolean) is begin if Free or else Empty then Storage (First_Out) := Item; if First_Out = Size then First_Out := 1; else First_Out := First_Out + 1; end if; Free := First_Out /= First_In; Empty := False; Success := True; else Success := False; end if; end Put; procedure Get (Item : out Integer; Success : out Boolean) is begin if Free or else not Empty then Item := Storage (First_In); if First_In = Size then First_In := 1; else First_In := First_In + 1; end if; Free := First_Out /= First_In; Empty := not Free; Success := True; else Success := False; end if; end Get; end Buffer_Type; procedure Put (Buffer : in out Buffer_Type; Item : in Integer) is Success : Boolean; begin loop Buffer.Put (Item, Success); exit when Success; Buffer.Wait; end loop; end Put; procedure Get (Buffer : in out Buffer_Type; Item : out Integer) is Success : Boolean; begin loop Buffer.Get (Item, Success); exit when Success; Buffer.Wait; end loop; end Get; end Bounded_Buffer; ----------------------- P.S. As a general note. This object might interesting as an exercise, but not likely needed. In a real application it would be strange to expect multiple consumers taking integers out of buffer in some unpredictable order. Normally, it is so that either there is one producer and one or many consumers (like in distribution of jobs), or else there is many producers and one consumer (like writing to log file). This might sufficiently simplify the design. Yet another variant is multiple consumers receiving whole waveform of integers put to the buffer (broadcasting). This would be more difficult. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de