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,FREEMAIL_FROM, LOTS_OF_MONEY autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,6f69b1cf0f02b9ac X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 2001-01-14 17:04:06 PST Path: supernews.google.com!sn-xit-03!supernews.com!freenix!oleane.net!oleane!fr.clara.net!heighliner.fr.clara.net!news.tele.dk!130.133.1.3!fu-berlin.de!uni-berlin.de!ppp-4-183.5800-7.access.uk.worldonline.COM!not-for-mail From: "Nick Roberts" Newsgroups: comp.lang.ada Subject: Re: How can I avoid Using a Semaphore? Date: Mon, 15 Jan 2001 01:06:08 -0000 Message-ID: <93ti8b$bjpps$1@ID-25716.news.dfncis.de> References: NNTP-Posting-Host: ppp-4-183.5800-7.access.uk.worldonline.com (62.64.161.183) X-Trace: fu-berlin.de 979520589 12183356 62.64.161.183 (16 [25716]) X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 5.50.4133.2400 X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4133.2400 Xref: supernews.google.com comp.lang.ada:4012 Date: 2001-01-15T01:06:08+00:00 List-Id: Please find attached my first quick attempt at a slightly neater solution. It's untested, so don't say I didn't warn you! The essential idea is that the task reading the socket does something like this: loop get length of buffer call Create to allocate a buffer in the queue (and in memory) read data into buffer call Commit to allow other tasks to obtain the buffer end loop Each task handling messages does the following: loop call Obtain to get an unprocessed buffer process the buffer as required call Delete to release the buffer (from the queue and memory) end loop Does this vaguely cut it? I use the trick of passing out a 'token' from Create and Obtain, which is passed into Commit or Delete to identify the buffer in the queue. Create and Obtain are both entries: Create blocks whilst the queue is full; Obtain blocks whilst there are no buffers in the queue awaiting processing. There can be any number of message-handling tasks, as they will be arbitrated between properly by their calls to Obtain. Of course, the call to Commit is very like clearing a semaphore to permit the second phase of processing of a buffer. Now I come to think of it, buffers are obtained from the queue in no particular order, so 'queue' is the wrong term, really. Perhaps Protected_Array_Queueing isn't really the right name for this package. Maybe Buffer_Pooling or Buffer_Distribution would be better. (Or Grab_Bag? ;-) -- Nick Roberts http://www.AdaOS.org "DuckE" wrote in message news:cd%76.260429$U46.8278617@news1.sttls1.wa.home.com... > I have an application that receives a streams of data from TCP/IP sockets. > The stream of data is separated into "packets" each beginning with a 32 bit > length value. > ... ===== -- (c) 2000 Nicholas James Roberts -- All rights in this work are hereby granted into the PUBLIC DOMAIN -- by the author. The author asserts his moral rights over this work. generic type Datum_Type is private; package Protected_Array_Queueing is type Data_Array is array (Positive range <>) of Datum_Type; type Array_Access is access Data_Array; type Buffer_Token is private; -- Convenience declarations: type Array_Access_Array is array (Positive range <>) of Array_Access; type Boolean_Array is array (Positive range <>) of Boolean; protected type Buffer_Queue (Capacity: Natural) is entry Create (Length: in Natural; Token: out Buffer_Token; Buffer: out Array_Access); procedure Commit (Token: in Buffer_Token); entry Obtain (Token: out Buffer_Token; Buffer: out Array_Access); procedure Delete (Token: in Buffer_Token); procedure Reset; private Queue: Array_Access_Array(1..Capacity); Allocated: Boolean_Array(1..Capacity) := (others => False); Available: Boolean_Array(1..Capacity) := (others => False); Create_Here: Positive := 1; Obtain_Here: Positive := 1; Alloc_Count: Natural := 0; Avail_Count: Natural := 0; end Buffer_Queue; Invalid_Token: exception; private type Buffer_Token is new Positive; end Protected_Array_Queueing; ===== with Unchecked_Deallocation; package body Protected_Array_Queueing is procedure Free is new Unchecked_Deallocation(Data_Array,Array_Access); protected body Buffer_Queue is function Next (Here: in Positive) return Positive is begin if Here = Capacity then return 1; else return Here+1; end if; end Next; entry Create (Length: in Natural; Token: out Buffer_Token; Buffer: out Array_Access) when Alloc_Count < Capacity is begin while Allocated(Create_Here) loop Create_Here := Next(Create_Here); end loop; Token := Buffer_Token(Create_Here); Buffer := new Data_Array(1..Length); Queue(Create_Here) := Buffer; Alloc_Count := Alloc_Count+1; Allocated(Create_Here) := True; Available(Create_Here) := False; end Create; procedure Commit (Token: in Buffer_Token) is Commit_Here: Positive range 1..Capacity := Positive(Token); begin if not Allocated(Commit_Here) then raise Invalid_Token; end if; if not Available(Commit_Here) then Available(Commit_Here) := True; Avail_Count := Avail_Count+1; end if; end Commit; entry Obtain (Token: out Buffer_Token; Buffer: out Array_Access) when Avail_Count > 0 is begin while not Available(Obtain_Here) loop Obtain_Here := Next(Obtain_Here); end loop; Token := Buffer_Token(Obtain_Here); Buffer := Queue(Obtain_Here); Avail_Count := Avail_Count-1; Available(Obtain_Here) := False; end Obtain; procedure Delete (Token: in Buffer_Token) is Delete_Here: Positive range 1..Capacity := Positive(Token); begin if not Allocated(Delete_Here) then raise Invalid_Token; end if; Free(Queue(Delete_Here)); -- Queue(Delete_Here) := null; if Available(Delete_Here) then Avail_Count := Avail_Count-1; end if; Allocated(Delete_Here) := False; Alloc_Count := Alloc_Count-1; end Delete; procedure Reset is begin for i in 1..Capacity loop Free(Queue(i)); -- Queue(i) := null; end loop; Allocated := (others => False); Available := (others => False); Create_Here := 1; -- not really necessary Obtain_Here := 1; -- not really necessary Alloc_Count := 0; Avail_Count := 0; end Reset; end Buffer_Queue; end Protected_Array_Queueing;