* RE: How can I avoid Using a Semaphore? (long)
@ 2001-02-08 23:42 Beard, Frank
0 siblings, 0 replies; 8+ messages in thread
From: Beard, Frank @ 2001-02-08 23:42 UTC (permalink / raw)
To: 'comp.lang.ada@ada.eu.org'
It wasn't a conclusion, it was a question (hence
the question mark ('?') at the end of the sentence).
It was supposed to mean I was puzzled that I/O was
not potentially blocking. I thought I new it was
potentially blocking, but when I read 9.5.1 I quit
reading at 17 for some reason. I guess because it
started talking about bounded errors. For some
reason, it seemed like the next paragraph started
a new section.
I don't know, my brain was failing me. I was tired.
But thanks for responding. I would have gotten around
to re-reading it eventually, and hopefully I would
have noticed it the next time.
Thanks
Frank
-----Original Message-----
From: Robert Dewar [mailto:dewar@gnat.com]
> So, according to section 9.5.1, doing I/O during a protected
> operation is NOT potentially blocking?
How do you come to that odd (and wrong) conclusion :-)
^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: How can I avoid Using a Semaphore? (long) @ 2001-02-07 21:55 Beard, Frank 0 siblings, 0 replies; 8+ messages in thread From: Beard, Frank @ 2001-02-07 21:55 UTC (permalink / raw) To: 'comp.lang.ada@ada.eu.org' So, according to section 9.5.1, doing I/O during a protected operation is NOT potentially blocking? For example, would it be permissible to do the following: protected body Protected_Something is procedure Do_Something (status : out Status_Type) is begin Ada.Text_Io.Open(file => file, mode => Ada.Text_Io.IN_FILE, name => "status_file", form => ""); Status_Io.Get(file => file, item => status); Ada.Text_Io.Close(file); end Do_Something; end Protected_Something; Frank -----Original Message----- From: DuckE [mailto:nospam_steved94@home.com] Sent: Friday, February 02, 2001 10:01 PM To: comp.lang.ada@ada.eu.org Subject: Re: How can I avoid Using a Semaphore? (long) On reviewing 9.5.1 of the RM I see that this is definitely NOT the case. In 9.5.1 the specific operations that are considered potentially blocking are listed. ^ permalink raw reply [flat|nested] 8+ messages in thread
* How can I avoid Using a Semaphore? (long) @ 2001-01-13 16:18 DuckE 2001-01-22 16:51 ` mark_lundquist 2001-02-02 21:38 ` Niklas Holsti 0 siblings, 2 replies; 8+ messages in thread From: DuckE @ 2001-01-13 16:18 UTC (permalink / raw) 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. For each of these sockets I have a task that receives the length, then gets a pre-allocated data buffer that is large enough to hold the data, receives the data into the data buffer, and then puts a reference to the buffer into a queue for processing by other tasks. Pseudo code for the main loop for the receive task is something like: Loop Receive 4 bytes of data from the socket Convert the 4 bytes to an integer value Get a buffer from available buffers that is large enough to hold remaining data in message Receive remaining part of message into buffer Queue the message for processing by other tasks End Loop To avoid memory leaks I am using a controlled type with reference counting to implement my data buffer. Since multiple threads may simultaneously have access to the buffer, I use a protected type for reference counting. Since I am using a protected type for reference counting, I cannot assign packets within a protected type (to implement queue's of packets for instance) since these assignments would be attempting to do a protected operation within a protected type. I have worked around this using a semaphore (the semaphore is created using a protected type) around the assignment of packets: lock semaphore assign packet unlock semaphore This technique has proven reliable in production code, but I don't find it to be very "clean". Suggestions? Here is a subset of my packet implementation: package NPUnetworkPacketUtil is type aPacketNPU is private; private protected type aRefCounterNPU is procedure PlaseHoldNPU; procedure ReleaseHoldNPU( lastHoldNPU : out boolean ); private referenceCountNPU : Natural := 0; end aRefCounterNPU; type aPacketBufNPU( bufSizeNPU : Positive ); type aPacketBUfPtrNPU is accesss all aPacketBufNPU; type aPacketNPU is new Ada.Finalization.Controlled with record packetBufPtrNPU : aPacketBufPtrNPU; end record; procedure Initialize( object : in out aPacketNPU ); procedure Adjust( object : in out aPacketNPU ); procedure Finalize( object : in out aPacketNPU ); type aPacketBufNPU( bufSizeNPU : Positive ) is limited record dataBufferNPU : aliased aDataArrayNPU( 1 .. bufSizeNPU ); holdLockNPU : aRefCounterNPU; end record; end NPUnetworkPacketUtil ; package body NPUnetworkPacketUtil is protected body aRefCounterNPU is procedure PlaceHoldNPU is begin referenceCountNPU := referenceCountNPU + 1; end PlaceHoldNPU; procedure ReleaseHoldNPU( lastHoldNPU : out boolean ) is begin referenceCountNPU := referenceCountNPU - 1; lastHoldNPU := referenceCountNPU = 0; end ReleaseHoldNPU; end aRefCounterNPU; procedure Initialize( object : in out aPacketNPU ) is begin object.packetBufPtrNPU := null; end Initialize; procedure Adjust( object : in out aPacketNPU ) is begin if object.packetBufPtrNPU /= null then packetBufPtrNPU.holdLockNPU.PlaceHoldNPU; end if; end Adjust; procedure Finalize( object : in out aPacketNPU ) is lastHold : boolean; begin if object.packetBufPtrNPU /= null then packetBufNPU.holdLockNPU.ReleaseHoldNPU( lastHold ); if lastHold then -- Take action to put buffer in the free pool end if; end if; end Finalize; end NPUnetworkPacketUtil; Thank's in advance, SteveD ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: How can I avoid Using a Semaphore? (long) 2001-01-13 16:18 DuckE @ 2001-01-22 16:51 ` mark_lundquist 2001-01-23 6:02 ` DuckE 2001-02-02 21:38 ` Niklas Holsti 1 sibling, 1 reply; 8+ messages in thread From: mark_lundquist @ 2001-01-22 16:51 UTC (permalink / raw) Hey Steve, I'd like to take up your original question: "How can I avoid using a semaphore?" In article <cd%76.260429$U46.8278617@news1.sttls1.wa.home.com>, "DuckE" <nospam_steved94@home.com> wrote: > > To avoid memory leaks I am using a controlled type with reference counting > to implement my data buffer. Since multiple threads may simultaneously have > access to the buffer, I use a protected type for reference counting. > > Since I am using a protected type for reference counting, I cannot assign > packets within a protected type (to implement queue's of packets for > instance) since these assignments would be attempting to do a protected > operation within a protected type. I don't get it! Can you explain that? Are you talking about the "potentially blocking" rule? I don't see how the scenario you described would run afoul of that rule, and I couldn't find anything in your example code to help me understand what you meant... > > I have worked around this using a semaphore (the semaphore is created using > a protected type) around the assignment of packets: > > lock semaphore > assign packet > unlock semaphore I didn't see anything like that in your example -- it looked like you were using your Mutex type (or aMutex or whatever) to protect your free block lists. So help me understand more about this semaphore problem... In the meantime, a couple of notes: 1) You've said you want to avoid heap allocation -- is that for performance reasons? If so, do you know for sure that heap allocation is going to cause you to miss deadlines or cause a performance bottleneck? If you don't know for sure, you might just go ahead and write it using heap allocation and without all this extra complexity. Then, if that turns out to be not good enough, you can always implement your own allocation scheme (and the right way to encapsulate that is probably with your own Storage_Pool type -- it's easy and direct, no "magic" to worry about). 2) Also if you care about performance, implementing a mutex as a protected record is generally a case of "abstraction inversion" with an attendant performance penalty -- my guess is that that's going to hit you harder than heap allocation would. The Ada runtime is implementing protected records on top of mutexes and condition variables and stuff provided by the OS, and it's probably doing all kinds of checks for pending aborts and other stuff that it has to do, and all you want is a mutex! You might look into using the OS-supplied mutexes directly, *if* it turns out that's what you really need (needing locking to be primitive is often a red flag that some part of the design is "inside out"). 3) You have an array of free block lists, and a "parallel" array of mutexes associated with the free block lists. Doesn't that mean that you really want a mutex to be part of a free block list? 4) Just a style point here, but to me using Interfaces.C.Char to represent a byte or octet or whatever you want to call it, seems a little weird. I like to think that Interfaces.C is for interfacing to C. A better choice might be Interfaces.Unsigned_8. Anyway, hope you give some more detail about the semaphore issue... Best Regards, Mark Lundquist P.S. Your identifier style sucks. (Why mince words? :-) :-) :-) Sent via Deja.com http://www.deja.com/ ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: How can I avoid Using a Semaphore? (long) 2001-01-22 16:51 ` mark_lundquist @ 2001-01-23 6:02 ` DuckE 2001-02-02 22:18 ` Mark Lundquist 0 siblings, 1 reply; 8+ messages in thread From: DuckE @ 2001-01-23 6:02 UTC (permalink / raw) > > To avoid memory leaks I am using a controlled type with reference counting > > to implement my data buffer. Since multiple threads may simultaneously have > > access to the buffer, I use a protected type for reference counting. > > > > Since I am using a protected type for reference counting, I cannot assign > > packets within a protected type (to implement queue's of packets for > > instance) since these assignments would be attempting to do a protected > > operation within a protected type. > > I don't get it! Can you explain that? Are you talking about > the "potentially blocking" rule? I don't see how the scenario you > described would run afoul of that rule, and I couldn't find anything in > your example code to help me understand what you meant... This is exactly the rule I'm talking about. I have defined my protected type for reference counting (aRefCounterNPU) contained in the packet buffer (aPacketBufNPU). I put my reference counter inside of a protected type since different tasks may concurrently have references to the same packet buffer and may release them asynchronously. aPacketNPU is a controlled type containing a reference to a packet buffer (aPacketBufNPU) that invokes the "PlaceHoldNPU" and "ReleaseHoldNPU" procedures durning the "Adjust" and "Finalize" routines as packets are assigned and finalized. If it were permitted, I would use a protected object to contain my pool of available packets. Something like: PROTECTED TYPE Buffer_Manager IS FUNCTION New_Packet( packetSize : Positive ) RETURN aPacketNPU; PROCEDURE Free_Packet( packet : in out aPacketNPU ); END Buffer_Manager; But in implementing this buffer manager I would be performing assignments of packet buffers inside the protected type, and thus violate the potentially blocking rule. Am I missing something here? > > > > > I have worked around this using a semaphore (the semaphore is created using > > a protected type) around the assignment of packets: > > > > lock semaphore > > assign packet > > unlock semaphore > > I didn't see anything like that in your example -- it looked like you > were using your Mutex type (or aMutex or whatever) to protect your free > block lists. > In my example the routine NewPacketNPU may be called on by different tasks in order to obtain new packets, so access to the free list must be protected. But since assignment of entries from the list requires placing a hold on the entries taken from the list, I run into the potentially blocking rule. That was my reasoning when I wrote the code. But now I'm starting to think that I may be able to re-arrange things such that the reference count is adjusted outside of accessing the free lists, which would solve my problem. I'll have to look at this some more... I didn't include it in my example, but I run into a similar difficulty when I go to put packets into a queue. It seems that introducing that reference counter in the controlled type makes things tricky all around. > So help me understand more about this semaphore problem... > > In the meantime, a couple of notes: > > 1) You've said you want to avoid heap allocation -- is that for > performance reasons? If so, do you know for sure that heap allocation > is going to cause you to miss deadlines or cause a performance > bottleneck? If you don't know for sure, you might just go ahead and > write it using heap allocation and without all this extra complexity. > Then, if that turns out to be not good enough, you can always implement > your own allocation scheme (and the right way to encapsulate that is > probably with your own Storage_Pool type -- it's easy and direct, > no "magic" to worry about). This code is in a library module that is common to several pieces of software. It is one of those cases where adding a small degree of complexity may benefit the performance of several applications. > > 2) Also if you care about performance, implementing a mutex as a > protected record is generally a case of "abstraction inversion" with an > attendant performance penalty -- my guess is that that's going to hit > you harder than heap allocation would. The Ada runtime is implementing > protected records on top of mutexes and condition variables and stuff > provided by the OS, and it's probably doing all kinds of checks for > pending aborts and other stuff that it has to do, and all you want is a > mutex! You might look into using the OS-supplied mutexes directly, > *if* it turns out that's what you really need (needing locking to be > primitive is often a red flag that some part of the design is "inside > out"). That's why I posted this inquiry in the first place. > > 3) You have an array of free block lists, and a "parallel" array of > mutexes associated with the free block lists. Doesn't that mean that > you really want a mutex to be part of a free block list? > Perhaps, but as you'll notice I initialize my free block lists using: availablePacketTable : anAvailablePacketTable := ( 1 => ( NULL, 2**5, 0, 64 ), -- 32 2 => ( NULL, 2**6, 0, 32 ), -- 64 3 => ( NULL, 2**7, 0, 32 ), -- 128 4 => ( NULL, 2**8, 0, 16 ), -- 256 5 => ( NULL, 2**9, 0, 16 ), -- 512 6 => ( NULL, 2**10, 0, 16 ), -- 1024 7 => ( NULL, 2**11, 0, 16 ), -- 2048 8 => ( NULL, 2**12, 0, 16 ), -- 4096 9 => ( NULL, 2**13, 0, 16 ), -- 8192 10 => ( NULL, 2**14, 0, 16 ), -- 16384 11 => ( NULL, 2**15, 0, 16 ), -- 32768 12 => ( NULL, 2**16, 0, 16 ), -- 65536 13 => ( NULL, 2**17, 0, 16 ), -- 131072 14 => ( NULL, 2**18, 0, 16 ), -- 262144 15 => ( NULL, 2**19, 0, 16 ), -- 524288 16 => ( NULL, 2**20, 0, 16 ) -- 1048576 ); If I made the "mutex" a part of the record, how would it appear in this initializer? > 4) Just a style point here, but to me using Interfaces.C.Char to > represent a byte or octet or whatever you want to call it, seems a > little weird. I like to think that Interfaces.C is for interfacing to > C. A better choice might be Interfaces.Unsigned_8. As I recall this is just mating with the types used by the Win32Ada bindings. > > Anyway, hope you give some more detail about the semaphore issue... > > Best Regards, > Mark Lundquist > > P.S. Your identifier style sucks. (Why mince words? :-) :-) :-) Any style of code with which you are unfamiliar "sucks". Every time someone new comes to our group we hear the same comment. Usually it takes less than 2 weeks and they never know how they did without it. Thanks for your response. SteveD > > > Sent via Deja.com > http://www.deja.com/ ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: How can I avoid Using a Semaphore? (long) 2001-01-23 6:02 ` DuckE @ 2001-02-02 22:18 ` Mark Lundquist 2001-02-03 3:01 ` DuckE 0 siblings, 1 reply; 8+ messages in thread From: Mark Lundquist @ 2001-02-02 22:18 UTC (permalink / raw) Steve, sorry to take so long getting back to you. You probably have it all figured out by now... DuckE <nospam_steved94@home.com> wrote in message news:b89b6.298508$U46.9559869@news1.sttls1.wa.home.com... > >[mark wrote] > > I don't get it! Can you explain that? Are you talking about > > the "potentially blocking" rule? I don't see how the scenario you > > described would run afoul of that rule, and I couldn't find anything in > > your example code to help me understand what you meant... > > This is exactly the rule I'm talking about. Entries are potentially blocking, but protected subprograms are not. You don't need entries in your protected reference count, right? So you should be OK? > > > > 3) You have an array of free block lists, and a "parallel" array of > > mutexes associated with the free block lists. Doesn't that mean that > > you really want a mutex to be part of a free block list? > > > > Perhaps, but as you'll notice I initialize my free block lists using: > > availablePacketTable : anAvailablePacketTable := > ( 1 => ( NULL, 2**5, 0, 64 ), -- 32 > 2 => ( NULL, 2**6, 0, 32 ), -- 64 > 3 => ( NULL, 2**7, 0, 32 ), -- 128 > > If I made the "mutex" a part of the record, how would it appear in this > initializer? Well, it would look like something like: availablePacketTable : anAvailablePacketTable := ( 1 => Create_Packet_Table_Entry (Size => 2**5, Count => 64), 2 => Create_Packet_Table_Entry (Size => 2**6, Count => 32), . . . ); Best, Mark ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: How can I avoid Using a Semaphore? (long) 2001-02-02 22:18 ` Mark Lundquist @ 2001-02-03 3:01 ` DuckE 0 siblings, 0 replies; 8+ messages in thread From: DuckE @ 2001-02-03 3:01 UTC (permalink / raw) "Mark Lundquist" <mark@rational.com> wrote in message news:95fbn7$njb$1@usenet.rational.com... > Steve, sorry to take so long getting back to you. You probably have it all > figured out by now... > > DuckE <nospam_steved94@home.com> wrote in message > news:b89b6.298508$U46.9559869@news1.sttls1.wa.home.com... > > > > >[mark wrote] > > > I don't get it! Can you explain that? Are you talking about > > > the "potentially blocking" rule? I don't see how the scenario you > > > described would run afoul of that rule, and I couldn't find anything in > > > your example code to help me understand what you meant... > > > > This is exactly the rule I'm talking about. > > Entries are potentially blocking, but protected subprograms are not. You > don't > need entries in your protected reference count, right? So you should be OK? > Alas, I have been working under a misconception.... When I read: "During a protected action, it is a bounded error to invoke an operation that is potentially blocking", I incorrectly assumed this included anything that required mutual exclusion (such as protected procedures). On reviewing 9.5.1 of the RM I see that this is definitely NOT the case. In 9.5.1 the specific operations that are considered potentially blocking are listed. I re-wrote my packet buffer routine without the use of a semaphore. I was still somewhat concerned about protected operations performed within the controlled operations of my "Packet", but I now realize that there is no problem in this area. SteveD ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: How can I avoid Using a Semaphore? (long) 2001-01-13 16:18 DuckE 2001-01-22 16:51 ` mark_lundquist @ 2001-02-02 21:38 ` Niklas Holsti 1 sibling, 0 replies; 8+ messages in thread From: Niklas Holsti @ 2001-02-02 21:38 UTC (permalink / raw) Cc: Niklas Holsti DuckE wrote: > > I have an application that receives a streams of data from TCP/IP sockets. [ snip ] > > To avoid memory leaks I am using a controlled type with reference counting > to implement my data buffer. Since multiple threads may simultaneously have > access to the buffer, I use a protected type for reference counting. > > Since I am using a protected type for reference counting, I cannot assign > packets within a protected type (to implement queue's of packets for > instance) since these assignments would be attempting to do a protected > operation within a protected type. As I understand the LRM, you are allowed to use *other* protected objects from within a protected type. By LRM 9.5.1(15), a call on a protected subprogram is only considered potentially blocking if it is an "external" call and has the same target object as the action that performs the call. In your case, the caller (queue) and callee (reference counter) would be actions of different protected types, so the call would not be potentially blocking. Niklas Holsti Working at but not speaking for Space Systems Finland ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2001-02-08 23:42 UTC | newest] Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2001-02-08 23:42 How can I avoid Using a Semaphore? (long) Beard, Frank -- strict thread matches above, loose matches on Subject: below -- 2001-02-07 21:55 Beard, Frank 2001-01-13 16:18 DuckE 2001-01-22 16:51 ` mark_lundquist 2001-01-23 6:02 ` DuckE 2001-02-02 22:18 ` Mark Lundquist 2001-02-03 3:01 ` DuckE 2001-02-02 21:38 ` Niklas Holsti
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox