#include <stdio.h>
#include "BBC/RNG.h"
#include "BBC/BUG.h"
Data Structures | |
| struct | _RNG_rcb |
Defines | |
| #define | NULL ((unsigned char *)0) |
| NULL pointer definition. | |
| #define | RND_TO(_ptr, _msk) (((unsigned int)(_ptr) + _msk) & ~_msk) |
| Rounds the specified address up to the nearest binary boundary. | |
Functions | |
| void | rng_bdestroy (struct block *block) |
| Closes the blocking control structure. More... | |
| void | rng_binit (struct block *block) |
| Initializes the blocking control structure. More... | |
| void | rng_wake (struct block *block, int freeing) |
| Awakens an allocator if freeing the specified amount has a chance of satisfying the request. More... | |
| int | rng_wait (struct block *block, unsigned char *volatile *rrd, unsigned char *rd, int needed, int timeout) |
| Blocks the requestor until enough memory is returned to satisfy the request or until timeout period expires. More... | |
| void * | allocate (struct _RNG_rcb *rcb, int minimum, const void *curWrt, int *allocated, int timeout) |
| The underlying workhorse allocator. More... | |
| void * | RNG_buf (const struct _RNG_rcb *rcb) |
| Query routine to return a pointer to the original buffer. More... | |
| int | RNG_bsize (const struct _RNG_rcb *rcb) |
| Query routine to return the size of the original buffer. More... | |
| void * | RNG_beg (const struct _RNG_rcb *rcb) |
| Query routine to return a pointer to the beginning of the underflow area. More... | |
| void * | RNG_rbeg (const struct _RNG_rcb *rcb) |
| Query routine to return a pointer to the beginning of the ring buffer area. More... | |
| void * | RNG_rend (const struct _RNG_rcb *rcb) |
| Query routine to return a pointer to the end of the ring buffer area. More... | |
| void * | RNG_end (const struct _RNG_rcb *rcb) |
| Query routine to return a pointer to the end of the overflow area. More... | |
| void * | RNG_rd (const struct _RNG_rcb *rcb) |
| Query routine to return a pointer to current read pointer the ring buffer area. More... | |
| void * | RNG_wr (const struct _RNG_rcb *rcb) |
| Query routine to return a pointer to the current write pointer. More... | |
| void * | RNG_shard (const struct _RNG_rcb *rcb) |
| Query routine to return a pointer to current list of shards. More... | |
| int | RNG_destroy (struct _RNG_rcb *rcb) |
| Returns any resources associated with this ring buffer. More... | |
| int | RNG_sizeof_rcb () |
| Returns the size of the Ring Contol Block. More... | |
| int | RNG_init (struct _RNG_rcb *rcb, unsigned char *buf, int size, int underflow, int overflow, int alignment, RNG_type blocking) |
| Initializes the control structure for a Ring buffer. More... | |
| void * | RNG_get (struct _RNG_rcb *rcb, int request, const void *nxtWrt) |
| Non-blocking allocation request for a specified amount of memory. More... | |
| void * | RNG_getW (struct _RNG_rcb *rcb, int request, const void *nxtWrt, int timeout) |
| Blocking allocation request for a specified amount of memory. More... | |
| void * | RNG_grab (struct _RNG_rcb *rcb, int minimum, const void *nxtWrt, int *allocated) |
| Non-blocking allocation request for all the remaining contigious memory. More... | |
| void * | RNG_grabW (struct _RNG_rcb *rcb, int minimum, const void *nxtWrt, int *allocated, int timeout) |
| Bocking allocation request for all the remaining contigious memory. More... | |
| int | RNG_free (struct _RNG_rcb *rcb, const void *packet, int amount) |
| Frees the requested amount of memory from the specified address. More... | |
| void * | RNG_shrink (struct _RNG_rcb *rcb, const void *newWrt, int left) |
| Shrinks the previously allocated packet back to the specified address. More... | |
| int | RNG_reset (struct _RNG_rcb *rcb) |
| If the pool is empty, resets the WR/RD pointers to their initial values. More... | |
The writer (allocator) only need modify the WRITE pointer, while the reader (freer) need only modify the READ pointer. Each may reference the contents of the other pointer. These references may be 'stale', in the sense that the actual value may change, but the consequences of this are beign. For instance, consider the allocater. It must determine how much memory is still available in the pool. It does this by calculating the distance between the READ and WRITE pointers. Potentially, a freer could interrupt this thread of execution just after this value is calculated. However, all this really means is that the allocator may not see all the memory that is available at that exact instance in time. So two things will happen in this case
1. There is enough memory to satisfy the request 2. There is not enough memory to satisfy the request
In the first case, all is well, the allocator got what he wanted. In the second case, the allocator is forced to retry. This is really no different than if the allocator had been called slightly sooner (before the free routine could put back the memory), so unless there is some highly determinestic reason which sequences the allocator and freer, this is just the luck of the draw.
There is, as always, one complication; how to distinguish the completely full state from the completely empty state. The tact taken here is to always contain the WRITE pointer within the pool, but, when the pool is completely empty, to represent the READ pointer by the WRITE pointer + the size of the buffer. This means that the READ buffer can potentially point outside the buffer. This is okay, provided that anytime this value is used, it is first checked to see if it is outside the pool. It can then be constrained to be within the pool simply be subtracting the size of the pool.
The WRITE (allocator) does this when the distance between the two pointers is calculated. If this distance is the size of the pool, read pointer can be safely pushed to it's value - length of the pool. There is no danger of the FREER manipulating the pointer, since all the memory is allocated, ie there is no **legitimate** reason for the free routine to be called.
IMPLEMENTATION NOTE 2
---------------------
These first two variables WR and RD can potentially be modified from different threads, so references to these values cannot be optimized out. After much experimenting, I finally landed on the following syntax for declaring the value of the pointer to be volatile. Note that this is not the same as
volatile unsigned char *adr;
This declares the contents at the location adr to be volatile, not the value of adr. The former is what one usually wants, but in this case, it is the value of adr that is volatile.
Without the volatile declaration the optimizer is free to tranform
w1 = rcb->wr; w1 = rcb->wr; w2 = rcb->wr; into w2 = w1; w3 = rcb->wr; w3 = w1;
If rcb->wr is being modified from another thread of execution, this is incorrect.
|
||||||||||||||||||||||||
|
The underlying workhorse allocator.
|
|
|
Closes the blocking control structure.
|
|
|
Query routine to return a pointer to the beginning of the underflow area.
|
|
|
Initializes the blocking control structure.
|
|
|
Query routine to return the size of the original buffer.
|
|
|
Query routine to return a pointer to the original buffer.
|
|
|
Returns any resources associated with this ring buffer.
|
|
|
Query routine to return a pointer to the end of the overflow area.
|
|
||||||||||||||||
|
Frees the requested amount of memory from the specified address.
|
|
||||||||||||||||
|
Non-blocking allocation request for a specified amount of memory.
|
|
||||||||||||||||||||
|
Blocking allocation request for a specified amount of memory.
|
|
||||||||||||||||||||
|
Non-blocking allocation request for all the remaining contigious memory.
If there is less than the minimum amount of memory in the pool, NULL is returned. |
|
||||||||||||||||||||||||
|
Bocking allocation request for all the remaining contigious memory.
If less the timeout period expires or the internal write pointer is inconsistent with the chkWrt argument, NULL is returned. The user may distinguish these cases by calling RNG_wr().
|
|
||||||||||||||||||||||||||||||||
|
Initializes the control structure for a Ring buffer.
|
|
|
Query routine to return a pointer to the beginning of the ring buffer area.
|
|
|
Query routine to return a pointer to current read pointer the ring buffer area.
|
|
|
Query routine to return a pointer to the end of the ring buffer area.
|
|
|
If the pool is empty, resets the WR/RD pointers to their initial values.
|
|
|
Query routine to return a pointer to current list of shards.
|
|
||||||||||||||||
|
Shrinks the previously allocated packet back to the specified address.
|
|
|
Returns the size of the Ring Contol Block.
|
|
||||||||||||||||||||||||
|
Blocks the requestor until enough memory is returned to satisfy the request or until timeout period expires.
|
|
||||||||||||
|
Awakens an allocator if freeing the specified amount has a chance of satisfying the request.
|
|
|
Query routine to return a pointer to the current write pointer.
|
1.2.13.1 written by Dimitri van Heesch,
© 1997-2001