comp.lang.ada
 help / color / mirror / Atom feed
From: "DuckE" <nospam_steved94@home.com>
Subject: Re: How can I avoid Using a Semaphore?
Date: Tue, 16 Jan 2001 03:53:41 GMT
Date: 2001-01-16T03:53:41+00:00	[thread overview]
Message-ID: <9BP86.270637$U46.8654942@news1.sttls1.wa.home.com> (raw)
In-Reply-To: 93ti8b$bjpps$1@ID-25716.news.dfncis.de


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







  parent reply	other threads:[~2001-01-16  3:53 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox