From 66fbbbb19a38b4a90cf4b16a679779bd9bc6ec01 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 17 Nov 2014 16:51:57 -0500 Subject: [PATCH] libCom/test: re-write ringPointerTest --- src/libCom/test/ringPointerTest.c | 357 ++++++++++++++++-------------- 1 file changed, 195 insertions(+), 162 deletions(-) diff --git a/src/libCom/test/ringPointerTest.c b/src/libCom/test/ringPointerTest.c index e50aeb639..cffb94bf0 100644 --- a/src/libCom/test/ringPointerTest.c +++ b/src/libCom/test/ringPointerTest.c @@ -26,179 +26,212 @@ #include "epicsUnitTest.h" #include "testMain.h" -#define ringSize 10 -#define consumerCount 4 -#define producerCount 4 - -static volatile int testExit = 0; -int value[ringSize*2]; - -typedef struct info { - epicsEventId consumerEvent; - epicsRingPointerId ring; - int checkOrder; - int value[ringSize*2]; -}info; - -static void consumer(void *arg) +static void testSingle(void) { - info *pinfo = (info *)arg; - static int expectedValue=0; - int *newvalue; - char myname[20]; + void *i; + const int rsize = 100; + void * const zero = 0; /* avoid warnings about int<->pointer casting */ + void *addr = 0; + epicsRingPointerId ring = epicsRingPointerCreate(rsize); - epicsThreadGetName(epicsThreadGetIdSelf(), myname, sizeof(myname)); - testDiag("%s starting", myname); - while(1) { - epicsEventMustWait(pinfo->consumerEvent); - if (testExit) return; - while ((newvalue = (int *)epicsRingPointerPop(pinfo->ring))) { - if (pinfo->checkOrder) { - testOk(expectedValue == *newvalue, - "%s: (got) %d == %d (expected)", myname, *newvalue, expectedValue); - expectedValue = *newvalue + 1; - } else { - testOk(pinfo->value[*newvalue] <= producerCount, "%s: got a %d (%d times seen before)", - myname, *newvalue, pinfo->value[*newvalue]); - } - /* This must be atomic... */ - pinfo->value[*newvalue]++; - epicsThreadSleep(0.05); - } + testDiag("Testing operations w/o threading"); + + testOk1(epicsRingPointerIsEmpty(ring)); + testOk1(!epicsRingPointerIsFull(ring)); + testOk1(epicsRingPointerGetFree(ring)==rsize); + testOk1(epicsRingPointerGetSize(ring)==rsize); + testOk1(epicsRingPointerGetUsed(ring)==0); + + testOk1(epicsRingPointerPop(ring)==NULL); + + addr = zero+1; + testOk1(epicsRingPointerPush(ring, addr)==1); + + testOk1(!epicsRingPointerIsEmpty(ring)); + testOk1(!epicsRingPointerIsFull(ring)); + testOk1(epicsRingPointerGetFree(ring)==rsize-1); + testOk1(epicsRingPointerGetSize(ring)==rsize); + testOk1(epicsRingPointerGetUsed(ring)==1); + + testDiag("Fill it up"); + for(i=zero+2; iring)) { - epicsThreadSleep(0.2); - if (testExit) return; - } - testOk(epicsRingPointerPush(pinfo->ring, (void *)&value[i]), - "%s: Pushing %d, ring not full", myname, i); - epicsEventSignal(pinfo->consumerEvent); - if (testExit) return; +static int foundCorruption; + +static +size_t ptr2int(void *p) +{ + void *zero = 0; + size_t i = p-zero; + if((i&0xffff)!=((i>>16)&0xffff)) { + testDiag("Pointer value corruption %p", p); + foundCorruption = 1; } + return i&0xffff; +} + +typedef struct { + epicsRingPointerId ring; + epicsEventId sync, wait; + int stop; + void *lastaddr; +} pairPvt; + +static void pairConsumer(void *raw) +{ + pairPvt *pvt = raw; + void *prev = pvt->lastaddr; + + epicsEventMustTrigger(pvt->sync); + + while(1) { + size_t c,p; + + epicsEventMustWait(pvt->wait); + if(pvt->stop) + break; + + pvt->lastaddr = epicsRingPointerPop(pvt->ring); + c = ptr2int(pvt->lastaddr); + p = ptr2int(prev); + if(p+1!=c) { + testFail("consumer skip %p %p", prev, pvt->lastaddr); + break; + } + prev = pvt->lastaddr; + } + + pvt->stop = 1; + epicsEventMustTrigger(pvt->sync); +} + +static void testPair(int locked) +{ + unsigned int myprio = epicsThreadGetPrioritySelf(), consumerprio; + pairPvt pvt; + const int rsize = 100; + int i, expect; + epicsRingPointerId ring; + if(locked) + ring = epicsRingPointerLockedCreate(rsize); + else + ring = epicsRingPointerCreate(rsize); + + pvt.ring = ring; + pvt.sync = epicsEventCreate(epicsEventEmpty); + pvt.wait = epicsEventCreate(epicsEventEmpty); + pvt.stop = 0; + pvt.lastaddr = 0; + + foundCorruption = 0; + + testDiag("single producer, single consumer with%s locking", locked?"":"out"); + + /* give the consumer thread a slightly higher priority so that + * it can preempt us on RTOS targets. On non-RTOS targets + * we expect to be preempt'ed at some random time + */ + if(!epicsThreadLowestPriorityLevelAbove(myprio, &consumerprio)) + testAbort("Can't run test from thread with highest priority"); + + epicsThreadMustCreate("pair", consumerprio, + epicsThreadGetStackSize(epicsThreadStackSmall), + &pairConsumer, &pvt); + /* wait for worker to start */ + epicsEventMustWait(pvt.sync); + + i=1; + while(iconsumerEvent = consumerEvent = epicsEventMustCreate(epicsEventEmpty); - if (!consumerEvent) { - testAbort("epicsEventMustCreate failed"); - } - - testDiag("******************************************************"); - testDiag("** Test 1: local ring pointer, check size and order **"); - testDiag("******************************************************"); - - pinfo->ring = ring = epicsRingPointerCreate(ringSize); - if (!ring) { - testAbort("epicsRingPointerCreate failed"); - } - testOk(epicsRingPointerIsEmpty(ring), "Ring empty"); - - for (i=0; epicsRingPointerPush(ring,(void *)&value[i]); ++i) {} - testOk(i==ringSize, "ring filled, %d values", i); - - for (i=0; (pgetValue = (int *)epicsRingPointerPop(ring)); ++i) { - testOk(i==*pgetValue, "Pop test: %d == %d", i, *pgetValue); - } - testOk(epicsRingPointerIsEmpty(ring), "Ring empty"); - - testDiag("**************************************************************"); - testDiag("** Test 2: unlocked ring pointer, one consumer, check order **"); - testDiag("**************************************************************"); - - pinfo->checkOrder = 1; - tid=epicsThreadCreate("consumer", 50, - epicsThreadGetStackSize(epicsThreadStackSmall), consumer, pinfo); - if(!tid) testAbort("epicsThreadCreate failed"); - epicsThreadSleep(0.2); - - for (i=0; ivalue[i] == 1, "Value test: %d was processed", i); - } - - testExit = 1; - epicsEventSignal(consumerEvent); - epicsThreadSleep(1.0); - - epicsRingPointerDelete(pinfo->ring); - - testDiag("*************************************************************************************"); - testDiag("** Test 3: locked ring pointer, many consumers, many producers, check no of copies **"); - testDiag("*************************************************************************************"); - - pinfo->ring = ring = epicsRingPointerLockedCreate(ringSize); - if (!ring) { - testAbort("epicsRingPointerLockedCreate failed"); - } - testOk(epicsRingPointerIsEmpty(ring), "Ring empty"); - - for (i=0; ivalue[i] = 0; - testExit = 0; - pinfo->checkOrder = 0; - for (i=0; ivalue[i] == producerCount, "Value test: %d was processed %d times", i, producerCount); - } - - testExit = 1; - epicsEventSignal(consumerEvent); - epicsThreadSleep(1.0); - + testPlan(36); + testSingle(); + testPair(0); + testPair(1); return testDone(); }