From fedaf622acc66f1bbd609885c4fab8a1b0122c72 Mon Sep 17 00:00:00 2001 From: "Jeff Hill johill@lanl.gov" Date: Wed, 15 May 2013 12:05:58 -0600 Subject: [PATCH] improved multiSubscrDestroyNoLateCallbackTest quality by temporarily raing the priority of the main thread in the ca context --- src/ca/client/acctst.c | 150 +++++++++++++++++++++++++++-------------- 1 file changed, 101 insertions(+), 49 deletions(-) diff --git a/src/ca/client/acctst.c b/src/ca/client/acctst.c index c06696c4b..a988e5337 100644 --- a/src/ca/client/acctst.c +++ b/src/ca/client/acctst.c @@ -1339,8 +1339,11 @@ struct MultiSubscrDestroyNoLateCallbackEventData { }; struct MultiSubscrDestroyNoLateCallbackTestData { + const char * m_pChanName; chid m_chan; epicsMutexId m_mutex; + epicsEventId m_testDoneEvent; + unsigned m_interestLevel; struct MultiSubscrDestroyNoLateCallbackEventData m_eventData [multiSubscrDestroyNoLateCallbackEventCount]; }; @@ -1357,78 +1360,127 @@ static void noLateCallbackDetect ( struct event_handler_args args ) verify ( callbackIsOk ); } -/* - * verify that a subscription callback never comes after the subscription is destroyed - */ -static void multiSubscrDestroyNoLateCallbackTest ( const char *pName, unsigned interestLevel ) +static void multiSubscrDestroyNoLateCallbackThread ( void * pParm ) { + struct MultiSubscrDestroyNoLateCallbackTestData * const pTestData = + ( struct MultiSubscrDestroyNoLateCallbackTestData * ) pParm; unsigned i, j; int status; - showProgressBegin ( "multiSubscrDestroyLateNoCallbackTest", interestLevel ); - - struct MultiSubscrDestroyNoLateCallbackTestData * pTestData = - calloc ( 1u, sizeof ( struct MultiSubscrDestroyNoLateCallbackTestData ) ); - verify ( pTestData ); - - pTestData->m_mutex = epicsMutexCreate (); - verify ( pTestData->m_mutex ); - status = ca_context_create ( ca_enable_preemptive_callback ); verify ( status == ECA_NORMAL ); - status = ca_create_channel ( pName, 0, 0, CA_PRIORITY_DEFAULT, &pTestData->m_chan ); + status = ca_create_channel ( pTestData->m_pChanName, 0, 0, + CA_PRIORITY_DEFAULT, &pTestData->m_chan ); status = ca_pend_io ( timeoutToPendIO ); SEVCHK ( status, "multiSubscrDestroyLateNoCallbackTest: channel connect failed" ); verify ( status == ECA_NORMAL ); - for ( i=0; i < 1000; i++ ) { - for ( j=0; j < multiSubscrDestroyNoLateCallbackEventCount; j++ ) { - epicsMutexLockStatus lockStatus = epicsMutexLock ( pTestData->m_mutex ); - verify ( lockStatus == epicsMutexLockOK ); - pTestData->m_eventData[j].m_nCallback = 0; - pTestData->m_eventData[j].m_callbackIsOk = TRUE; - pTestData->m_eventData[j].m_pTestData = pTestData; - epicsMutexUnlock ( pTestData->m_mutex ); - SEVCHK ( ca_add_event ( DBR_GR_FLOAT, pTestData->m_chan, noLateCallbackDetect, - &pTestData->m_eventData[j], &pTestData->m_eventData[j].m_id ) , NULL ); - } - SEVCHK ( ca_flush_io(), NULL ); - { - epicsMutexLockStatus lockStatus = epicsMutexLock ( pTestData->m_mutex ); - verify ( lockStatus == epicsMutexLockOK ); - while ( pTestData->m_eventData[0].m_nCallback == 0 ) { - epicsMutexUnlock ( pTestData->m_mutex ); - epicsThreadSleep ( 100e-6 ); - lockStatus = epicsMutexLock ( pTestData->m_mutex ); - verify ( lockStatus == epicsMutexLockOK ); - } - epicsMutexUnlock ( pTestData->m_mutex ); - } - for ( j=0; j < multiSubscrDestroyNoLateCallbackEventCount; j++ ) { - SEVCHK ( ca_clear_event ( pTestData->m_eventData[j].m_id ) , NULL ); - epicsMutexLockStatus lockStatus = epicsMutexLock ( pTestData->m_mutex ); - verify ( lockStatus == epicsMutexLockOK ); - pTestData->m_eventData[j].m_callbackIsOk = FALSE; - epicsMutexUnlock ( pTestData->m_mutex ); - } - if ( i % 100 == 0 ) { - showProgress ( interestLevel ); - } + /* + * create a set of subscriptions + */ + for ( i=0; i < 10000; i++ ) { + unsigned int priorityOfTestThread; + for ( j=0; j < multiSubscrDestroyNoLateCallbackEventCount; j++ ) { + epicsMutexLockStatus lockStatus = epicsMutexLock ( pTestData->m_mutex ); + verify ( lockStatus == epicsMutexLockOK ); + pTestData->m_eventData[j].m_nCallback = 0; + pTestData->m_eventData[j].m_callbackIsOk = TRUE; + pTestData->m_eventData[j].m_pTestData = pTestData; + epicsMutexUnlock ( pTestData->m_mutex ); + SEVCHK ( ca_add_event ( DBR_GR_FLOAT, pTestData->m_chan, noLateCallbackDetect, + &pTestData->m_eventData[j], &pTestData->m_eventData[j].m_id ) , NULL ); + } + SEVCHK ( ca_flush_io(), NULL ); + + /* + * raise the priority of the current thread hoping to improve our + * likelyhood of detecting a bug + */ + priorityOfTestThread = epicsThreadGetPrioritySelf (); + epicsThreadSetPriority ( epicsThreadGetIdSelf(), epicsThreadPriorityHigh ); + + + /* + * wait for the first subscription update to arrive + */ + { + epicsMutexLockStatus lockStatus = epicsMutexLock ( pTestData->m_mutex ); + verify ( lockStatus == epicsMutexLockOK ); + while ( pTestData->m_eventData[0].m_nCallback == 0 ) { + epicsMutexUnlock ( pTestData->m_mutex ); + epicsThreadSleep ( 50e-6 ); + lockStatus = epicsMutexLock ( pTestData->m_mutex ); + verify ( lockStatus == epicsMutexLockOK ); + } + epicsMutexUnlock ( pTestData->m_mutex ); + } + /* + * try to destroy all of the subscriptions at precisely the same time that + * their first callbacks are running + */ + for ( j=0; j < multiSubscrDestroyNoLateCallbackEventCount; j++ ) { + SEVCHK ( ca_clear_event ( pTestData->m_eventData[j].m_id ) , NULL ); + epicsMutexLockStatus lockStatus = epicsMutexLock ( pTestData->m_mutex ); + verify ( lockStatus == epicsMutexLockOK ); + pTestData->m_eventData[j].m_callbackIsOk = FALSE; + epicsMutexUnlock ( pTestData->m_mutex ); + } + /* + * return to the original priority + */ + epicsThreadSetPriority ( epicsThreadGetIdSelf(), priorityOfTestThread ); + + if ( i % 1000 == 0 ) { + showProgress ( pTestData->m_interestLevel ); + } } SEVCHK ( ca_clear_channel ( pTestData->m_chan ), NULL ); ca_context_destroy (); - epicsMutexDestroy ( pTestData->m_mutex ); + epicsEventMustTrigger ( pTestData->m_testDoneEvent ); +} +/* + * verify that, in a preemtive callback mode client, a subscription callback never + * comes after the subscription is destroyed + */ +static void multiSubscrDestroyNoLateCallbackTest ( const char *pName, unsigned interestLevel ) +{ + struct MultiSubscrDestroyNoLateCallbackTestData * pTestData; + + showProgressBegin ( "multiSubscrDestroyLateNoCallbackTest", interestLevel ); + + pTestData = calloc ( 1u, sizeof ( struct MultiSubscrDestroyNoLateCallbackTestData ) ); + verify ( pTestData ); + pTestData->m_mutex = epicsMutexMustCreate (); + pTestData->m_testDoneEvent = epicsEventMustCreate ( epicsEventEmpty ); + pTestData->m_pChanName = pName; + pTestData->m_interestLevel = interestLevel; + epicsThreadMustCreate ( + "multiSubscrDestroyNoLateCallbackTest", + epicsThreadPriorityLow, + epicsThreadGetStackSize ( epicsThreadStackMedium ), + multiSubscrDestroyNoLateCallbackThread, + pTestData ); + + /* + * wait for test to complete + */ + epicsEventMustWait ( pTestData->m_testDoneEvent ); + + /* + * cleanup + */ + epicsMutexDestroy ( pTestData->m_mutex ); + epicsEventDestroy ( pTestData->m_testDoneEvent ); free ( pTestData ); showProgressEnd ( interestLevel ); } - /* * multiSubscriptionDeleteTest *