mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-03-26 00:34:17 -07:00
Make the abq module manage elements of arbitrary type (knowing only their address and size) instead of managing cbsblock only. (this is preparatory to removing cbsblock from the cbs public interface.)
Update abqtest to use the new interface. Add ABQ design. Copied from Perforce Change: 182013 ServerID: perforce.ravenbrook.com
This commit is contained in:
parent
e0e34a1c98
commit
2987b9fc04
4 changed files with 354 additions and 127 deletions
209
mps/code/abq.c
209
mps/code/abq.c
|
|
@ -1,18 +1,15 @@
|
|||
/* abq.c: AVAILABLE BLOCK QUEUE
|
||||
/* abq.c: QUEUE IMPLEMENTATION
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .readership: Any MPS developer
|
||||
* .purpose: A fixed-length FIFO queue.
|
||||
*
|
||||
* .purpose: A FIFO queue substrate for <code/poolmv2.c>
|
||||
*
|
||||
* .design: See <design/poolmvt/>
|
||||
* .design: <design/abq/>
|
||||
*/
|
||||
|
||||
#include "meter.h"
|
||||
#include "abq.h"
|
||||
#include "cbs.h"
|
||||
#include "mpm.h"
|
||||
|
||||
SRCID(abq, "$Id$");
|
||||
|
|
@ -20,37 +17,39 @@ SRCID(abq, "$Id$");
|
|||
|
||||
/* Private prototypes */
|
||||
|
||||
static Size ABQQueueSize(Count elements);
|
||||
static Size ABQQueueSize(Count elements, Size elementSize);
|
||||
static Index ABQNextIndex(ABQ abq, Index index);
|
||||
static Addr ABQElement(ABQ abq, Index index);
|
||||
|
||||
|
||||
/* Methods */
|
||||
|
||||
/* ABQInit -- Initialize an ABQ
|
||||
*
|
||||
* items is the number of items the queue can hold
|
||||
* elements is the number of elements the queue can hold
|
||||
*/
|
||||
Res ABQInit(Arena arena, ABQ abq, void *owner, Count items)
|
||||
Res ABQInit(Arena arena, ABQ abq, void *owner, Count elements, Size elementSize)
|
||||
{
|
||||
Count elements;
|
||||
void *p;
|
||||
Res res;
|
||||
|
||||
AVERT(Arena, arena);
|
||||
AVER(abq != NULL);
|
||||
AVER(items > 0);
|
||||
AVER(elements > 0);
|
||||
|
||||
elements = items + 1;
|
||||
|
||||
res = ControlAlloc(&p, arena, ABQQueueSize(elements),
|
||||
/* Necessary in order to be able to distinguish "empty" from "full" */
|
||||
elements = elements + 1;
|
||||
|
||||
res = ControlAlloc(&p, arena, ABQQueueSize(elements, elementSize),
|
||||
/* withReservoirPermit */ FALSE);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
abq->elements = elements;
|
||||
abq->elementSize = elementSize;
|
||||
abq->in = 0;
|
||||
abq->out = 0;
|
||||
abq->queue = (CBSBlock *)p;
|
||||
abq->queue = p;
|
||||
|
||||
METER_INIT(abq->push, "push", owner);
|
||||
METER_INIT(abq->pop, "pop", owner);
|
||||
|
|
@ -67,19 +66,12 @@ Res ABQInit(Arena arena, ABQ abq, void *owner, Count items)
|
|||
/* ABQCheck -- validate an ABQ */
|
||||
Bool ABQCheck(ABQ abq)
|
||||
{
|
||||
Index index;
|
||||
|
||||
CHECKS(ABQ, abq);
|
||||
CHECKL(abq->elements > 0);
|
||||
CHECKL(abq->elementSize > 0);
|
||||
CHECKL(abq->in < abq->elements);
|
||||
CHECKL(abq->out < abq->elements);
|
||||
CHECKL(abq->queue != NULL);
|
||||
/* Is this really a local check? */
|
||||
for (index = abq->out; index != abq->in; ) {
|
||||
CHECKL(CBSBlockCheck(abq->queue[index]));
|
||||
if (++index == abq->elements)
|
||||
index = 0;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -95,7 +87,7 @@ void ABQFinish(Arena arena, ABQ abq)
|
|||
METER_EMIT(&abq->pop);
|
||||
METER_EMIT(&abq->peek);
|
||||
METER_EMIT(&abq->delete);
|
||||
ControlFree(arena, abq->queue, ABQQueueSize(abq->elements));
|
||||
ControlFree(arena, abq->queue, ABQQueueSize(abq->elements, abq->elementSize));
|
||||
|
||||
abq->elements = 0;
|
||||
abq->queue = NULL;
|
||||
|
|
@ -104,18 +96,17 @@ void ABQFinish(Arena arena, ABQ abq)
|
|||
}
|
||||
|
||||
|
||||
/* ABQPush -- push a block onto the tail of the ABQ */
|
||||
Res ABQPush(ABQ abq, CBSBlock block)
|
||||
/* ABQPush -- push an element onto the tail of the ABQ */
|
||||
Res ABQPush(ABQ abq, Addr element)
|
||||
{
|
||||
AVERT(ABQ, abq);
|
||||
AVERT(CBSBlock, block);
|
||||
|
||||
METER_ACC(abq->push, ABQDepth(abq));
|
||||
|
||||
if (ABQIsFull(abq))
|
||||
return ResFAIL;
|
||||
|
||||
abq->queue[abq->in] = block;
|
||||
mps_lib_memcpy(ABQElement(abq, abq->in), element, abq->elementSize);
|
||||
abq->in = ABQNextIndex(abq, abq->in);
|
||||
|
||||
AVERT(ABQ, abq);
|
||||
|
|
@ -123,10 +114,10 @@ Res ABQPush(ABQ abq, CBSBlock block)
|
|||
}
|
||||
|
||||
|
||||
/* ABQPop -- pop a block from the head of the ABQ */
|
||||
Res ABQPop(ABQ abq, CBSBlock *blockReturn)
|
||||
/* ABQPop -- pop an element from the head of the ABQ */
|
||||
Res ABQPop(ABQ abq, Addr elementReturn)
|
||||
{
|
||||
AVER(blockReturn != NULL);
|
||||
AVER(elementReturn != NULL);
|
||||
AVERT(ABQ, abq);
|
||||
|
||||
METER_ACC(abq->pop, ABQDepth(abq));
|
||||
|
|
@ -134,8 +125,7 @@ Res ABQPop(ABQ abq, CBSBlock *blockReturn)
|
|||
if (ABQIsEmpty(abq))
|
||||
return ResFAIL;
|
||||
|
||||
*blockReturn = abq->queue[abq->out];
|
||||
AVERT(CBSBlock, *blockReturn);
|
||||
mps_lib_memcpy(elementReturn, ABQElement(abq, abq->out), abq->elementSize);
|
||||
|
||||
abq->out = ABQNextIndex(abq, abq->out);
|
||||
|
||||
|
|
@ -145,9 +135,9 @@ Res ABQPop(ABQ abq, CBSBlock *blockReturn)
|
|||
|
||||
|
||||
/* ABQPeek -- peek at the head of the ABQ */
|
||||
Res ABQPeek(ABQ abq, CBSBlock *blockReturn)
|
||||
Res ABQPeek(ABQ abq, Addr elementReturn)
|
||||
{
|
||||
AVER(blockReturn != NULL);
|
||||
AVER(elementReturn != NULL);
|
||||
AVERT(ABQ, abq);
|
||||
|
||||
METER_ACC(abq->peek, ABQDepth(abq));
|
||||
|
|
@ -155,8 +145,7 @@ Res ABQPeek(ABQ abq, CBSBlock *blockReturn)
|
|||
if (ABQIsEmpty(abq))
|
||||
return ResFAIL;
|
||||
|
||||
*blockReturn = abq->queue[abq->out];
|
||||
AVERT(CBSBlock, *blockReturn);
|
||||
mps_lib_memcpy(elementReturn, ABQElement(abq, abq->out), abq->elementSize);
|
||||
|
||||
/* Identical to pop, but don't increment out */
|
||||
|
||||
|
|
@ -165,46 +154,49 @@ Res ABQPeek(ABQ abq, CBSBlock *blockReturn)
|
|||
}
|
||||
|
||||
|
||||
/* ABQDelete -- delete a block from the ABQ */
|
||||
Res ABQDelete(ABQ abq, CBSBlock block)
|
||||
typedef struct ABQDeleteClosureStruct *ABQDeleteClosure;
|
||||
typedef struct ABQDeleteClosureStruct {
|
||||
Addr element;
|
||||
Size elementSize;
|
||||
Res res;
|
||||
} ABQDeleteClosureStruct;
|
||||
|
||||
|
||||
static Res ABQDeleteCallback(ABQDisposition *dispositionReturn, Addr element,
|
||||
void *closureP)
|
||||
{
|
||||
Index index, next, in;
|
||||
CBSBlock *queue;
|
||||
|
||||
AVERT(ABQ, abq);
|
||||
AVERT(CBSBlock, block);
|
||||
|
||||
METER_ACC(abq->delete, ABQDepth(abq));
|
||||
|
||||
index = abq->out;
|
||||
in = abq->in;
|
||||
queue = abq->queue;
|
||||
|
||||
while (index != in) {
|
||||
if (queue[index] == block) {
|
||||
goto found;
|
||||
}
|
||||
index = ABQNextIndex(abq, index);
|
||||
ABQDeleteClosure closure = closureP;
|
||||
if (mps_lib_memcmp(element, closure->element, closure->elementSize) == 0) {
|
||||
*dispositionReturn = ABQDispositionDELETE;
|
||||
closure->res = ResOK;
|
||||
} else {
|
||||
*dispositionReturn = ABQDispositionKEEP;
|
||||
}
|
||||
|
||||
return ResFAIL;
|
||||
|
||||
found:
|
||||
/* index points to the node to be removed */
|
||||
next = ABQNextIndex(abq, index);
|
||||
while (next != in) {
|
||||
queue[index] = queue[next];
|
||||
index = next;
|
||||
next = ABQNextIndex(abq, index);
|
||||
}
|
||||
abq->in = index;
|
||||
AVERT(ABQ, abq);
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
/* ABQDelete -- delete an element from the ABQ */
|
||||
Res ABQDelete(ABQ abq, Addr element)
|
||||
{
|
||||
ABQDeleteClosureStruct closure;
|
||||
|
||||
AVERT(ABQ, abq);
|
||||
|
||||
METER_ACC(abq->delete, ABQDepth(abq));
|
||||
|
||||
closure.element = element;
|
||||
closure.elementSize = abq->elementSize;
|
||||
closure.res = ResFAIL;
|
||||
|
||||
ABQIterate(abq, ABQDeleteCallback, &closure);
|
||||
|
||||
return closure.res;
|
||||
}
|
||||
|
||||
|
||||
/* ABQDescribe -- Describe an ABQ */
|
||||
Res ABQDescribe(ABQ abq, mps_lib_FILE *stream)
|
||||
Res ABQDescribe(ABQ abq, ABQDescribeElement describeElement, mps_lib_FILE *stream)
|
||||
{
|
||||
Res res;
|
||||
Index index;
|
||||
|
|
@ -224,11 +216,10 @@ Res ABQDescribe(ABQ abq, mps_lib_FILE *stream)
|
|||
return res;
|
||||
|
||||
for (index = abq->out; index != abq->in; ) {
|
||||
res = CBSBlockDescribe(abq->queue[index], stream);
|
||||
res = (*describeElement)(ABQElement(abq, index), stream);
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
if (++index == abq->elements)
|
||||
index = 0;
|
||||
index = ABQNextIndex(abq, index);
|
||||
}
|
||||
|
||||
res = WriteF(stream, "\n", NULL);
|
||||
|
|
@ -274,7 +265,7 @@ Bool ABQIsFull(ABQ abq)
|
|||
}
|
||||
|
||||
|
||||
/* ABQDepth -- return the number of items in an ABQ */
|
||||
/* ABQDepth -- return the number of elements in an ABQ */
|
||||
Count ABQDepth(ABQ abq)
|
||||
{
|
||||
Index out, in;
|
||||
|
|
@ -290,13 +281,65 @@ Count ABQDepth(ABQ abq)
|
|||
}
|
||||
|
||||
|
||||
/* ABQQueueSize -- calculate the storage required for the vector to
|
||||
store elements items */
|
||||
static Size ABQQueueSize(Count elements)
|
||||
/* ABQDispositionCheck -- check method for an ABQDisposition value */
|
||||
static Bool ABQDispositionCheck(ABQDisposition disposition)
|
||||
{
|
||||
/* strange but true: the sizeof expression calculates the size of a
|
||||
single queue element */
|
||||
return (Size)(sizeof(((ABQ)NULL)->queue[0]) * elements);
|
||||
CHECKL(disposition == ABQDispositionKEEP
|
||||
|| disposition == ABQDispositionDELETE);
|
||||
UNUSED(disposition); /* <code/mpm.c#check.unused> */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* ABQIterate -- call 'iterate' for each element in an ABQ */
|
||||
void ABQIterate(ABQ abq, ABQIterateMethod iterate, void *closureP)
|
||||
{
|
||||
Index copy, index, in;
|
||||
Res res;
|
||||
|
||||
AVERT(ABQ, abq);
|
||||
AVER(FUNCHECK(iterate));
|
||||
|
||||
copy = abq->out;
|
||||
index = abq->out;
|
||||
in = abq->in;
|
||||
|
||||
while (index != in) {
|
||||
Addr element = ABQElement(abq, index);
|
||||
ABQDisposition disposition = ABQDispositionNONE;
|
||||
res = (*iterate)(&disposition, element, closureP);
|
||||
AVERT(ABQDisposition, disposition);
|
||||
if (disposition == ABQDispositionKEEP) {
|
||||
if (copy != index)
|
||||
mps_lib_memcpy(ABQElement(abq, copy), element, abq->elementSize);
|
||||
copy = ABQNextIndex(abq, copy);
|
||||
}
|
||||
index = ABQNextIndex(abq, index);
|
||||
if (res != ResOK)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If any elements were deleted, need to copy remainder of queue. */
|
||||
if (copy != index) {
|
||||
while (index != in) {
|
||||
mps_lib_memcpy(ABQElement(abq, copy), ABQElement(abq, index),
|
||||
abq->elementSize);
|
||||
copy = ABQNextIndex(abq, copy);
|
||||
index = ABQNextIndex(abq, index);
|
||||
}
|
||||
abq->in = copy;
|
||||
}
|
||||
|
||||
AVERT(ABQ, abq);
|
||||
}
|
||||
|
||||
|
||||
/* ABQQueueSize -- calculate the storage required for the vector to
|
||||
store the elements */
|
||||
static Size ABQQueueSize(Count elements, Size elementSize)
|
||||
{
|
||||
return (Size)(elements * elementSize);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -310,6 +353,12 @@ static Index ABQNextIndex(ABQ abq, Index index)
|
|||
return next;
|
||||
}
|
||||
|
||||
/* ABQElement -- return pointer to the index'th element in the queue
|
||||
vector. */
|
||||
static Addr ABQElement(ABQ abq, Index index) {
|
||||
return AddrAdd(abq->queue, index * abq->elementSize);
|
||||
}
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
/* abq.h: ABQ INTERFACE
|
||||
/* abq.h: QUEUE INTERFACE
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .purpose: A FIFO queue substrate for <code/poolmv2.c>
|
||||
* .purpose: A fixed-length FIFO queue.
|
||||
*
|
||||
* .source: <design/poolmvt/>
|
||||
* .design: <design/abq/>
|
||||
*/
|
||||
|
||||
#ifndef abq_h
|
||||
#define abq_h
|
||||
|
||||
#include "meter.h"
|
||||
#include "cbs.h"
|
||||
#include "mpm.h"
|
||||
|
||||
|
||||
|
|
@ -24,17 +23,22 @@
|
|||
/* Prototypes */
|
||||
|
||||
typedef struct ABQStruct *ABQ;
|
||||
extern Res ABQInit(Arena arena, ABQ abq, void *owner, Count items);
|
||||
typedef Res (*ABQDescribeElement)(Addr element, mps_lib_FILE *stream);
|
||||
typedef unsigned ABQDisposition;
|
||||
typedef Res (*ABQIterateMethod)(ABQDisposition *dispositionReturn, Addr element, void *closureP);
|
||||
|
||||
extern Res ABQInit(Arena arena, ABQ abq, void *owner, Count elements, Size elementSize);
|
||||
extern Bool ABQCheck(ABQ abq);
|
||||
extern void ABQFinish(Arena arena, ABQ abq);
|
||||
extern Res ABQPush(ABQ abq, CBSBlock block);
|
||||
extern Res ABQPop(ABQ abq, CBSBlock *blockReturn);
|
||||
extern Res ABQPeek(ABQ abq, CBSBlock *blockReturn);
|
||||
extern Res ABQDelete(ABQ abq, CBSBlock block);
|
||||
extern Res ABQDescribe(ABQ abq, mps_lib_FILE *stream);
|
||||
extern Res ABQPush(ABQ abq, Addr element);
|
||||
extern Res ABQPop(ABQ abq, Addr elementReturn);
|
||||
extern Res ABQPeek(ABQ abq, Addr elementReturn);
|
||||
extern Res ABQDelete(ABQ abq, Addr element);
|
||||
extern Res ABQDescribe(ABQ abq, ABQDescribeElement describeElement, mps_lib_FILE *stream);
|
||||
extern Bool ABQIsEmpty(ABQ abq);
|
||||
extern Bool ABQIsFull(ABQ abq);
|
||||
extern Count ABQDepth(ABQ abq);
|
||||
extern void ABQIterate(ABQ abq, ABQIterateMethod iterate, void *closureP);
|
||||
|
||||
|
||||
/* Types */
|
||||
|
|
@ -42,9 +46,10 @@ extern Count ABQDepth(ABQ abq);
|
|||
typedef struct ABQStruct
|
||||
{
|
||||
Count elements;
|
||||
Size elementSize;
|
||||
Index in;
|
||||
Index out;
|
||||
CBSBlock *queue;
|
||||
Addr queue;
|
||||
|
||||
/* Meter queue depth at each operation */
|
||||
METER_DECL(push);
|
||||
|
|
@ -55,6 +60,12 @@ typedef struct ABQStruct
|
|||
Sig sig;
|
||||
} ABQStruct;
|
||||
|
||||
enum {
|
||||
ABQDispositionKEEP = 1, /* keep item in queue */
|
||||
ABQDispositionDELETE, /* delete element from queue */
|
||||
ABQDispositionNONE /* no disposition (error) */
|
||||
};
|
||||
|
||||
#endif /* abq_h */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -41,54 +41,42 @@ static unsigned popee = 1;
|
|||
static unsigned deleted = 0;
|
||||
|
||||
|
||||
typedef struct TestStruct *Test;
|
||||
typedef struct TestBlockStruct *TestBlock;
|
||||
|
||||
typedef struct TestStruct
|
||||
typedef struct TestBlockStruct
|
||||
{
|
||||
Test next;
|
||||
TestBlock next;
|
||||
unsigned id;
|
||||
CBSBlockStruct cbsBlockStruct;
|
||||
} TestStruct;
|
||||
Addr base;
|
||||
Addr limit;
|
||||
} TestBlockStruct;
|
||||
|
||||
|
||||
static CBSBlock TestCBSBlock(Test t)
|
||||
static TestBlock testBlocks = NULL;
|
||||
|
||||
|
||||
static TestBlock CreateTestBlock(unsigned no)
|
||||
{
|
||||
return &t->cbsBlockStruct;
|
||||
}
|
||||
|
||||
static Test CBSBlockTest(CBSBlock c)
|
||||
{
|
||||
return PARENT(TestStruct, cbsBlockStruct, c);
|
||||
}
|
||||
|
||||
|
||||
static Test testBlocks = NULL;
|
||||
|
||||
|
||||
static CBSBlock CreateCBSBlock(unsigned no)
|
||||
{
|
||||
Test b = malloc(sizeof(TestStruct));
|
||||
TestBlock b = malloc(sizeof(TestBlockStruct));
|
||||
cdie(b != NULL, "malloc");
|
||||
|
||||
b->next = testBlocks;
|
||||
b->id = no;
|
||||
b->cbsBlockStruct.base = 0;
|
||||
b->cbsBlockStruct.limit = 0;
|
||||
b->base = 0;
|
||||
b->limit = 0;
|
||||
|
||||
testBlocks = b;
|
||||
|
||||
return TestCBSBlock(b);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
static void DestroyCBSBlock(CBSBlock c)
|
||||
static void DestroyTestBlock(TestBlock b)
|
||||
{
|
||||
Test b = CBSBlockTest(c);
|
||||
|
||||
if (b == testBlocks)
|
||||
testBlocks = b->next;
|
||||
else {
|
||||
Test prev;
|
||||
TestBlock prev;
|
||||
|
||||
for (prev = testBlocks; prev != 0; prev = prev->next)
|
||||
if (prev->next == b) {
|
||||
|
|
@ -104,12 +92,13 @@ static void DestroyCBSBlock(CBSBlock c)
|
|||
static void step(void)
|
||||
{
|
||||
Res res;
|
||||
CBSBlock a;
|
||||
TestBlock a;
|
||||
|
||||
switch (abqRnd(9)) {
|
||||
case 0: case 1: case 2: case 3:
|
||||
push:
|
||||
res = ABQPush(&abq, CreateCBSBlock(pushee));
|
||||
a = CreateTestBlock(pushee);
|
||||
res = ABQPush(&abq, (Addr)&a);
|
||||
if (res != ResOK) {
|
||||
goto pop;
|
||||
}
|
||||
|
|
@ -117,7 +106,7 @@ static void step(void)
|
|||
break;
|
||||
case 5: case 6: case 7: case 8:
|
||||
pop:
|
||||
res = ABQPop(&abq, &a);
|
||||
res = ABQPop(&abq, (Addr)&a);
|
||||
if (res != ResOK){
|
||||
goto push;
|
||||
}
|
||||
|
|
@ -125,20 +114,20 @@ static void step(void)
|
|||
popee++;
|
||||
deleted = 0;
|
||||
}
|
||||
cdie(CBSBlockTest(a)->id == popee, "pop");
|
||||
cdie(a->id == popee, "pop");
|
||||
popee++;
|
||||
DestroyCBSBlock(a);
|
||||
DestroyTestBlock(a);
|
||||
break;
|
||||
default:
|
||||
if (!deleted & (pushee > popee)) {
|
||||
Test b;
|
||||
TestBlock b;
|
||||
|
||||
deleted = (unsigned)abqRnd (pushee - popee) + popee;
|
||||
for (b = testBlocks; b != NULL; b = b->next)
|
||||
if (b->id == deleted)
|
||||
break;
|
||||
cdie(b != NULL, "found to delete");
|
||||
res = ABQDelete(&abq, TestCBSBlock(b));
|
||||
res = ABQDelete(&abq, (Addr)&b);
|
||||
cdie(res == ResOK, "ABQDelete");
|
||||
}
|
||||
}
|
||||
|
|
@ -159,7 +148,7 @@ extern int main(int argc, char *argv[])
|
|||
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
|
||||
"mps_arena_create");
|
||||
|
||||
die(ABQInit((Arena)arena, &abq, NULL, ABQ_SIZE),
|
||||
die(ABQInit((Arena)arena, &abq, NULL, ABQ_SIZE, sizeof(TestBlock)),
|
||||
"ABQInit");
|
||||
|
||||
abqSize = ABQ_SIZE;
|
||||
|
|
|
|||
178
mps/design/abq.txt
Normal file
178
mps/design/abq.txt
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
.. mode:: -*- rst -*-
|
||||
|
||||
Queue
|
||||
=====
|
||||
|
||||
:Tag: design.mps.abq
|
||||
:Author: Gareth Rees
|
||||
:Date: 2013-05-20
|
||||
:Status: complete design
|
||||
:Revision: $Id$
|
||||
:Copyright: See section `C. Copyright and License`_.
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
_`.intro`: This is the design of the ABQ module, which implements a
|
||||
fixed-length queue of small objects.
|
||||
|
||||
_`readership`: This document is intended for any MM developer.
|
||||
|
||||
_`name`: The name ABQ originally stood for "Available Block Queue" as
|
||||
the module is used by the MVT pool.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
_`.req.push` Clients can efficiently push new elements onto the queue.
|
||||
|
||||
_`.req.pop` Clients can efficiently pop elements from the queue.
|
||||
|
||||
_`.req.empty` Clients can efficiently test whether the queue is empty.
|
||||
|
||||
_`.req.abstract` The ABQ module does not know anything about the
|
||||
elements in the queue other than their size.
|
||||
|
||||
_`.req.delete` Clients can delete elements from the queue. (Note: not necessarily efficiently.)
|
||||
|
||||
_`.req.iterate` Clients can iterate over elements in the queue.
|
||||
|
||||
|
||||
Interface
|
||||
---------
|
||||
|
||||
.. c:type:: ABQ
|
||||
|
||||
``ABQ`` is the type of a queue. It is an alias for ``ABQStruct *``.
|
||||
``ABQStruct`` is defined in the header so that it can be inlined in
|
||||
client structures: clients must not depend on its implementation
|
||||
details.
|
||||
|
||||
.. c:function:: ABQInit(Arena arena, ABQ abq, void *owner, Count elements, Size elementSize)
|
||||
|
||||
Initialize the queue ``abq``. The parameter ``arena`` is the arena
|
||||
whose control pool should be used to allocate the memory for the
|
||||
queue; ``owner`` is passed to :c:func:`MeterInit` for the statistics; ``elements`` is the maximum number of elements that can be stored in the queue; and ``elementSize`` is the size of each element.
|
||||
|
||||
.. c:function:: void ABQFinish(Arena arena, ABQ abq)
|
||||
|
||||
Finish ``abq`` and free all resources associated with it.
|
||||
|
||||
.. c:function:: Res ABQPush(ABQ abq, Addr element)
|
||||
|
||||
If the queue is not full, push ``element`` on to the queue and return
|
||||
``ResOK``. If the queue is full, leave it unchanged and return
|
||||
``ResFAIL``.
|
||||
|
||||
.. c:function:: Res ABQPop(ABQ abq, Addr elementReturn)
|
||||
|
||||
If the queue is not empty, copy the first element on the queue into
|
||||
the memory pointed to by ``elementReturn``, remove the element from
|
||||
the queue, and return ``ResOK``. If the queue is empty, return
|
||||
``ResFAIL``.
|
||||
|
||||
.. c:function:: Res ABQPeek(ABQ abq, Addr elementReturn)
|
||||
|
||||
If the queue is not empty, copy the first element on the queue into
|
||||
the memory pointed to by ``elementReturn`` and return ``ResOK``. If
|
||||
the queue is empty, return ``ResFAIL``. (This is the same as
|
||||
:c:func:`ABQPop` except that the queue is unchanged.)
|
||||
|
||||
.. c:function:: Res ABQDelete(ABQ abq, Addr element)
|
||||
|
||||
If any elements in the queue compare equal to the element pointed to
|
||||
by ``element``, delete them from the queue and return ``ResOK``.
|
||||
Otherwise, return ``ResFAIL``.
|
||||
|
||||
.. c:function:: Bool ABQIsEmpty(ABQ abq)
|
||||
|
||||
If the queue is empty, return ``TRUE``, otherwise return ``FALSE``.
|
||||
|
||||
.. c:function:: Bool ABQIsFull(ABQ abq)
|
||||
|
||||
If the queue is full, return ``TRUE``, otherwise return ``FALSE``.
|
||||
|
||||
.. c:function:: Count ABQDepth(ABQ abq)
|
||||
|
||||
Return the number of elements in the queue.
|
||||
|
||||
.. c:type:: Res (*ABQDescribeElement)(Addr element, mps_lib_FILE *stream)
|
||||
|
||||
A function that can describe an element that has been pushed onto a queue.
|
||||
|
||||
.. c:type:: typedef unsigned ABQDisposition
|
||||
|
||||
An enumerated value returned by a function of
|
||||
:c:type:`ABQIterateMethod` describing what should happen to an element
|
||||
of a queue during the iteration. The value ``ABQDispositionKEEP``
|
||||
means that the element must be kept in the queue;
|
||||
``ABQDispositionDELETE`` means that the element must be deleted from
|
||||
the queue.
|
||||
|
||||
.. c:type:: Res (*ABQIterateMethod)(ABQDisposition *dispositionReturn, Addr element, void *closureP)
|
||||
|
||||
A callback function for :c:func:`ABQIterate`. The parameter
|
||||
``element`` is an element in the queue, and ``closureP`` is the value
|
||||
that was originally passed to ``ABQIterate``. This function must set
|
||||
``*dispositionReturn`` to ``ABQDispositionKEEP`` if ``element`` must
|
||||
be kept in the queue, or ``ABQDispositionDELETE`` if ``element`` must
|
||||
be deleted from the queue. If it returns ``ResOK`` then iteration will
|
||||
continue. If it returns any other result code, iteration will stop.
|
||||
|
||||
.. c:function:: void ABQIterate(ABQ abq, ABQIterateMethod iterate, void *closureP)
|
||||
|
||||
Call ``iterate`` for each elements in the queue, passing the element
|
||||
and ``closureP``. See :c:type:`ABQIterateMethod` for details.
|
||||
|
||||
|
||||
B. Document history
|
||||
-------------------
|
||||
|
||||
- 2013-05-20 GDR_ Created.
|
||||
|
||||
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
|
||||
|
||||
|
||||
C. Copyright and License
|
||||
------------------------
|
||||
|
||||
Copyright (C) 2013 Ravenbrook Limited. All rights reserved.
|
||||
<http://www.ravenbrook.com/>. This is an open source license. Contact
|
||||
Ravenbrook for commercial licensing options.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Redistributions in any form must be accompanied by information on how
|
||||
to obtain complete source code for this software and any
|
||||
accompanying software that uses this software. The source code must
|
||||
either be included in the distribution or be available for no more than
|
||||
the cost of distribution plus a nominal fee, and must be freely
|
||||
redistributable under reasonable conditions. For an executable file,
|
||||
complete source code means the source code for all modules it contains.
|
||||
It does not include source code for modules or files that typically
|
||||
accompany the major components of the operating system on which the
|
||||
executable file runs.
|
||||
|
||||
**This software is provided by the copyright holders and contributors
|
||||
"as is" and any express or implied warranties, including, but not
|
||||
limited to, the implied warranties of merchantability, fitness for a
|
||||
particular purpose, or non-infringement, are disclaimed. In no event
|
||||
shall the copyright holders and contributors be liable for any direct,
|
||||
indirect, incidental, special, exemplary, or consequential damages
|
||||
(including, but not limited to, procurement of substitute goods or
|
||||
services; loss of use, data, or profits; or business interruption)
|
||||
however caused and on any theory of liability, whether in contract,
|
||||
strict liability, or tort (including negligence or otherwise) arising in
|
||||
any way out of the use of this software, even if advised of the
|
||||
possibility of such damage.**
|
||||
Loading…
Add table
Add a link
Reference in a new issue