comp.lang.ada
 help / color / mirror / Atom feed
* How can I avoid Using a Semaphore? (long)
@ 2001-01-13 16:18 DuckE
  2001-01-15  1:06 ` How can I avoid Using a Semaphore? Nick Roberts
                   ` (2 more replies)
  0 siblings, 3 replies; 34+ 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] 34+ messages in thread

* Re: How can I avoid Using a Semaphore?
  2001-01-13 16:18 How can I avoid Using a Semaphore? (long) DuckE
@ 2001-01-15  1:06 ` Nick Roberts
  2001-01-15  3:17   ` Robert Dewar
  2001-01-16  3:53   ` DuckE
  2001-01-22 16:51 ` How can I avoid Using a Semaphore? (long) mark_lundquist
  2001-02-02 21:38 ` Niklas Holsti
  2 siblings, 2 replies; 34+ messages in thread
From: Nick Roberts @ 2001-01-15  1:06 UTC (permalink / raw)


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" <nospam_steved94@home.com> 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;






^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore?
  2001-01-15  1:06 ` How can I avoid Using a Semaphore? Nick Roberts
@ 2001-01-15  3:17   ` Robert Dewar
  2001-01-16  3:53   ` DuckE
  1 sibling, 0 replies; 34+ messages in thread
From: Robert Dewar @ 2001-01-15  3:17 UTC (permalink / raw)


In article <93ti8b$bjpps$1@ID-25716.news.dfncis.de>,
  "Nick Roberts" <nickroberts@callnetuk.com> wrote:
> -- (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.

This is about the most confusing copyright notice I have seen.
The first line is straightforward, and seems to be asserting
a copyright interest.

The second statement contradicts this by saying it is in the
public domain. The only way something is in the public domain
is if the author specificially give up the copyright. Once
something is in the public domain, the author no longer has
any rights over it.

The third sentence may have some significance in the EU, but
in the US, it hs meaningless. The only rights of an author are
those granted by congress under the copyright act. And we are
confused as to whether this work is copyrighted or not.

The best advice reacting to this notice is to assume that the
copyright is fully in effect, and that this work should not be
copied or otherwise infringed on. I am not sure that is the
intent, but no other interpretation is legally safe.

It all goes to show that in any case you should not trust the
notices you find in software units, the copyright status is not
formally affected by such notices in any case (though in a
court case, the existence of such a statement may be used as
evidence, for instance in this case, if someone does infringe
the copyright, then as a defendant, they could try to persaude
a jury that the work was indeed in the public domain, and if
the jury was convinced that would be that :-)


Sent via Deja.com
http://www.deja.com/



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore?
  2001-01-15  1:06 ` How can I avoid Using a Semaphore? Nick Roberts
  2001-01-15  3:17   ` Robert Dewar
@ 2001-01-16  3:53   ` DuckE
  2001-01-17 15:42     ` Nick Roberts
  1 sibling, 1 reply; 34+ messages in thread
From: DuckE @ 2001-01-16  3:53 UTC (permalink / raw)



"Nick Roberts" <nickroberts@callnetuk.com> wrote in message
news:93ti8b$bjpps$1@ID-25716.news.dfncis.de...
> 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?

No.  One of the things I'm attempting to avoid (which is perhaps creating
some difficulty) is dynamic allocation and deallocation at runtime.  Perhaps
I cut out too much implementation.

What you will find below is a more complete sample.  As you will see below I
set up a table containing packets of different sizes.  When a request is
made for a new packet "NewPacketNPU( size )" the list is searched for the
smallest available packet to meet the request.

To the user of this it's associated modules using packets is simple:

  packet := NewPacketNPU( maxPacketSize );
  PutNPU( packet, integerValue );
  PutNPU( packet, floatValue );
  FinishPacketNPU( packet );
  SendPacketTGM( service, packet );

With no concern of memory leaks.

SteveD


--  Network Packet Utility
--    This module contains routines for manipulating "network packets".
--    The network packet type "aPacketNPU" is limited private and defined
--    within this module.
--
--    Functions are provided to "Put" data to a packet and to "Get" data
--    from a packet.  A primative set of data types are defined with get
--    and put operations overloaded for each of these types.
--
--    A task safe data packet pool is also maintained by this module.
--
WITH Ada.Finalization;
WITH Interfaces.C;
WITH System;
WITH BDTbaseDataTypes;
 USE BDTbaseDataTypes;
PACKAGE NPUnetworkPacketUtil IS

  -- packetOverflowNPU is raised if there is an attempt to store more data
into
  -- a packet than the size of the buffer allows.
  -- packetUnderflowNPU is raised if there is an attempt to read past the
end
  -- of the packet.
  packetUnderflowNPU    : EXCEPTION;
  packetOverflowNPU     : EXCEPTION;
  noAvailablePacketsNPU : EXCEPTION;
  packetTooBigNPU       : EXCEPTION;

  -- In the TimberGrafx protocol each message is sent with a command code
  -- to a node address.
  SUBTYPE aCommandCodeNPU IS aUInt16NPU;

  TYPE aNodeAddressNPU IS PRIVATE;

  TYPE aPacketNPU IS PRIVATE;

  package C renames Interfaces.C;

  TYPE aDataArrayNPU IS ARRAY( Positive RANGE <> ) OF ALIASED C.Char;

  -- Gets a new packet from the available packets that is a size greater
than
  -- or equal to the size given by packetSizeNPU.
  -- The "get" operation places a "hold" on the entry.
  -- If no packets are available raises the exception: noAvailablePacketsNPU
  FUNCTION NewPacketNPU( packetSizeNPU : Natural ) RETURN aPacketNPU;

  -- Release a packet by assigning to Null
  FUNCTION NullPacketNPU RETURN aPacketNPU;

PRIVATE
  PROCEDURE ResetPacketToHeaderNPU( packetNPU : aPacketNPU );

  TYPE aNodeAddressNPU IS NEW aUInt16NPU;

  broadcastAddressNPU : CONSTANT aNodeAddressNPU := 16#FFFF#;
  routerAddressNPU    : CONSTANT aNodeAddressNPU := 0;

  PROTECTED TYPE aRefCounterNPU IS
    PROCEDURE PlaceHoldNPU;
    PROCEDURE ReleaseHoldNPU( lastHoldNPU : out BOOLEAN );
  PRIVATE
    referenceCountNPU : Natural := 0;
  END aRefCounterNPU;

--  NOTE: All references in the public portion of is module refer to packets
as if they
--  were all data.  Internally dataBufferNPU reserves headerLengthNPU bytes
at the beginning
--  of the data array for the header.

  headerLengthNPU      : CONSTANT := 8;  -- size of packet header

  TYPE aPacketBufNPU( bufSizeNPU : Positive );

  TYPE aPacketBufPtrNPU IS ACCESS 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); -- Buffered data
      nbBytesNPU    : Natural := 0;          -- Bytes currently in the
buffer
      positionNPU   : Positive := 1;         -- Position where next data is
to be stored
      nextPacketNPU : aPacketBufPtrNPU := NULL;  -- Pointer for keeping
buffers in a linked list
      holdLockNPU   : aRefCounterNPU;        -- Reference counter for the
packet buffer
      packetFinishedNPU : BOOLEAN := FALSE;  -- Packet has been finished,
for sending
    END RECORD;

END NPUnetworkPacketUtil;


WITH Interfaces.C;
WITH System;
WITH Unchecked_Conversion;
WITH Ada.Strings;
WITH Ada.Strings.Fixed;
WITH BDTbaseDataTypes;
 USE BDTbaseDataTypes;

PACKAGE BODY NPUnetworkPacketUtil IS
  PACKAGE Fixed RENAMES Ada.Strings.Fixed;
  PACKAGE Strings RENAMES Ada.Strings;

  --------------------------------------------------------------------------
------
  --
  -- The reference count is put inside a protected type to make it task
safe.
  --
  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;
  --------------------------------------------------------------------------
--------------
  --
  -- Keep a table of free packet lists.  All socket communications use these
packets
  -- The number of entries in each list may grow based on demand until the
limit is reached
  TYPE
    anAvailablePacketEntry IS
      RECORD
        packets        : aPacketBufPtrNPU := NULL;  -- Pointer to list of
unallocated packets of this size
        packetSize     : Natural;                   -- Size of packets in
this list
        nbAllocPackets : Natural;                   -- Nb of packets to
allocated of this size
        maxNbPackets   : Natural;                   -- Max nb of packets to
allocate of this size
      END RECORD;

  TYPE
    anAvailablePacketTable IS ARRAY( Positive RANGE <> ) OF
anAvailablePacketEntry;

  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
    );

  PROTECTED TYPE aMutex IS
    ENTRY LockMutex;
    PROCEDURE UnlockMutex;
  PRIVATE
    isLocked : BOOLEAN := FALSE;
  END aMutex;

  PROTECTED BODY aMutex IS
    ENTRY LockMutex WHEN NOT isLocked IS
    BEGIN
      isLocked := TRUE;
    END LockMutex;
    PROCEDURE UnlockMutex IS
    BEGIN
      isLocked := FALSE;
    END UnlockMutex;
  END aMutex;

  tableProtect : ARRAY ( availablePacketTable'RANGE ) OF aMutex;

  -- Gets a new packet from the available packets that is a size greater
than
  -- or equal to the size given by packetSizeNPU.
  -- The "get" operation places a "hold" on the entry.
  FUNCTION NewPacketNPU( packetSizeNPU : Natural ) RETURN aPacketNPU IS
    newPacket : aPacketNPU;
    retPtr : aPacketBufPtrNPU RENAMES newPacket.packetBufPtrNPU;
    actualSize : Natural := packetSizeNPU + headerLengthNPU;
  BEGIN
    retPtr := NULL;
    TableSearch:
    FOR ii IN availablePacketTable'RANGE LOOP
      DECLARE
        tableEntry : anAvailablePacketEntry RENAMES availablePacketTable(
ii );
      BEGIN
        IF tableEntry.packetSize > actualSize THEN
          tableProtect( ii ).LockMutex;
           IF tableEntry.packets /= NULL THEN
            retPtr := tableEntry.packets;
             tableEntry.packets := tableEntry.packets.nextPacketNPU;
             retPtr.nextPacketNPU := NULL;
             retPtr.holdLockNPU.PlaceHoldNPU;
           ELSIF tableEntry.nbAllocPackets < tableEntry.maxNbPackets THEN
             tableEntry.nbAllocPackets := tableEntry.nbAllocPackets + 1;
             retPtr := NEW aPacketBufNPU( tableEntry.packetSize );

             retPtr.holdLockNPU.PlaceHoldNPU;
           END IF;
           tableProtect( ii ).UnlockMutex;
           EXIT tableSearch;
        END IF;
      END;
    END LOOP tableSearch;
    IF retPtr /= NULL THEN
      RETURN newPacket;
    ELSE
      RAISE noAvailablePacketsNPU;
    END IF;
  END NewPacketNPU;

  -- Places an additional "hold" on an entry that was obtained using
  -- "NewPacketNPU"
  PROCEDURE HoldPacketBuf( packetBufNPU : aPacketBufPtrNPU ) IS
  BEGIN
    packetBufNPU.holdLockNPU.PlaceHoldNPU;
  END HoldPacketBuf;

  -- Removes the "hold" on an entry.  When all holds are removed the
  -- entry automatically returns to the free pool.
  PROCEDURE ReleasePacketBuf( packetBufNPU : in out aPacketBufPtrNPU ) IS
    lastHold : BOOLEAN;
  BEGIN
    IF packetBufNPU /= NULL THEN
     packetBufNPU.holdLockNPU.ReleaseHoldNPU( lastHold );
     IF lastHold THEN
       TableSearch:
      FOR ii IN availablePacketTable'RANGE LOOP
        DECLARE
          tableEntry : anAvailablePacketEntry RENAMES
availablePacketTable( ii );
        BEGIN
          IF tableEntry.packetSize = packetBufNPU.bufSizeNPU THEN
             tableProtect( ii ).LockMutex;
             packetBufNPU.nextPacketNPU := tableEntry.packets;
             tableEntry.packets := packetBufNPU;
             packetBufNPU := NULL;
           tableProtect( ii ).UnlockMutex;
             EXIT tableSearch;
          END IF;
        END;
      END LOOP tableSearch;
     END IF;
    END IF;
  END ReleasePacketBuf;

  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
      HoldPacketBuf( object.packetBufPtrNPU );
    END IF;
  END Adjust;

  PROCEDURE Finalize( object : in out aPacketNPU ) IS
  BEGIN
    IF object.packetBufPtrNPU /= NULL THEN
      ReleasePacketBuf( object.packetBufPtrNPU );
    END IF;
  END Finalize;

  FUNCTION NullPacketNPU RETURN aPacketNPU IS
    packet : aPacketNPU;
  BEGIN
    RETURN packet;
  END NullPacketNPU;

END NPUnetworkPacketUtil;







^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore?
  2001-01-16  3:53   ` DuckE
@ 2001-01-17 15:42     ` Nick Roberts
  2001-01-20 18:16       ` DuckE
  0 siblings, 1 reply; 34+ messages in thread
From: Nick Roberts @ 2001-01-17 15:42 UTC (permalink / raw)


Steve, what you're doing IS dynamic run-time allocation! The only difference
is that you are doing it yourself, rather than getting Ada (or its runtime
system) to do it for you.

In this case, the problem of buffer allocation is 'orthogonal' to the
problem of the synchronisation of tasks in passing data to one another
through a buffer queue (perhaps 'pool' would be a better name then 'queue').

If you need to replace the default Ada allocation system with one of your
own (e.g. for reasons of speed), you can do so by modifying my solution in
two ways:

(a) you can use "for Array_Access'Storage_Pool use My_Fast_Pool;" and then
implement your own storage pool, My_Fast_Pool, according to RM95 13.11;

(b) you can have a fixed-size byte array (preferably as a component inside
the protected type Buffer_Queue, I think), and allocate and deallocate bytes
within this array (doing so inside the protected entry Create and procedures
Delete and Reset, to prevent inter-task interference), perhaps using the
'binary chop' scheme you use at the moment.

As to writing data into the buffers (and then reading it back out), I'm
pretty certain you want to use streams, instead of doing all the hard work
yourself. See RM95 13.13.

I hope this helps. (Am I missing something?*)

PS: Purely out of idle curiosity, does your identifier style come from
Smalltalk? (Or Modula?) Also, have you considered using UDP instead of TCP?

--
Nick Roberts
http://www.AdaOS.org


*Yes I know, but am I missing something in Steve's problem?   ;-)






^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore?
  2001-01-17 15:42     ` Nick Roberts
@ 2001-01-20 18:16       ` DuckE
  2001-01-20 19:16         ` Robert Dewar
  2001-01-22  0:16         ` mark_lundquist
  0 siblings, 2 replies; 34+ messages in thread
From: DuckE @ 2001-01-20 18:16 UTC (permalink / raw)


"Nick Roberts" <nickroberts@callnetuk.com> wrote in message
news:94563n$cb6kp$1@ID-25716.news.dfncis.de...
> Steve, what you're doing IS dynamic run-time allocation! The only
difference
> is that you are doing it yourself, rather than getting Ada (or its runtime
> system) to do it for you.
>
> In this case, the problem of buffer allocation is 'orthogonal' to the
> problem of the synchronisation of tasks in passing data to one another
> through a buffer queue (perhaps 'pool' would be a better name then
'queue').
>

If I the data was only being referenced by one task at a time, I would
agree.  But to expand a little on my example, we have code that does
something like:

  packet := NewPacketNPU( 10000 );
  PutNPU( packet, value1 );
  PutNPU( packet, value2 );
  SendPacketTGM( port1, packet );
  SendPacketTGM( port2, packet );
  SendPacketTGM( port3, packet );

In this arrangement the packet is sent to three separate tasks, and may only
be released when all three are no longer referencing the data.

The reason I chose not to use Ada serialization, is that items are inserted
into the packet in "network byte order".  Unfortunately in Ada 95 the 'input
and 'output attributes are pre-defined for the built in data types, so I
have no control over byte ordering.  I know that GNAT works around this when
you use their DSA, but they do so by using a "special" version of the RTL
that makes ALL streams in network byte order.

In my opinion this is one of the weak points of Ada 95.  It would have been
better to not have the 'input and 'output pre-defined for built in types (as
a part of the language) but to include a package for defining these
attributes.  That way an arbitrary representation of built in types could be
used with streams when desired.

SteveD












^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore?
  2001-01-20 18:16       ` DuckE
@ 2001-01-20 19:16         ` Robert Dewar
  2001-01-21  1:28           ` DuckE
  2001-01-21 16:53           ` Nick Roberts
  2001-01-22  0:16         ` mark_lundquist
  1 sibling, 2 replies; 34+ messages in thread
From: Robert Dewar @ 2001-01-20 19:16 UTC (permalink / raw)


In article <0Cka6.290338$U46.9207275@news1.sttls1.wa.home.com>,
  "DuckE" <nospam_steved94@home.com> wrote:
> In my opinion this is one of the weak points of Ada 95.  It
> would have been better to not have the 'input and 'output
> pre-defined for built in types (as a part of the language)
> but to include a package for defining these
> attributes.  That way an arbitrary representation of built in
> types could be used with streams when desired.


I don't see your point here. Surely you are not arguing in
favor of REQUIRING people to define their own stream attributes
for types, that would be a huge pain for the most common use
of stream attributes.

There are two possibilities

1. You want to control stream behavior on a type by type basis.
This you can do perfectly fine, by just avoiding built in types
like Integer, which is good practice anyway, and then define
the stream attributes to work however you want.

2. You want to control stream attributes globally (as is
permitted in GNAT by replacing the System.Stream_Attributes
unit), but you seem to say in the same message that you do NOT
like the fact that in GNAT this approach results in the default
routines applying to everything.

It really seems like Ada 95 does EXACTLY the right think in the
terms you have layed out here, you will have to be a lot
clearer in making your acase that something is missing. Perhaps
you can give at least a sketch of what you would like to see.

From where I sit, it seems like your problem is reasonable,
and easily addressed with the current language features, and
i can't see any addition to these features which would be
helpful in this particular case.


Sent via Deja.com
http://www.deja.com/



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore?
  2001-01-20 19:16         ` Robert Dewar
@ 2001-01-21  1:28           ` DuckE
  2001-01-21 16:04             ` Robert Dewar
  2001-01-21 16:53           ` Nick Roberts
  1 sibling, 1 reply; 34+ messages in thread
From: DuckE @ 2001-01-21  1:28 UTC (permalink / raw)



"Robert Dewar" <robert_dewar@my-deja.com> wrote in message
news:94co6t$v27$1@nnrp1.deja.com...
> In article <0Cka6.290338$U46.9207275@news1.sttls1.wa.home.com>,
>   "DuckE" <nospam_steved94@home.com> wrote:
> > In my opinion this is one of the weak points of Ada 95.  It
> > would have been better to not have the 'input and 'output
> > pre-defined for built in types (as a part of the language)
> > but to include a package for defining these
> > attributes.  That way an arbitrary representation of built in
> > types could be used with streams when desired.
>
>
> I don't see your point here. Surely you are not arguing in
> favor of REQUIRING people to define their own stream attributes
> for types, that would be a huge pain for the most common use
> of stream attributes.

No I'm not in favor of requiring people to define their own stream
attributes.

>
> There are two possibilities
>
> 1. You want to control stream behavior on a type by type basis.
> This you can do perfectly fine, by just avoiding built in types
> like Integer, which is good practice anyway, and then define
> the stream attributes to work however you want.
>
> 2. You want to control stream attributes globally (as is
> permitted in GNAT by replacing the System.Stream_Attributes
> unit), but you seem to say in the same message that you do NOT
> like the fact that in GNAT this approach results in the default
> routines applying to everything.
>

I believe there's a third:

3. You want to control stream behavior on a type by type basis for all types
including built in types.  You also include a package containing streaming
definitions for built in types that may be included using a WITH statement.

This behavior would be more consistent with operation of functions like
"sin" and "cos" that are not pre-defined, but included in a standard
package.

> It really seems like Ada 95 does EXACTLY the right think in the
> terms you have layed out here, you will have to be a lot
> clearer in making your acase that something is missing. Perhaps
> you can give at least a sketch of what you would like to see.
>

Perhaps I would like to see something like:

package Ada.Streams.Built_In_Types is
  --
  --  Define 'Input, 'Output for built in types
  --
end Ada.Streams.Built_In_Types;

And then in my code I have the control to create:

package Steves_Streaming_For_Built_In_Types is
  --
  --  Define 'Input, 'Output for built in types
  --
end Steves_Streaming_For_Built_In_Types;

> From where I sit, it seems like your problem is reasonable,
> and easily addressed with the current language features, and
> i can't see any addition to these features which would be
> helpful in this particular case.
>

For me it's easier to just stay away from streaming.  For one thing, the
behavior is implementation dependent.  For another, I have been quite
effective at getting things done without it.

>
> Sent via Deja.com
> http://www.deja.com/





^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore?
  2001-01-21  1:28           ` DuckE
@ 2001-01-21 16:04             ` Robert Dewar
  2001-01-21 23:23               ` DuckE
  2001-01-22  0:35               ` Built-in types (was " mark_lundquist
  0 siblings, 2 replies; 34+ messages in thread
From: Robert Dewar @ 2001-01-21 16:04 UTC (permalink / raw)


In article <tXqa6.290632$U46.9271836@news1.sttls1.wa.home.com>,
  "DuckE" <nospam_steved94@home.com> wrote:

> 3. You want to control stream behavior on a type by type
> basis for all types including built in types.

I don't see the point in adding a rather complex feature to
the language whose only purpose is to encourage increased
usage of bulit in primitive types, when we generally want
to discourage such use. Carefully written Ada programs should
not use the built-in types in any case.


Sent via Deja.com
http://www.deja.com/



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore?
  2001-01-20 19:16         ` Robert Dewar
  2001-01-21  1:28           ` DuckE
@ 2001-01-21 16:53           ` Nick Roberts
  2001-01-21 18:24             ` Robert Dewar
  1 sibling, 1 reply; 34+ messages in thread
From: Nick Roberts @ 2001-01-21 16:53 UTC (permalink / raw)


I concur with Robert's comments on Ada's stream facilities.

I would have thought some companies which sell Ada compilers might
(depending on their clientele etc.) consider it a good idea to provide a
facility like GNAT's for changing all the default representations to the
network format, as well as (or by means of) providing something like
System.Stream_Attributes.

To solve your buffer synchronisation problem, Steve, please see the generic
package spec attached. The idea here is that the packet picking task(s)
does/do something like this:

   loop
      read the packet's length
      call Create to create a buffer of the correct length
      read the packet's data into the buffer
      call Dispatch to cause the buffer to be serviced
      (further calls to Dispatch on the buffer possible)
   end loop

Each servicing task does something like this:

   loop
      call Obtain to get a buffer that needs a specific service
      perform the service
      (calls to Dispatch possible, to cause further servicing of the buffer)
      call Release to signal that the service has been completed
   end loop;

A buffer is deleted automatically whenever a call to Release makes its
Disp_Count go down to zero.

This scheme has a lot of flexibility. It enables service tasks to dispatch a
buffer for further processing. It enables several tasks to perform the same
service, and it could enable one task to perform many services under some
circumstances. It makes it possible to have several packet picking tasks,
provided you ensure they actually pick the packets atomically.

I have left the package body, and the details of implementation, to you.
However, I've suggested that you would need two arrays, one for the
allocation of buffers, and one for the allocation of 'dispatches'.

Incidentally, I think you will need:

   type Array_Access is access all Data_Array;

if you are going to use an internal array for the buffer data, instead of
allocation with 'new'. The internal array will have to be aliased.

Hope this is helpful,

--
Nick Roberts
http://www.AdaOS.org


=====

generic
   type Datum_Type is private;
   type Service_Type is (<>);

package Buffer_Distribution_Management is

   type Data_Array is array (Positive range <>) of Datum_Type;

   type Array_Access is access Data_Array;

   type Buffer_Token   is private;
   type Dispatch_Token is private;

   -- Utility declarations (effectively private):

   type Buffer_Index   is new Positive;
   type Dispatch_Index is new Positive;

   type Buffer_Descriptor is
      record
         Allocated:  Boolean := False;
         Data:       Array_Access;
         Disp_Count: Natural := 0;
      end record;

   type Dispatch_Descriptor is
      record
         Allocated:  Boolean := False;
         Buffer:     Buffer_Index;
         Service:    Service_Type;
      end record;

   type Buffer_Array   is (Buffer_Index   range <>) of Buffer_Descriptor;
   type Dispatch_Array is (Dispatch_Index range <>) of Dispatch_Descriptor;

   -- The most important declaration for this package:

   protected type Buffer_Distributor (Buffer_Cap, Dispatch_Cap: Natural) is

      entry Create (Length: in  Natural;
                    Buffer: out Array_Access;
                    Token:  out Buffer_Token);

      procedure Delete (Token: in Buffer_Token);

      entry Dispatch (Token:   in Buffer_Token;
                      Service: in Service_Type);

      entry Obtain (Service: in  Service_Type;
                    Buffer:  out Array_Access;
                    Token:   out Dispatch_Token);

      procedure Release (Token: in Dispatch_Token);

      procedure Reset;

   private
      Buffers:    Buffer_Array   (1..Buffer_Cap);
      Dispatches: Dispatch_Array (1..Dispatch_Cap);
      ...

   end Buffer_Distributor;

private

   type Buffer_Token   is new Buffer_Index;
   type Dispatch_Token is new Dispatch_Index;

end Buffer_Distribution_Management;







^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore?
  2001-01-21 16:53           ` Nick Roberts
@ 2001-01-21 18:24             ` Robert Dewar
  2001-01-23  0:21               ` Nick Roberts
  0 siblings, 1 reply; 34+ messages in thread
From: Robert Dewar @ 2001-01-21 18:24 UTC (permalink / raw)


In article <94f577$d9s66$1@ID-25716.news.dfncis.de>,
  "Nick Roberts" <nickroberts@callnetuk.com> wrote:

> I would have thought some companies which sell Ada compilers
                           ^
                           other (than Ada Core Technologies)

is presumably what you meant here.

Naturally GNAT Professional does include this capability, just
so that this is absolutely clear, and the need (and hence the
reason that this facility is provided), comes from our
customers who need to be able to use GLADE (Annex E
capabilities) for heterogenous distribution.

Probably since GNAT Professional is the only commercial
compiler that provides Annex E support, the requirement is
less significant for other technologies. Yes, I realize there
are other uses of this capability, which is why we provided
it in a generalized form, but they are not so compelling,
since, as I pointed out in my earlier message, you can usually
do what you want by avoiding the use of predefined types (which
generally is a good idea in any case).

Robert Dewar
Ada Core Technologies


Sent via Deja.com
http://www.deja.com/



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore?
  2001-01-21 16:04             ` Robert Dewar
@ 2001-01-21 23:23               ` DuckE
  2001-01-22  0:28                 ` mark_lundquist
  2001-01-22  1:51                 ` Robert Dewar
  2001-01-22  0:35               ` Built-in types (was " mark_lundquist
  1 sibling, 2 replies; 34+ messages in thread
From: DuckE @ 2001-01-21 23:23 UTC (permalink / raw)



"Robert Dewar" <robert_dewar@my-deja.com> wrote in message
news:94f1a8$k9r$1@nnrp1.deja.com...
> In article <tXqa6.290632$U46.9271836@news1.sttls1.wa.home.com>,
>   "DuckE" <nospam_steved94@home.com> wrote:
>
> > 3. You want to control stream behavior on a type by type
> > basis for all types including built in types.
>
> I don't see the point in adding a rather complex feature to
> the language whose only purpose is to encourage increased
> usage of bulit in primitive types, when we generally want
> to discourage such use. Carefully written Ada programs should
> not use the built-in types in any case.
>

After a little more reflection it occurs to me that what I really want is
for the format of data on a stream to be dependent on the stream, or at
least be capable of being dependent on the stream.

For example, within one application I may want to stream information to a
network in big endian format and stream information to files in little
endian format.  From what I understand (I may certainly be wrong) I cannot
do this in Ada.  If I want this functionality I must resort to C++.

SteveD


>
> Sent via Deja.com
> http://www.deja.com/





^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore?
  2001-01-20 18:16       ` DuckE
  2001-01-20 19:16         ` Robert Dewar
@ 2001-01-22  0:16         ` mark_lundquist
  1 sibling, 0 replies; 34+ messages in thread
From: mark_lundquist @ 2001-01-22  0:16 UTC (permalink / raw)




> In my opinion this is one of the weak points of Ada 95.  It would
have been
> better to not have the 'input and 'output pre-defined for built in
types (as
> a part of the language) but to include a package for defining these
> attributes.  That way an arbitrary representation of built in types
could be
> used with streams when desired.

Why don't you just derive from the predefined type, then override the
stream attributes on your derived type?  That doesn't seem like a huge
inconvenience... OTOH, it seems like Ada is helping, not hurting, by
supplying predefined implementations of those attributes for predefined
types (for when you *don't* care how they are implemented!)

Maybe I'm missing your point when you say this is a weak point...?  If
so, try again and I'll try to follow :-)

Said another way, if you say you want different stream I/O methods for
Integer than the predefined ones, what you really mean is that you
don't want an Integer! :-)  What you want is something that is just
like an Integer but has different I/O methods.

Mark Lundquist
Rational Software



Sent via Deja.com
http://www.deja.com/



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore?
  2001-01-21 23:23               ` DuckE
@ 2001-01-22  0:28                 ` mark_lundquist
  2001-01-22  1:51                 ` Robert Dewar
  1 sibling, 0 replies; 34+ messages in thread
From: mark_lundquist @ 2001-01-22  0:28 UTC (permalink / raw)


In article <CbKa6.294821$U46.9394163@news1.sttls1.wa.home.com>,
  "DuckE" <nospam_steved94@home.com> wrote:
>
>
> After a little more reflection it occurs to me that what I really
want is
> for the format of data on a stream to be dependent on the stream, or
at
> least be capable of being dependent on the stream.

Yes...

>
> For example, within one application I may want to stream information
to a
> network in big endian format and stream information to files in little
> endian format.  From what I understand (I may certainly be wrong) I
cannot
> do this in Ada.

Certainly you can!

You do it by creating a new type derived from
Ada.Streams.Root_Stream_Type (or one of its descendants) and overriding
its primitives (like Read and Write).

>  If I want this functionality I must resort to C++.
>

Ye gads!
:-) :-)

Mark Lundquist
Rational Software


Sent via Deja.com
http://www.deja.com/



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Built-in types (was Re: How can I avoid Using a Semaphore?
  2001-01-21 16:04             ` Robert Dewar
  2001-01-21 23:23               ` DuckE
@ 2001-01-22  0:35               ` mark_lundquist
  2001-01-22  1:54                 ` Robert Dewar
  1 sibling, 1 reply; 34+ messages in thread
From: mark_lundquist @ 2001-01-22  0:35 UTC (permalink / raw)


In article <94f1a8$k9r$1@nnrp1.deja.com>,
  Robert Dewar <robert_dewar@my-deja.com> wrote:
>
> Carefully written Ada programs should
> not use the built-in types in any case.
>

That seems a little broad...

When a careful Ada programmer writes 'Integer', he's saying that he
understands the things about Integer that are implementation-defined
and that those things are "don't cares" for him in this instance.  It's
not careless to say that and mean it.

Need I elaborate?  (I don't feel like a lot of typing this afternoon :-)

-- mark


Sent via Deja.com
http://www.deja.com/



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore?
  2001-01-21 23:23               ` DuckE
  2001-01-22  0:28                 ` mark_lundquist
@ 2001-01-22  1:51                 ` Robert Dewar
  2001-01-23  2:36                   ` DuckE
  1 sibling, 1 reply; 34+ messages in thread
From: Robert Dewar @ 2001-01-22  1:51 UTC (permalink / raw)


In article <CbKa6.294821$U46.9394163@news1.sttls1.wa.home.com>,
  "DuckE" <nospam_steved94@home.com> wrote:
> For example, within one application I may want to stream
> information to a network in big endian format and stream
> information to files in little endian format.  From what I
> understand (I may certainly be wrong) I cannot do this in
> Ada.  If I want this functionality I must resort to C++.

Sure you can do this in Ada, just define two types (use
derived types if you want to be able to convert between them)
and specify different stream routines for the two types (or
sets of types).

To what feature are you referring in C++ here that will help
you solve this feature. I am unaware of any feature in standard
C++ that would provide any automatic solution, but I certainly
don't know all of C++ :-)


Sent via Deja.com
http://www.deja.com/



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Built-in types (was Re: How can I avoid Using a Semaphore?
  2001-01-22  0:35               ` Built-in types (was " mark_lundquist
@ 2001-01-22  1:54                 ` Robert Dewar
  2001-01-22 16:18                   ` mark_lundquist
  0 siblings, 1 reply; 34+ messages in thread
From: Robert Dewar @ 2001-01-22  1:54 UTC (permalink / raw)


In article <94fv9d$cjt$1@nnrp1.deja.com>,
  mark_lundquist@my-deja.com wrote:
> In article <94f1a8$k9r$1@nnrp1.deja.com>,
>   Robert Dewar <robert_dewar@my-deja.com> wrote:
> >
> > Carefully written Ada programs should
> > not use the built-in types in any case.
> >
>
> That seems a little broad...
>
> When a careful Ada programmer writes 'Integer', he's saying
> that he understands the things about Integer that are
> implementation-defined and that those things are "don't
> cares" for him in this instance.  It's not careless to say
> that and mean it.

It is never actively *useful* to be able to do this, since
you certainly have *some* requirements on any type you supply,
and you may as well make them explicit.

The trouble is that 90% of programmers writing Integer
explicitly do NOT know what they are saying, and make a mess.
That is why most coding standards wisely suggest not using
type Integer. There are some exceptions, e.g. as the subscript
of the standard type String, and you cannot get away from this
built in type, because of library usage.

P.S. Jean Ichbiah feels it was a bad mistake to have had the
type Standard.String depend on Integer in this way, but it was
too late to change.


Sent via Deja.com
http://www.deja.com/



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Built-in types (was Re: How can I avoid Using a Semaphore?
  2001-01-22  1:54                 ` Robert Dewar
@ 2001-01-22 16:18                   ` mark_lundquist
  2001-01-22 17:20                     ` Robert Dewar
  0 siblings, 1 reply; 34+ messages in thread
From: mark_lundquist @ 2001-01-22 16:18 UTC (permalink / raw)


In article <94g3tf$gb9$1@nnrp1.deja.com>,
  Robert Dewar <robert_dewar@my-deja.com> wrote:
> In article <94fv9d$cjt$1@nnrp1.deja.com>,
>   mark_lundquist@my-deja.com wrote:
> >
> > When a careful Ada programmer writes 'Integer', he's saying
> > that he understands the things about Integer that are
> > implementation-defined and that those things are "don't
> > cares" for him in this instance.  It's not careless to say
> > that and mean it.
>
> It is never actively *useful* to be able to do this, since
> you certainly have *some* requirements on any type you supply,
> and you may as well make them explicit.

Couldn't it be that my only requirement is that this be (using the
example of integer types) the "whatever integer"?  If that's my only
requirement, then I'm being explicit about it when I write "Integer",
because that's what Integer is supposed to be -- the "whatever
integer".  Anything else that I might specify is in fact *not* a
requirement for me.

(Let's see, just for integer types, what can the programmer specify?
There's base range, size, alignment, stream I/O attributes... anything
else?)

>
> The trouble is that 90% of programmers writing Integer
> explicitly do NOT know what they are saying, and make a mess.
> That is why most coding standards wisely suggest not using
> type Integer.

Well that's just it... it seems like if the programmer is sharp enough
to specify all this stuff, then he also ought to be sharp enough to
know when he means the "whatever" types and to use them when that's
what he means.

I suppose if it were a choice between the programmer blindly using
Integer for everything (considerations of scalar abstraction aside),
and blindly specifying everything because a style guide told him to do
so, then I guess I'd prefer the latter (but not by much; see below...)
However, that is a truly bonehead operating level and if these were
really the only alternatives I doubt I'd want that programmer writing
code for anything I cared about! :-)  I mean, if you're going to go to
the trouble to make a style guide that tells them to specify down to
the gn@t'$ @$$ whether they depend on it or not, and expect them to
follow it, then is it really that hard to teach them what Integer
means?  Then give advice with some substance, like "don't write a
record component of type Integer if you're going to apply a
representation clause" -- in which case you know your code will still
compile if it's ported to another platform.  You may or may not care
about slightly different behavior, but you do care that it compile! :-)

Is it OK to use the predefined Float type? :-) Suppose I nail down the
precision and/or range to something I think makes sense for a
particular architecture... might that not result in less-than-optimal
performance if my code is ported to joe random architecture?  So that's
the whole point of having the "whatever" types.  You need to be able to
say "whatever".  The issue is that people know when they're
saying "whatever" and that they don't say it when they don't mean it.

There was a thread here last year, in which someone was lamenting that
Ada's integer types were not as "portable" as Java's because the
language doesn't nail standardize the sizes/ranges.  I argued that (a)
there are different kinds of portability, and (b) of the two kinds
relevant to the argument, Java provides one, and Ada provides both, but
that (c) the objector was looking in the wrong place in Ada for the
Java-style portable integer types -- the right place is not the
Standard integer types but the ones in package Interfaces.  Once again,
you want to be able to say "whatever".

Now, I do have a beef with overspecification, because it obscures.  I'm
always looking for communication of design intent.  So if I see an
integer type declared, and there's no abstraction involved, and we're
nailing down the size, then I say "OK, what intent is being captured
here -- where are the bits that depend on this?"  It's quite annoying
when the answer is "Nothing really depends on it, we just specified
because it's bad not to specify everything".

> There are some exceptions, e.g. as the subscript
> of the standard type String, and you cannot get away from this
> built in type, because of library usage.
>
> P.S. Jean Ichbiah feels it was a bad mistake to have had the
> type Standard.String depend on Integer in this way, but it was
> too late to change.

Changing the subject, speaking of strings... it seems a little
unfortunate that Ada95 has 3 kinds of strings (not counting the
dimension of standard vs. wide), all with essentially the same
interface, and no abstraction of that interface.  As a result, generic
programming across the string types doesn't come naturally, although I
guess this can be more-or-less fixed outside the language with wrapper
classes.

Best Regards,
mark




Sent via Deja.com
http://www.deja.com/



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore? (long)
  2001-01-13 16:18 How can I avoid Using a Semaphore? (long) DuckE
  2001-01-15  1:06 ` How can I avoid Using a Semaphore? Nick Roberts
@ 2001-01-22 16:51 ` mark_lundquist
  2001-01-23  6:02   ` DuckE
  2001-02-02 21:38 ` Niklas Holsti
  2 siblings, 1 reply; 34+ 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] 34+ messages in thread

* Re: Built-in types (was Re: How can I avoid Using a Semaphore?
  2001-01-22 16:18                   ` mark_lundquist
@ 2001-01-22 17:20                     ` Robert Dewar
  2001-01-22 23:17                       ` Mark Lundquist
  0 siblings, 1 reply; 34+ messages in thread
From: Robert Dewar @ 2001-01-22 17:20 UTC (permalink / raw)


In article <94hmgo$o2k$1@nnrp1.deja.com>,
  mark_lundquist@my-deja.com wrote:
> If that's my only
> requirement, then I'm being explicit about it when I write
> "Integer", because that's what Integer is supposed to be --
> the "whatever integer".

In this very unlikely scenario, I would suggest writing

  type My_Int is new Integer;
  --  Use standard default (and presumably efficient) integer

so that if there are porting problems, or if you do need to
specify additional attributes, then it is easily done without
major rewriting.

> (Let's see, just for integer types, what can the programmer
> specify? There's base range, size, alignment, stream I/O
> attributes... anything else?)

Yes, there are other things, but the point is that we are
specifically talking here about a complaint that you can NOT
specify them for the standard type Integer. That's what this
thread is about.

It is curious logic to be in a position of saying

1. I want to use Integer when I don't want to specify any
   additional stuff.

2. It is annoying that for type Integer, I cannot specify
   additional stuff

that makes little sense to me!


> Well that's just it... it seems like if the programmer is
> sharp enough to specify all this stuff, then he also ought to
> be sharp enough to know when he means the "whatever" types
> and to use them when that's what he means.

Please give a VERY clear example of why it is good EVER to
use type Integer (other than when constrained by a library)?

Even if efficiency is a concern, the proper approach is to
write something like

   type Temp_Int is range min-required .. max-required;
   type My_Int is new Temp_Int'Base;

Now use My_Int. That's really MUCH better than using Integer
directly.


> There was a thread here last year, in which someone was
> lamenting that Ada's integer types were not as "portable" as
> Java's because the language doesn't nail standardize the
> sizes/ranges.

Well this of course makes no sense. In Java you only have the
standard types, so it is important to standardize them. In
serious Ada, you don't use these standard types anyway, so
the fact that they are not defined is not relevant to serious
programs.

Of course at this stage, it would in practice be fine to define
type Integer as being always 32 bits, precisely because serious
code is not going to use this much anyway.

Well to be honest (as they say in the AARM), we can't do that
*because* of the involvement of Integer with Standard.String.


Sent via Deja.com
http://www.deja.com/



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Built-in types (was Re: How can I avoid Using a Semaphore?
  2001-01-22 17:20                     ` Robert Dewar
@ 2001-01-22 23:17                       ` Mark Lundquist
       [not found]                         ` <m33deaaeks.fsf@ns40.infomatch.bc.ca>
       [not found]                         ` <94km00$bv8$1@nnrp1.deja.com>
  0 siblings, 2 replies; 34+ messages in thread
From: Mark Lundquist @ 2001-01-22 23:17 UTC (permalink / raw)



Robert Dewar <robert_dewar@my-deja.com> wrote in message
news:94hq56$rlv$1@nnrp1.deja.com...
> In article <94hmgo$o2k$1@nnrp1.deja.com>,
>   mark_lundquist@my-deja.com wrote:
> > If that's my only
> > requirement, then I'm being explicit about it when I write
> > "Integer", because that's what Integer is supposed to be --
> > the "whatever integer".
>
> In this very unlikely scenario, I would suggest writing
>
>   type My_Int is new Integer;
>   --  Use standard default (and presumably efficient) integer
>
> so that if there are porting problems, or if you do need to
> specify additional attributes, then it is easily done without
> major rewriting.

You've almost convinced me :-)

First I would have to figure out how to think up type names that are not so
cheesy as "My_Int" :-)  And the names shouldn't "encode" specifics about
their implementation properties, e.g. "Int16" is going to be a bad choice if
I later decide it has to be 32 bits!  Also -- in this example, you've
defined your own integer type so that you have the flexibility to change it
later.  Isn't there still always a problem, in that you still assume that
you'll always be able to use the same type for all the same things?  Let's
say you go and use My_Int everywhere instead of Integer.  Now you find that
for certain of those uses, the current definition of My_Int isn't going to
cut it.  Well, the ability to change the definition of My_Int only helps you
if the new definition is also what you want for all the uses of My_Int.
Maybe you can't really change My_Int in the way you require for a particular
use, without screwing it up in its other uses.  So My_Int is not a great
Integer substitute.  It's certainly no worse than Integer, but I'm not
convinced that it's all *that* much better from the standpoint of
portability, resilience to change etc. (remember, this is the case where I
truly *don't* *care* about the unspecified properties).

> > (Let's see, just for integer types, what can the programmer
> > specify? There's base range, size, alignment, stream I/O
> > attributes... anything else?)
>
> Yes, there are other things,

What are they?  I'm trying to see what it would take to define an integer
type that is fully specified, leaving nothing to the implementation-specific
defaults.

(I think that leaves out anything specified by a pragma, right?)

> but the point is that we are
> specifically talking here about a complaint that you can NOT
> specify them for the standard type Integer. That's what this
> thread is about.

*was* about, and then only briefly (_I_ was the one who changed the subject
line...) :-)  My original response was to your statement that carefully
written Ada programs don't (within reeason of course) use predefined types.
But you use Deja and it doesn't do a good job with changed subject lines :-)

>
> It is curious logic to be in a position of saying
>
> 1. I want to use Integer when I don't want to specify any
>    additional stuff.
>
> 2. It is annoying that for type Integer, I cannot specify
>    additional stuff
>
> that makes little sense to me!

I said no such thing, nor implied it!  What you say there is exactly the
point I made to "DuckE" however many posts ago, when he said it was a weak
point of Ada that you can't write 'Input etc. for the predefined types :-)

>
>
> > Well that's just it... it seems like if the programmer is
> > sharp enough to specify all this stuff, then he also ought to
> > be sharp enough to know when he means the "whatever" types
> > and to use them when that's what he means.
>
> Please give a VERY clear example of why it is good EVER to
> use type Integer (other than when constrained by a library)?

OK

procedure Append (
        This : in Element;
        Instances : Natural;        -- subtype of Integer anyway
        To : Collection
    );

>
> Even if efficiency is a concern, the proper approach is to
> write something like
>
>    type Temp_Int is range min-required .. max-required;
>    type My_Int is new Temp_Int'Base;
>
> Now use My_Int. That's really MUCH better than using Integer
> directly.

[OK, I'm not debating you right now :-)  Just a question, because I really
don't know...]

Why did you derive My_Int from Temp_Int, instead of defining it as you did
Temp_Int?

[OK, I'm debating you again :-)]

If I really have no requirements on the range, won't I just say
    type Temp_Int is range Integer'first .. Integer'last;
???  (I suppose there *might* be occasions where I have no requirements on
the range, but where that might someday change...)  OTOH, if I nail it down
to something else, am I not saying that I want constraint checks if this is
ported to an architecture where overflow won't take of it?

>
>
> > There was a thread here last year, in which someone was
> > lamenting that Ada's integer types were not as "portable" as
> > Java's because the language doesn't nail standardize the
> > sizes/ranges.
>
> Well this of course makes no sense.

of course...

> In Java you only have the
> standard types, so it is important to standardize them.

True, if you can't define your own elementary types then the standard ones
ought to be standardized.  Also, Java is meant to run on one machine (the
JVM), so in a sense the standard types are defined the way they are because
they're natural for the target machine.






^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore?
  2001-01-21 18:24             ` Robert Dewar
@ 2001-01-23  0:21               ` Nick Roberts
  0 siblings, 0 replies; 34+ messages in thread
From: Nick Roberts @ 2001-01-23  0:21 UTC (permalink / raw)


"Robert Dewar" <robert_dewar@my-deja.com> wrote in message
news:94f9h7$qpk$1@nnrp1.deja.com...
> > I would have thought some companies which sell Ada compilers
>                            ^
>                            other (than Ada Core Technologies)
>
> is presumably what you meant here.

Yes, that is what I meant. (Sorry :-)

--
Nick Roberts






^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore?
  2001-01-22  1:51                 ` Robert Dewar
@ 2001-01-23  2:36                   ` DuckE
  0 siblings, 0 replies; 34+ messages in thread
From: DuckE @ 2001-01-23  2:36 UTC (permalink / raw)



"Robert Dewar" <robert_dewar@my-deja.com> wrote in message
news:94g3n9$g2p$1@nnrp1.deja.com...
> In article <CbKa6.294821$U46.9394163@news1.sttls1.wa.home.com>,
>   "DuckE" <nospam_steved94@home.com> wrote:
> > For example, within one application I may want to stream
> > information to a network in big endian format and stream
> > information to files in little endian format.  From what I
> > understand (I may certainly be wrong) I cannot do this in
> > Ada.  If I want this functionality I must resort to C++.
>
> Sure you can do this in Ada, just define two types (use
> derived types if you want to be able to convert between them)
> and specify different stream routines for the two types (or
> sets of types).

I stand corrected.  I see that I can derive different types from
Root_Stream_Type that permit the different behavior.

But... I still think that the inability to define the ordering for built in
types is a limitation.  If this limitation were not present then a special
version of library would not be required for GLADE.

SteveD






^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore? (long)
  2001-01-22 16:51 ` How can I avoid Using a Semaphore? (long) mark_lundquist
@ 2001-01-23  6:02   ` DuckE
  2001-02-02 22:00     ` Sucking (was Re: How can I avoid Using a Semaphore? (long)) Mark Lundquist
  2001-02-02 22:18     ` How can I avoid Using a Semaphore? (long) Mark Lundquist
  0 siblings, 2 replies; 34+ 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] 34+ messages in thread

* Re: How can I avoid Using a Semaphore? (long)
  2001-01-13 16:18 How can I avoid Using a Semaphore? (long) DuckE
  2001-01-15  1:06 ` How can I avoid Using a Semaphore? Nick Roberts
  2001-01-22 16:51 ` How can I avoid Using a Semaphore? (long) mark_lundquist
@ 2001-02-02 21:38 ` Niklas Holsti
  2 siblings, 0 replies; 34+ 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] 34+ messages in thread

* Sucking (was Re: How can I avoid Using a Semaphore? (long))
  2001-01-23  6:02   ` DuckE
@ 2001-02-02 22:00     ` Mark Lundquist
  2001-02-03  1:44       ` Jeffrey Carter
  2001-02-03  3:21       ` DuckE
  2001-02-02 22:18     ` How can I avoid Using a Semaphore? (long) Mark Lundquist
  1 sibling, 2 replies; 34+ messages in thread
From: Mark Lundquist @ 2001-02-02 22:00 UTC (permalink / raw)



DuckE <nospam_steved94@home.com> wrote in message
news:b89b6.298508$U46.9559869@news1.sttls1.wa.home.com...

> [Mark wrote:]
> >
> > P.S.  Your identifier style sucks.  (Why mince words? :-) :-) :-)
>
> Any style of code with which you are unfamiliar "sucks".

Actually, no... :-)  "This is unfamiliar", and "This sucks" are two
distinctly different reactions :-)

I have specific reasons for believing it sucks, which have nothing to do
with unfamiliarity :-)  You probably know most of them already, so unless
someone wants to discuss it I won't go there :-).  But what I presume you
mean
is that this style conveys benefits that I'm unable to appreciate without
having actually worked with it for a period of time (approximately two weeks
it, would appear :-).  I'll just have to take your word for that!

It seems clear enough what the style is...  Each package has a full name,
with an acronymic prefix.  Then each identifier declared therein gets that
same acronym as a suffix.  OK... nope, sorry! :-)  I think it would take me
more than 2 weeks to forget how I got along without that... :-)

The style of "aFoobar" and "anApteryx" for type names seems like a different
form of the "The_Foobar" cop-out for parameter names -- both meant to spare
us the trouble of thinking up a parameter name that would be more meaningful
than just repeating the name of the type, am I right?  (Interestingly, the
orthography seems derived from the Smalltalk environment and the books by
Adele Goldberg, et al... but in Smalltalk, the sense is completely the
opposite: this style of naming is used not for types, but for method
arguments, because since it's an untyped language you need a parameter name
like "aList" as a cue to the reader that the actual is supposed  to be of
type List!)

>  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.

I just really dislike all identifier format conventions.  That goes for
Hungarian notation, "suffix inflectional", etc.  I don't care if it's
Subsaharan pluperfect transfusional or whatever, I give 'em all the
heave-ho!!  Just keep it natural.  Yeah I know, that's just my personal
preference... Like the pronunciation of "bona fide" [:-) :-)], it's
ultimately a matter of taste...  I used to use a format convention for
identifiers, but I grew out of it.

An aside, relating naming conventions to this idea of "class-oriented
programming"...  One of the supposed advantages of "member function"
notation and distinguished-receiver syntax is that within a method, you
don't have to qualify references to members of the current instance by some
parameter name.  It's considered lame and lowbrow and "procedural" to have
to do
that.  Not too long ago, I was working with some C++ code where the
developers had adopted a curious naming convention for member objects...
they were all given names like "m_Foo", "m_Bar", where the "m_" stood for --
you guessed it -- "member".  How bizarre to resort to a naming convention to
work around what is supposed to be an advantage of the language.  Even
admitting that it isn't an advantage after all, writing "this->Foo" is so
much more natural -- anyone can understand that without having to learn some
convention! :-) :-)

Best Regards,
Mark











^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Built-in types (was Re: How can I avoid Using a Semaphore?
       [not found]                         ` <m33deaaeks.fsf@ns40.infomatch.bc.ca>
@ 2001-02-02 22:01                           ` Mark Lundquist
  0 siblings, 0 replies; 34+ messages in thread
From: Mark Lundquist @ 2001-02-02 22:01 UTC (permalink / raw)



Ray Blaak <blaak@infomatch.com> wrote in message
news:m33deaaeks.fsf@ns40.infomatch.bc.ca...
> "Mark Lundquist" <mark@rational.com> writes:
> >
> > First I would have to figure out how to think up type names that are not
so
> > cheesy as "My_Int" :-)  And the names shouldn't "encode" specifics about
> > their implementation properties, e.g. "Int16"
>
> Well, you try to have a name that indicates what it is to be used for,
about,
> etc. e.g,
>
>   type Instance_Count is new Natural;
>
> Such names should be independent of the specifics of the type itself.
>
> Note that you would also have the very important benefit of not
accidentially
> mixing up various different "whatever" integers.

Hi Ray,

What we're debating is what to do after all the reasonable scalar
abstraction is done, if indeed there is anything left at that point.  It's
felt by many that it is a mistake to create a new type for every last thing
under the sun (a mistake characteristic of the "wild-eyed proselyte" stage,
it goes along with making everything a task :-))  Dewar asked for a
counterexample, and the one I gave was of an STL-style collection insert
operation that creates multiple copies of a value.  This is just the kind of
situation where creating a new type as you describe above is exactly what
you don't want to do, because it adds absolutely no benefit whatsoever --
the only effect is to force a lot of explicit conversions.  What you want is
the "whatever integer", and I think Integer is fine for this because that is
the meaning of Integer, while Dewar thinks I should define the "whatever
integer" type explicitly.  But Dewar's way does not result in gratuitous
explicit conversions, because as this is intentionally the "whatever
integer" type, it would be used anywhere "whatever" is needed (which
certainly will not be everywhere an integer type is needed, so there will
still be conversions, but those would be required anyway whether you write
it his way or my way).

>
> > Also -- in this example, you've defined your own integer type so that
you
> > have the flexibility to change it later.  Isn't there still always a
problem,
> > in that you still assume that you'll always be able to use the same type
for
> > all the same things?  Let's say you go and use My_Int everywhere instead
of
> > Integer.  Now you find that for certain of those uses, the current
definition
> > of My_Int isn't going to cut it.  Well, the ability to change the
definition
> > of My_Int only helps you if the new definition is also what you want for
all
> > the uses of My_Int.
>
> You have the exact problem if you use the "whatever" Integer. As soon as
some
> of the uses differ from the "whatever" usage, then you have to rename
things
> anyway.

Yes sir, that's absolutely right -- you have the same problem!  The point I
was trying to make (and didn't make very well :-) was not that Integer makes
it any better, but that My_Int *doesn't* make it any better.  Really, the
problem with what I wrote was that I contradicted myself -- if indeed all
the uses of "whatever integer" don't care, then they cannot possibly be
broken if the definition changes for the sake of one usage that suddenly
starts to care.  But as you point out, the right solution is not to change
the definition anyway, it's to use a different type.  Changing the
definition only obscures the code, since now we have a documented intent of
"don't care" even as it now does care.  So My_Int is not better with respect
to "resilience to change".







^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Built-in types (was Re: How can I avoid Using a Semaphore?
       [not found]                         ` <94km00$bv8$1@nnrp1.deja.com>
@ 2001-02-02 22:03                           ` Mark Lundquist
  0 siblings, 0 replies; 34+ messages in thread
From: Mark Lundquist @ 2001-02-02 22:03 UTC (permalink / raw)



Robert Dewar <robert_dewar@my-deja.com> wrote in message
news:94km00$bv8$1@nnrp1.deja.com...
> In article <94ifq8$uu$1@usenet.rational.com>,
>   "Mark Lundquist" <mark@rational.com> wrote:
> > It's certainly no worse than Integer, but I'm not
> > convinced that it's all *that* much better from the
> > standpoint of
> > portability, resilience to change etc. (remember, this is the
> > case where I
> > truly *don't* *care* about the unspecified properties).
>
> The point is that it emphasizes to the reader what is going on,
> and indeed it is more portable than Integer, if for example,
> the range is greater than 16 bits (remember that that is all
> you can depend on from type Integer).

If you need it to be "portable" in this aspect, then you do "care", and you
should not use Integer which means "don't care".  But I am talking about
when you -- one more time :-) -- don't care.

>
> The trouble once again with using naked Integer is that I
> cannot tell *why* you made this choice, and likely the reason
> is just incompetence :-)

Yeah, probably so :-)

But I can't see how overspecification leaves the reader any less blind to
the author's intent.  How is the reader to distinguish specification of
things you are depending on from that of things that you don't depend on?

>
>
> > type that is fully specified, leaving nothing to the
> > implementation-specific defaults.
>
> Such as the representation in bits, which can NOT be
> specified???

Of course not.  Read carefully, I said "leaving nothing to the
implementation-specific *defaults*" (if you can't specify it, it's not a
default, it's just implementation-specific).  Once again, what are all the
things
that can be specified?  I said what I thought after consulting the RM, and
you said there were more things that I missed -- what are they?  And in your
standard technique, do you define all those things for your "My_Int"?  If
not, why not?

>
> > Why did you derive My_Int from Temp_Int, instead of defining
> > it as you did Temp_Int?
>
> You completely missed the point of my declarations, have a look
> at them again! The 'Base is the WHOLE POINT of these
> declarations. So perhaps you want to look again, and perhaps
> your comments were based on not understanding the technique
> here (which for me is an absolutely standard one).

That's just the thing, I don't understand the technique :-).  I admit to
being clueless about it, and I would like to have someone explain it to me.

>
> >     type Temp_Int is range Integer'first .. Integer'last;
>
> That's pointless, it is just equivalent to
>
>    type Temp_Int is new Integer;

Yes, just as I thought... that's why I elaborated, I'm trying to figure out
at what point you object to Integer -- is it just that the range is not
nailed to the floor?

Best Regards
Mark Lundquist








^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore? (long)
  2001-01-23  6:02   ` DuckE
  2001-02-02 22:00     ` Sucking (was Re: How can I avoid Using a Semaphore? (long)) Mark Lundquist
@ 2001-02-02 22:18     ` Mark Lundquist
  2001-02-03  3:01       ` DuckE
  1 sibling, 1 reply; 34+ 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] 34+ messages in thread

* Re: Sucking (was Re: How can I avoid Using a Semaphore? (long))
  2001-02-02 22:00     ` Sucking (was Re: How can I avoid Using a Semaphore? (long)) Mark Lundquist
@ 2001-02-03  1:44       ` Jeffrey Carter
  2001-02-03  3:21       ` DuckE
  1 sibling, 0 replies; 34+ messages in thread
From: Jeffrey Carter @ 2001-02-03  1:44 UTC (permalink / raw)


Mark Lundquist wrote:
> The style of "aFoobar" and "anApteryx" for type names seems like a different
> form of the "The_Foobar" cop-out for parameter names

The first few letters of an identifier are the most important for
recognition. If all your identifiers start with some kind of noise, be
it "a", "The_", or the Hungarian notation crap, it makes your code
harder to read. As we all know, that is A Bad Thing.

Writing "aFoobar" and "anApteryx" in a language that allows underlines
in identifiers is unwise. An underline between words makes them easier
to read than just a case difference. Such a style in a case-insensitive
language is even less wise.

-- 
Jeff Carter
"You tiny-brained wipers of other people's bottoms!"
Monty Python & the Holy Grail



^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: How can I avoid Using a Semaphore? (long)
  2001-02-02 22:18     ` How can I avoid Using a Semaphore? (long) Mark Lundquist
@ 2001-02-03  3:01       ` DuckE
  0 siblings, 0 replies; 34+ 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] 34+ messages in thread

* Re: Sucking (was Re: How can I avoid Using a Semaphore? (long))
  2001-02-02 22:00     ` Sucking (was Re: How can I avoid Using a Semaphore? (long)) Mark Lundquist
  2001-02-03  1:44       ` Jeffrey Carter
@ 2001-02-03  3:21       ` DuckE
  2001-02-05 20:07         ` Mark Lundquist
  1 sibling, 1 reply; 34+ messages in thread
From: DuckE @ 2001-02-03  3:21 UTC (permalink / raw)


> It seems clear enough what the style is...  Each package has a full name,
> with an acronymic prefix.  Then each identifier declared therein gets that
> same acronym as a suffix.  OK... nope, sorry! :-)  I think it would take
me
> more than 2 weeks to forget how I got along without that... :-)

Our code started in a different language (EPascal) where external functions,
procedures and type definitions were not easily discernable from local
definitions.  Knowing the origin of these definition "at a glance" without
having to look it up has its advantages.

In Ada, I could certainly see eliminating these acronyms in favor of
qualifying these external definitions with their origins (ie:
Ada.Text_Io.Put_Line ).

> The style of "aFoobar" and "anApteryx" for type names seems like a
different
> form of the "The_Foobar" cop-out for parameter names -- both meant to
spare
> us the trouble of thinking up a parameter name that would be more
meaningful
> than just repeating the name of the type, am I right?

Our use of "a" or "an" to start a type definition simply adds instant
recognition of an identifier as a data type without regard to context.  IMHO
this is not much different than quickly identifying the start of a sentence
with a capital letter.

What these conventions really buy us is time.  When I look at a block of
code a great deal of information is available as hints from the coding
convention that keep me from having to look elsewhere for definitions.

[snip]
>
> Best Regards,
> Mark
>






^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Sucking (was Re: How can I avoid Using a Semaphore? (long))
  2001-02-03  3:21       ` DuckE
@ 2001-02-05 20:07         ` Mark Lundquist
  2001-02-06  7:16           ` Sven Nilsson
  0 siblings, 1 reply; 34+ messages in thread
From: Mark Lundquist @ 2001-02-05 20:07 UTC (permalink / raw)



DuckE <nospam_steved94@home.com> wrote in message
news:0PKe6.366080$U46.10801728@news1.sttls1.wa.home.com...
>
> Our code started in a different language (EPascal) where external
functions,
> procedures and type definitions were not easily discernable from local
> definitions.  Knowing the origin of these definition "at a glance" without
> having to look it up has its advantages.
>
> In Ada, I could certainly see eliminating these acronyms in favor of
> qualifying these external definitions with their origins (ie:
> Ada.Text_Io.Put_Line ).

There's an Ada style out there that you might find gives you the best of
both...  To use your code as an example, you would name your package
Network_Packet_Utilities (since I'm writing it this time I get to insist on
the underscores :-).  Then in other units that with your package, you say

    package NPU renames Network_Packet_Utilites;

Now you can use qualified names to explicate the name space relationships in
the formal way rather than the ad hoc way of using format conventions, but
it allows for a less prolix style :-).  I haven't looked at a whole lot of
the Ada code in the GNAT distribution, but I think I've seen that style used
there, and I know it's used internally at Rational in places too.

>
> > The style of "aFoobar" and "anApteryx" for type names seems like a
> different
> > form of the "The_Foobar" cop-out for parameter names -- both meant to
> spare
> > us the trouble of thinking up a parameter name that would be more
> meaningful
> > than just repeating the name of the type, am I right?
>
> Our use of "a" or "an" to start a type definition simply adds instant
> recognition of an identifier as a data type without regard to context.

Well, I have to wonder of what use is that information ("this identifier
names a type") apart from the context.  If there is none, then *to*me* the
"instant" recognition doesn't add value since I have to move immediately to
making some use of that information, and that depends on the context anyway.

(Your reply got me to thinking if there are any places in Ada where the fact
that an identifier names a type is not manifest from the syntax.  The only
case I could think of was that of conversions.  That's not saying you
_shouldn't_ want "instant recognition", only that I can't relate to the
reason why :-)).

It can be fun and instructive to postulate variants of a language, just for
the sake of argument :-).  So I wonder if people who like instant
recognition of types would be happier with an Ada in which occurences of a
type names were all accompanied by the word "type", e.g.

    Foo : constant type Wumpus;
    type Wumpi is array (Blah range <>) of type Wumpus;
    Z := type Wumpus'(X + Y);

(N.B. I am *not* advocating this... :-) :-)  But anyway, would this provide
the same level of satisfaction as building "this is a type" hints into
identifiers?

Some people (not I :-)) like to append "_Generic" or "_G" to generic unit
declarations.  In context of usage, "this is a generic" is even more
apparent than "this is a type", since you can't do squat with a generic
except instantiate it (or name it as a generic formal package, which looks
just like an instantiation), where it's always preceded by "is new" (and
"package", "procedure", or "function").  But one place that can get a little
confusing is in the generic body itself.  I've always sort of wished that
generic bodies weren't identical to nongeneric bodies -- e.g. that you had
to recapitulate the "generic" and the formal part in the body syntax.  I
usually do that in a comment (and then I have to accept the problem of
keeping the body comment in sync with the spec).

> IMHO
> this is not much different than quickly identifying the start of a
sentence
> with a capital letter.

More like the capitalization of nouns in German, I'd say :-)

--mark

P.S. One reason I find Ada style is so interesting is that it's the idea
with Ada that the style of writing should be optimized in favor of readers
rather than the writer (and "reader" of course includes the person of the
"writer" in her role as a reader of her own code).  So the question that
immediately follows is "which reader", because you potentially have a
diverse population of readers who differ in knowledge of Ada, knowledge of
the problem domain, knowledge of the present source text itself (in regard
to which each reader changes as their understanding increases), learning
style, etc., and you're shooting for a "best fit" across all these.  This
relates to commenting style as well as "coding" style.  Certainly it applies
not only to Ada, but to programming in any language where you are attempting
to be reader-friendly...








^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Sucking (was Re: How can I avoid Using a Semaphore? (long))
  2001-02-05 20:07         ` Mark Lundquist
@ 2001-02-06  7:16           ` Sven Nilsson
  0 siblings, 0 replies; 34+ messages in thread
From: Sven Nilsson @ 2001-02-06  7:16 UTC (permalink / raw)


New text follows below ;-)

> There's an Ada style out there that you might find gives you the best of
> both...  To use your code as an example, you would name your package
> Network_Packet_Utilities (since I'm writing it this time I get to insist on
> the underscores :-).  Then in other units that with your package, you say
> 
>     package NPU renames Network_Packet_Utilites;
> 
> Now you can use qualified names to explicate the name space relationships in
> the formal way rather than the ad hoc way of using format conventions, but
> it allows for a less prolix style :-).  I haven't looked at a whole lot of
> the Ada code in the GNAT distribution, but I think I've seen that style used
> there, and I know it's used internally at Rational in places too.

We use it quite extensively as well, if mainly because we have a very
complex system and package names tend to grow terribly long...

> > > The style of "aFoobar" and "anApteryx" for type names seems like a
> > > different
> > > form of the "The_Foobar" cop-out for parameter names -- both meant to
> > > spare
> > > us the trouble of thinking up a parameter name that would be more
> > > meaningful
> > > than just repeating the name of the type, am I right?
> >
> > Our use of "a" or "an" to start a type definition simply adds instant
> > recognition of an identifier as a data type without regard to context.

At my department we (as in someone else about 6 years ago) solved this
by enforcing coding rules that states that "all types shall be declared
as T_XXX and all constants as C_XXX". This yields code that looks
something like this:

	C_Max_Index : constant Natural := 25;
	type T_Index is new Natural range 0..C_Max_Index;

	procedure Foo(Index : in out T_Index);

There you go! Instant recognition of what is a type, what is a constant
and what is a parameter or variable or object. And you can even get it
in context!

> Well, I have to wonder of what use is that information ("this identifier
> names a type") apart from the context.  If there is none, then *to*me* the
> "instant" recognition doesn't add value since I have to move immediately to
> making some use of that information, and that depends on the context anyway.

Actually, there is. Not if you are a compiler, of course, but if you try
to read someone elses program thats written like this:

	function Return_Value_At_Index(Index : Index) return Index is
		I : Index := Index'First;
	begin
		...
	end Return_Value_At_Index;

That, ofcourse, won't compile as it stands, but people can get pretty
imaginative trying to get around that because they want their parameter
to be called something very similar to Index.

> It can be fun and instructive to postulate variants of a language, just for
> the sake of argument :-).  So I wonder if people who like instant
> recognition of types would be happier with an Ada in which occurences of a
> type names were all accompanied by the word "type", e.g.
> 
>     Foo : constant type Wumpus;
>     type Wumpi is array (Blah range <>) of type Wumpus;
>     Z := type Wumpus'(X + Y);
> 
> (N.B. I am *not* advocating this... :-) :-)  But anyway, would this provide
> the same level of satisfaction as building "this is a type" hints into
> identifiers?

That is a brilliant idea! I'll bring it up the next time we discuss
coding rules... Oh and :-) to you too!

> Some people (not I :-)) like to append "_Generic" or "_G" to generic unit
> declarations.  In context of usage, "this is a generic" is even more
> apparent than "this is a type", since you can't do squat with a generic
> except instantiate it (or name it as a generic formal package, which looks
> just like an instantiation), where it's always preceded by "is new" (and
> "package", "procedure", or "function").  But one place that can get a little
> confusing is in the generic body itself.  I've always sort of wished that
> generic bodies weren't identical to nongeneric bodies -- e.g. that you had
> to recapitulate the "generic" and the formal part in the body syntax.  I
> usually do that in a comment (and then I have to accept the problem of
> keeping the body comment in sync with the spec).

Ah, but when you're browsing through your library of packages, it can be
very nice to see in the package name that it is generic. I guess you've
never had to reuse someone elses code...

> > IMHO
> > this is not much different than quickly identifying the start of a
> sentence
> > with a capital letter.
> 
> More like the capitalization of nouns in German, I'd say :-)
> 
> --mark
> 
> P.S. One reason I find Ada style is so interesting is that it's the idea
> with Ada that the style of writing should be optimized in favor of readers
> rather than the writer (and "reader" of course includes the person of the
> "writer" in her role as a reader of her own code).  So the question that
> immediately follows is "which reader", because you potentially have a
> diverse population of readers who differ in knowledge of Ada, knowledge of
> the problem domain, knowledge of the present source text itself (in regard
> to which each reader changes as their understanding increases), learning
> style, etc., and you're shooting for a "best fit" across all these.  This
> relates to commenting style as well as "coding" style.  Certainly it applies
> not only to Ada, but to programming in any language where you are attempting
> to be reader-friendly...

I couldn't agree more! Our projects typically run over 3 to 5 years and
in that time a lot of people will have left the actual implementation
work and moved on to some sort of management. Having read-able code
becomes extremly important in that perspective. Especially if you try to
reuse code from a previous project.
We have rather strict coding rules and naming conventions based on the
Ada style guide and I can only say thank heavens for that!

-Sven



^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2001-02-06  7:16 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-01-13 16:18 How can I avoid Using a Semaphore? (long) DuckE
2001-01-15  1:06 ` How can I avoid Using a Semaphore? Nick Roberts
2001-01-15  3:17   ` Robert Dewar
2001-01-16  3:53   ` DuckE
2001-01-17 15:42     ` Nick Roberts
2001-01-20 18:16       ` DuckE
2001-01-20 19:16         ` Robert Dewar
2001-01-21  1:28           ` DuckE
2001-01-21 16:04             ` Robert Dewar
2001-01-21 23:23               ` DuckE
2001-01-22  0:28                 ` mark_lundquist
2001-01-22  1:51                 ` Robert Dewar
2001-01-23  2:36                   ` DuckE
2001-01-22  0:35               ` Built-in types (was " mark_lundquist
2001-01-22  1:54                 ` Robert Dewar
2001-01-22 16:18                   ` mark_lundquist
2001-01-22 17:20                     ` Robert Dewar
2001-01-22 23:17                       ` Mark Lundquist
     [not found]                         ` <m33deaaeks.fsf@ns40.infomatch.bc.ca>
2001-02-02 22:01                           ` Mark Lundquist
     [not found]                         ` <94km00$bv8$1@nnrp1.deja.com>
2001-02-02 22:03                           ` Mark Lundquist
2001-01-21 16:53           ` Nick Roberts
2001-01-21 18:24             ` Robert Dewar
2001-01-23  0:21               ` Nick Roberts
2001-01-22  0:16         ` mark_lundquist
2001-01-22 16:51 ` How can I avoid Using a Semaphore? (long) mark_lundquist
2001-01-23  6:02   ` DuckE
2001-02-02 22:00     ` Sucking (was Re: How can I avoid Using a Semaphore? (long)) Mark Lundquist
2001-02-03  1:44       ` Jeffrey Carter
2001-02-03  3:21       ` DuckE
2001-02-05 20:07         ` Mark Lundquist
2001-02-06  7:16           ` Sven Nilsson
2001-02-02 22:18     ` How can I avoid Using a Semaphore? (long) 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