GLAST / LAT > DAQ and FSW > FSW > Doxygen Index> PBS / dev > pbs / sun-gcc


Interface   Data Structures   File List   Data Fields   Globals  

RNG.h File Reference

Ring Bufffer memory manager, configures and manages a pool of memory as a ring buffer. More...

#include <PBS/RW_type.h>
#include <PBS/TOC_comdefs.h>
#include <PBS/TOV.h>

Classes

struct  _RNG_dsc
 This describes all the static properties of the ring buffer. More...

Defines

#define RNG_K_PTR_ERROR   ((void *)(1))
 Returned by either the RNG_get() or RNG_grab routines when an internal error is detected.
#define RNG_PTR_IS_VALID(ptr)   ( (void *)ptr > RNG_K_PTR_ERROR)
 Checks that the returned pointer is valid.
#define RNG_PTR_IS_ERROR(ptr)   ( (void *)ptr == RNG_K_PTR_ERROR)
 Checks if the pointer is indicates failure to allocate because of an error.

Typedefs

typedef enum _RNG_type RNG_type
 Typedef for enum _RNG_type.
typedef struct _RNG_dsc RNG_dsc
 Typedef for struct _RNG_dsc.

Enumerations

enum  _RNG_type {
  RNG_K_TYPE_LOCKING_ONLY = RW_K_TYPE_LOCKING_ONLY,
  RNG_K_TYPE_PENDING = RW_K_TYPE_PENDING,
  RNG_K_TYPE_PENDING_WTO = RW_K_TYPE_PENDING_WTO
}
 An enumeration of the types of ring buffers that can be created. More...

Functions

const RNG_dscRNG_dsc_get (const RNG_rcb *rcb)
 Query routine to return a pointer to the ring buffer description structure.
int RNG_sizeof_rcb (void)
 Returns the size of the Ring Contol Block.
int RNG_init (RNG_rcb *rcb, RNG_type type, void *buffer, int size, int underflow, int overflow, int alignment)
 Initializes the control structure for a Ring buffer.
int RNG_destroy (RNG_rcb *rcb)
 Returns any resources associated with this ring buffer.
void * RNG_get (RNG_rcb *rcb, int request, const void *write)
 Non-blocking allocation request for a specified amount of memory.
void * RNG_getW (RNG_rcb *rcb, int request, const void *write)
 Blocking allocation request for a specified amount of memory.
void * RNG_getW_toc (RNG_rcb *rcb, int request, const void *check_Wr, const TOC *toc)
 Blocking allocation request for a specified amount of memory, with timeout.
void * RNG_grab (RNG_rcb *rcb, int minimum, const void *write, int *allocated)
 Non-blocking allocation request for all the remaining contigious memory, i.e. a greedy form of RNG_get.
void * RNG_grabW (RNG_rcb *rcb, int minimum, const void *write, int *allocated)
 Blocking allocation request for all the remaining contigious memory, i.e. a greedy form of RNG_getW.
void * RNG_grabW_toc (RNG_rcb *rcb, int minimum, const void *check_wr, int *allocated, const TOC *toc)
 Blocking allocation request for all the remaining contigious memory with a timeout, i.e. a greedy form of RNG_getWtos.
int RNG_free (RNG_rcb *rcb, const void *packet, int amount)
 Frees the requested amount of memory from the specified address.
void * RNG_shrink (RNG_rcb *rcb, const void *write, int left)
 Shrinks the previously allocated packet back to the specified address.
int RNG_reset (RNG_rcb *rcb)
 If the ring buffer is empty, reset the read and write pointers to their initial positions. This can only be called if the user knows that the buffer is empty.


Detailed Description

Ring Bufffer memory manager, configures and manages a pool of memory as a ring buffer.

Author:
JJRussell - russell@slac.stanford.edu
  
   CVS $Id: RNG.h,v 1.4 2011/03/24 23:05:44 apw Exp $

SYNOPSIS
Implements a set of routines for managing a single writer / single reader ring buffer. The routines are thread and interrupt level safe, although one should not use the blocking forms RNG_getW() and RNG_grabW() nor any of their timeout variations in interrupt routines. While nothing in the code prohibits multiple writers and readers, using a ring buffer in this fashion runs is not natural. Ring buffers are really just a software implementation of a FIFO, which, by its nature, is a single writer, single reader object.


Define Documentation

#define RNG_K_PTR_ERROR   ((void *)(1))

Returned by either the RNG_get() or RNG_grab routines when an internal error is detected.

Warning:
The caller should not use this value directly, rather the macros RNG_GET_IS_VALID(ptr) and RNG_GET_IS_ERROR(ptr) should be used.

Referenced by rng_allocate().

#define RNG_PTR_IS_ERROR ( ptr   )     ( (void *)ptr == RNG_K_PTR_ERROR)

Checks if the pointer is indicates failure to allocate because of an error.

Parameters:
ptr The pointer to check
Return values:
0,the pointer is not an error condition pointer
1,the pointer is an error condition pointer
This macro checks if the pointer is an error condition pointer. Currently there is only one error condition pointer. This occurs when the next allocation pointer, as provided by the user does not match the expected value. Note that a NULL pointer means what it has always traditionally meant, i.e. out of memory

#define RNG_PTR_IS_VALID ( ptr   )     ( (void *)ptr > RNG_K_PTR_ERROR)

Checks that the returned pointer is valid.

Parameters:
ptr The pointer to check
Return values:
0,if the pointer is invalid
1,if the pointer is valid
The returned pointer from the RNG_get() or RNG_grab() routines can be invalid for two general reasons.

  • No memory
  • Internal inconsistancy

This macro checks that the pointer is not one of these values. This attempts to address the age old problem of how to indicate an error condition without resorting to an additional parameter for a status value.


Typedef Documentation

Typedef for struct _RNG_dsc.

This structure describes all the static properties of the ring buffer.

The ring buffer composed of three pieces carved out of a user provided block of memory. The three pieces are

     Underflow area
     Main pool
     Overflow area
  

Picturally the ring buffer looks like


      +---------------+  beg
      |               |
      |   Underflow   |
      |               |
      +---------------+ rbeg
      |               |
      |   Main        |
      |   Ring        |
      |   Buffer      |
      |               |
      +---------------+ rend
      |               |
      |   Underflow   |
      |               |
      +---------------+  end
      
  

As is common practice, the pointers to the beginning of the areas point at the real beginning and the pointers to the ending of the areas point one past the actual last address so that sizes are trivially calculated.

As a convenience the address of the initial buffer, its size and the requested ring buffer type are also kept in this structure. This may be useful to the user when he later attempts to free this memory.

Note that due to alignment rounding the initial buffer address and size may not match the ring buffer's beginning address and size.

Typedef for enum _RNG_type.

This determines how the ring allocators, RNG_getW() and RNG_grabW(), calls will behave when an allocation is attempted on an empty pool. One can specify non-blocking or blocking and with and without timeouts.

Note that there is no choice as to the blocking types as one sees in the LLI facility. This is because the blocking type affects only the behavior when multiple tasks are being blocked. Given the single writer / single reader nature of the ring buffer, the issue what to do when multiple tasking are pending never comes up.

If a non-blocking type is requested, common practice would be to use the simpler RNG_get() routine, since it never waits. The RNG_getWxxx and RNG_grabWxxx should not be used in this case, although their behavior is currently defined to degenerate to the RNG_get and RNG_grab, respectively.


Enumeration Type Documentation

enum _RNG_type

An enumeration of the types of ring buffers that can be created.

Enumerator:
RNG_K_TYPE_LOCKING_ONLY  Locking mechanism only, no blocking mechanism available
RNG_K_TYPE_PENDING  Enable blocking when the pool is exhausted
RNG_K_TYPE_PENDING_WTO  Enable blocking with timeouts when the pool is exhausted,


Function Documentation

int RNG_destroy ( RNG_rcb rcb  ) 

Returns any resources associated with this ring buffer.

Parameters:
rcb The Ring Control Block
Return values:
Status Frees any internally gathered resources associated with the specified ring buffer. The rcb is no longer usable as ring buffer after this call.
Warning:
It is the user's responsibility to dispose of the memory associated with the buffer that was being managed and the memory containing the Ring Control Block.

References _RNG_rcb::rw, and RW_destroy().

const RNG_dsc* RNG_dsc_get ( const RNG_rcb rcb  ) 

Query routine to return a pointer to the ring buffer description structure.

Parameters:
rcb The ring control block
Return values:
A pointer to ring buffer description
Returns a pointer to the ring buffer description structure. This structure contains all the static information about the ring buffer. Because these properties are static, the user may cache a pointer to this structure or the value of any of its elements. They will not change from the time the ring buffer is initialized until it is destroyed.

Here is a overview of the elements and there use.

beg This a pointer to the top of the underflow portion of the buffer. If if there is no underflow area, this will be the same as rbeg. Because of alignment reason, this pointer may or may not agree with the original buffer pointer passed in by the user.

rbeg Pointer to the top of the ring buffer proper.

rend Pointer to the bottom of the ring buffer proper. Also, by definition, the start of the overflow area.

end Pointer to the bottom of the overflow area.

msk The alignment mask, for shorts = 1, ints = 3, long long = 7

buf The original buffer pointer passed into RCB_init by the user. This routine along with bufsize allows the user to recover the original address and size of the pool of memory the RNG utilities where requested to manage. This may be useful when closing the ring buffer, allowing the user to return the managed memory to where ever it came from.

bufsize The size of the original buffer

References _RNG_rcb::dsc.

int RNG_free ( RNG_rcb rcb,
const void *  packet,
int  amount 
)

Frees the requested amount of memory from the specified address.

Parameters:
rcb The Ring Control Block
packet The pointer where the free begins
amount The amount of memory to free
Return values:
0 Successful
-1 Packet being freed is not contigous with the previous packet being freed
-2 Packet being freed extended into the shard area. Since this area is owned by the ring buffer and cannot belong to the user, this is a user specification error.
Frees the requested amount of memory beginning at ptr. Note that, unlike many other allocators, RNG_free allows partial freeing. One is not obligated to match allocations and deallocations. The only restriction is that the free ptr must be consistent with the next location to be freed by the Ring Buffer utilities, and that one frees only that which is allocated.

If fails, the current read pointer is returned. The only practical reason for failing is that the packet being freed is does not match the current read pointer. Currently there is no sanity check to prevent the user from freeing more memory than is actually allocated. That is fairly expensive and, the thought is, if one does this, the next free is going to fail. This is a little dicey, but see how this works. If it doesn't will add the proper sanity check.

There is one case where overfreeing is detected, that is when the packet being freed extends into the user area. As compared with detecting an arbritary overfree, this one is relatively cheap, so it is done.

References _RNG_dsc::beg, _RNG_rcb::dsc, _RNG_rcb::dyn, _RNG_dsc::end, _RNG_dsc::msk, _RNG_dyn::que, _RNG_dyn::rd, _RNG_dyn::rdx, _RNG_dsc::rend, ROUND_TO, _RNG_rcb::rw, RW__lock(), RW__unlock(), RW__wake(), RW_M_OPT_PEND, _RNG_rcb::size, _RNG_dsc::type, and _RNG_dyn::wr.

void* RNG_get ( RNG_rcb rcb,
int  request,
const void *  write 
)

Non-blocking allocation request for a specified amount of memory.

Parameters:
rcb The Ring Control Block
request The size of the request, in bytes.
write The end of the previously allocated block. Given the loose nature of ring buffers, this is used as an integrity check. If one is feeling brave, this may be specified as NULL. Doing this will skip the integrity checking.
Returns:
If successful, a pointer to the allocated memory, else NULL.
Attempts to allocate the requested amount of memory. If insufficient memory is available or the write pointer is inconsistent with the internal write pointer, NULL is returned. The user can distinguish these two cases by calling RNG_wr(), to fetch the current value of the write pointer. The user may also live dangerously and specify NULL for the write argument, in which case the consistency check is bypassed. No check is made to see if the request is for more memory than can ever be satisfied.

Special Cases
If the request is for 0 bytes, the next write pointer is returned. This allows the user to refresh where in the buffer the next write will come from. Alternatively, the user can use this value to check his own prejudice on the value of the next write pointer.
Note:
Remember, this is used as an integrity check. In some cases, the value of the returned write pointer will not match this value because of the wrap-around nature of ring buffers. Effectively all values of the write pointer past the end of the ring buffer proper must be remapped to the beginning of the ring buffer. Maybe a better way to thing of the write pointer is as the value at the end of the last allocation. It only so happens that a large fraction of the time this value is also the value of returned by the next get.

References _RNG_rcb::dyn, rng_allocate(), TOC_NOWAIT, and _RNG_dyn::wrx.

void* RNG_getW ( RNG_rcb rcb,
int  request,
const void *  write 
)

Blocking allocation request for a specified amount of memory.

Parameters:
rcb The Ring Control Block
request The size of the request, in bytes.
write The end of the previously allocated block. Given the loose nature of ring buffers, this is used as an integrity check. If one is feeling brave, this may be specified as NULL. Doing this will skip the integrity checking.
Returns:
If successful, a pointer to the allocated memory, else NULL.
Attempts to allocate the requested amount of memory. If insufficient memory is available RNG_getW blocks until the requested amount is available. No check is made to see if the request is for more memory than can every be satisfied.

If the write pointer is inconsistent with the internal write pointer, NULL is returned. The user can distinguish these two cases by calling RNG_wr(), to fetch the current value of the write pointer. The user may also live dangerously and specify NULL for the write argument, in which case the consistency check is bypassed.

References _RNG_rcb::dyn, rng_allocate(), TOC_FOREVER, and _RNG_dyn::wrx.

void* RNG_getW_toc ( RNG_rcb rcb,
int  request,
const void *  write,
const TOC toc 
)

Blocking allocation request for a specified amount of memory, with timeout.

Parameters:
rcb The Ring Control Block
request The size of the request, in bytes
write The end of the previously allocated block. Given the loose nature of ring buffers, this is used as an integrity check. If one is feeling brave, this may be specified as NULL. Doing this will skip the integrity checking.
toc The timeout control structure. This specifies the timeout value. TOC_NOWAIT and TOC_FOREVER may be specified here, although in this case the user should consider using RNG_get or RNG_getW.
Returns:
If successful, a pointer to the allocated memory, else NULL.
Attempts to allocate the requested amount of memory. If insufficient memory is available RNG_getW blocks until the requested amount is available or until the timeout period has expired. No check is made to see if the request is for more memory than can every be satisfied.

If the write pointer is inconsistent with the internal write pointer, NULL is returned. The user can distinguish these two cases by calling RNG_wr(), to fetch the current value of the write pointer. The user may also live dangerously and specify NULL for the write argument, in which case the consistency check is bypassed.

References _RNG_rcb::dyn, rng_allocate(), and _RNG_dyn::wrx.

void* RNG_grab ( RNG_rcb rcb,
int  minimum,
const void *  write,
int *  allocated 
)

Non-blocking allocation request for all the remaining contigious memory, i.e. a greedy form of RNG_get.

Parameters:
rcb The Ring Control Block
minimum The minimum size requested, in bytes.
write The end of the previously allocated block. Given the loose nature of ring buffers, this is used as an integrity check. If one is feeling brave, this may be specified as NULL. Doing this will skip the integrity checking.
allocated Pointer to receive the actual amount, in bytes, that was allocated.
Returns:
If successful, a pointer to the allocated memory, else NULL.
This is a greedy form of allocation. All the contigious memory from the current write pointer on is allocated to the caller provided this amount is larger than the minimum requested. This allows the user to continually fill memory even if does not know at allocation time how much is needed. This routine is often used with RNG_shrink(). Here one allocates as much as one can with RNG_grab, uses what he wants, then returns the unused portion by calling RNG_shrink().

If there is less than the minimum amount of memory in the pool, NULL is returned.

References rng_allocate(), and TOC_NOWAIT.

void* RNG_grabW ( RNG_rcb rcb,
int  minimum,
const void *  write,
int *  allocated 
)

Blocking allocation request for all the remaining contigious memory, i.e. a greedy form of RNG_getW.

Parameters:
rcb The Ring Control Block
minimum The minimum size requested, in bytes.
write The end of the previously allocated block. Given the loose nature of ring buffers, this is used as an integrity check. If one is feeling brave, this may be specified as NULL. Doing this will skip the integrity checking.
allocated Pointer to receive the actual amount, in bytes, that was allocated.
Returns:
If successful, a pointer to the allocated memory, else NULL.
This is a greedy form of allocation. All the contigious memory from the current write pointer on is allocated to the caller provided this amount is larger than the minimum requested. This allows the user to continually fill memory even if does not know at allocation time how much is needed. This routine is often used with RNG_shrink(). Here one allocates as much as one can with RNG_grab, uses what he wants, then returns the unused portion by calling RNG_shrink().

If there is less than the minimum amount of memory in the pool, RNG_grabW waits until the memory shows up. NULL is only on an internal error.

References rng_allocate(), and TOC_FOREVER.

void* RNG_grabW_toc ( RNG_rcb rcb,
int  minimum,
const void *  write,
int *  allocated,
const TOC toc 
)

Blocking allocation request for all the remaining contigious memory with a timeout, i.e. a greedy form of RNG_getWtos.

Parameters:
rcb The Ring Control Block
minimum The minimum size of the request, in bytes.
write The end of the previously allocated block. Given the loose nature of ring buffers, this is used as an integrity check. If one is feeling brave, this may be specified as NULL. Doing this will skip the integrity checking.
allocated Returned as the amount of memory actually allocated.
toc The timeout control structure. This specifies the timeout value. TOC_NOWAIT and TOC_FOREVER may be specified here, although in this case the user should consider using RNG_grab or RNG_grabW.
Returns:
If successful, a pointer to the allocated memory, else NULL.
Attempts to allocate the requested amount of memory. If insufficient memory is available RNG_grabW blocks until the requested amount is available or until the timeout period has expired. No check is made to see if the request is for more memory than can every be satisfied.

If the write pointer is inconsistent with the internal write pointer, NULL is returned. The user can distinguish these two cases by calling RNG_wr(), to fetch the current value of the write pointer. The user may also live dangerously and specify NULL for the write argument, in which case the consistency check is bypassed.

References rng_allocate().

int RNG_init ( RNG_rcb rcb,
RNG_type  type,
void *  buffer,
int  size,
int  underflow,
int  overflow,
int  alignment 
)

Initializes the control structure for a Ring buffer.

Parameters:
rcb Pointer to the ring buffer control block structure to be initialized.
type Indicates the type of ring buffer. This mainly controls the blocking. If insufficient memory is available, the allocation calls will block until it becomes available or a timeout occurs.
buffer The buffer to be managed
size The total size of the buffer (in bytes) to be managed
underflow The size (in bytes) to be assigned to the underflow area. This area is an area immediately preceeding the ring buffer area.
Warning:
Currently this feature is not implemented and should be specified as 0. It is provided for forward compatibility.
Parameters:
overflow The size (in bytes) to be assigned to the overflow area. This area carved from the end buf. The useful property of the overflow area is that while memory may be allocated from the overflow area, an initial allocation never begins in the overflow area. This allows some continuity when the wrap-around point of the ring buffer is encountered.
This number may be 0, but must be less than the total size since it taken from the total size.

Parameters:
alignment The byte alignment, expressed in binary powers of 2, eg
  • 0 => 1 byte alignment
  • 1 => 2 byte alignment
  • 2 => 4 byte alignment
  • 3 => 8 byte alignment
Return values:
Status Initializes a Ring Control Block to manage a pool of memory. The memory is carved into three pieces, an underflow area, a ring buffer area, and an overflow area. The detailed use and meaning of these areas is described elsewhere.

References _RNG_dsc::beg, _RNG_dsc::buf, _RNG_dsc::bufsize, _RNG_rcb::dsc, _RNG_rcb::dyn, _RNG_dsc::end, _RNG_dsc::msk, _RNG_dyn::que, _RNG_dsc::rbeg, _RNG_dyn::rd, _RNG_dyn::rdx, _RNG_dsc::rend, ROUND_TO, _RNG_rcb::rw, RW_init(), _RNG_rcb::size, _RNG_dsc::type, _RNG_dyn::wr, and _RNG_dyn::wrx.

int RNG_reset ( RNG_rcb rcb  ) 

If the ring buffer is empty, reset the read and write pointers to their initial positions. This can only be called if the user knows that the buffer is empty.

Parameters:
rcb The Ring Control Block
Returns:
If 0 is successful else ERROR (-1). The only plausible error is that a reset was requested on a buffer that was not empty.
Unlike many allocators a Ring Buffer has many states that correspond to the empty state. Consider the initial state, the read pointer is at the bottom of the buffer and the write pointer is at the top. After on allocation the read pointer is at the top of the buffer and the write pointer is at the end of the allocated buffer. If the buffer is now freed, the read pointer advances to the write pointer. The ring buffer is now totally empty, however, it is a different empty state than the original empty state. One consequence of this is that a request on the original state could be as large as the entire ring buffer and succeed. However, the same request on the second empty state would fail. This is because the largest contigious block availabe is from the current write pointer to the end of the buffer. Since the write pointer is not at the top of the buffer, this contigious block is necessarily smaller.

So, one may ask, why not just reset the pointers to the empty state any time the ring buffer is totally empty. The answer is that this destroys any history that the ring buffer may accumulate. Imagine the case where one allocates some memory and then immediately frees it. The current implementation would deliver a different memory block each time. In a debugging mode, one could go back and examine this memory for some clues. If the buffer pointers where to be continually reset, this the memory would always be allocated from the top of the pool, and this debugging feature would be lost.

One possible alternative would be to make this resetting a optional configuration parameter on the ring buffer initialization. That way this would happen automatically.

References _RNG_dsc::beg, _RNG_rcb::dsc, _RNG_rcb::dyn, _RNG_dsc::end, _RNG_dyn::rd, _RNG_dyn::rdx, _RNG_rcb::size, _RNG_dyn::wr, and _RNG_dyn::wrx.

void* RNG_shrink ( RNG_rcb rcb,
const void *  write,
int  left 
)

Shrinks the previously allocated packet back to the specified address.

Parameters:
rcb The Ring Control Block
write The address to shrink to. The current write pointer, up to alignment factors, is moved to this address.
left The unused amount, in bytes, of the previously allocated packet. This value + write addresss must match the current write pointer. If not, error. Note that the amount being returned must be consistent with the alignment factors. Concretely stated, if one demands 8-byte alignment, one cannot return in units less than 8-bytes.
Returns:
If successful, the next write pointer. Due to alignment reasons, this may or may not be the same as write. If NULL, error.
Routine shrinks the previously allocated packet back to the specified address. A check is performed to see if this write pointer plus the number of bytes left in the old allocation is consistent with the Ring Buffer Manager's internal write pointer. If not, NULL is returned.

Typically one would allocate a block of memory, and fill it by advancing the pointer returned and decreasing the amount left. After filling the buffer, one would then call RNG_shrink to return the unused portion. The parameters to RNG_shrink will be the address of the next location to be written and the amount left.

Note also that this has no consequences on waking anyone up who may be waiting for memory. By definition, this is a single allocator system. Since, RNG_shrink is really just extension of the allocation process, no one can be waiting.

EXAMPLE
-------

      amount = 100;
      ptr    = RNG_get (rcb, amount, prv);
      if (ptr == NULL) perror ("No memory\n");

      *ptr++ = 0xdeadbeef;  amount -= 1;
      *ptr++ = 0xabadbabe;  amount -= 1;

      chk    = RNG_shrink (rcb, ptr, amount);
      if (chk == NULL) perror ("Bad shrink\n");

References _RNG_dsc::beg, _RNG_rcb::dsc, _RNG_rcb::dyn, _RNG_dsc::msk, _RNG_dyn::que, _RNG_dyn::rd, _RNG_dyn::rdx, _RNG_dsc::rend, _RNG_rcb::size, _RNG_dyn::wr, and _RNG_dyn::wrx.

int RNG_sizeof_rcb ( void   ) 

Returns the size of the Ring Contol Block.

Return values:
The size of a Ring Control Block
This routine allows the user to allocate or set aside a block of memory to be used as Ring Control Block. It is the first step when initializing a Ring Control buffer. This routine allows the implementation to hide the internal structure of a Ring Control Block, but still allow the user to control its allocation.


Generated on Fri Aug 5 18:35:01 2011 by  doxygen 1.5.8