cyclonedds/src/os/tests/mutex.c

367 lines
11 KiB
C
Raw Normal View History

2018-04-10 17:03:59 +02:00
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "CUnit/Test.h"
2018-04-10 17:03:59 +02:00
#include "os/os.h"
#ifdef __VXWORKS__
# ifdef _WRS_KERNEL
# define FORCE_SCHEDULING() taskDelay(1)
# else
# define FORCE_SCHEDULING() sched_yield()
# endif
#else
# define FORCE_SCHEDULING()
#endif
#define BUSYLOOP (100000)
#define MAX_LOOPS (20)
typedef struct {
os_mutex global_mutex;
os_threadId global_data;
int nolock_corrupt_count;
int nolock_loop_count;
int lock_corrupt_count;
int lock_loop_count;
int trylock_corrupt_count;
int trylock_loop_count;
int trylock_busy_count;
int stop;
} shared_data;
os_threadAttr mutex_os_threadAttr;
os_threadId mutex_os_threadId[4];
os_time delay1 = { 5, 0 };
os_time pdelay = { 1, 0 };
char buffer[512];
int supported_resultBusy;
int loop;
static shared_data *sd;
char filePath[255];
uint32_t concurrent_lock_thread (_In_opt_ void *arg)
{
int j;
int loopc = 0;
int printed = 0;
while (!sd->stop)
{
if (arg) os_mutexLock (&sd->global_mutex);
sd->global_data = os_threadIdSelf();
FORCE_SCHEDULING();
for (j = 0; j < BUSYLOOP; j++);
if (os_threadIdToInteger(sd->global_data) !=
os_threadIdToInteger(os_threadIdSelf()))
{
if (arg)
{
sd->lock_corrupt_count++;
}
else
{
sd->nolock_corrupt_count++;
}
if (!printed) {
printed++;
}
}
if (arg)
{
sd->lock_loop_count++;
os_mutexUnlock (&sd->global_mutex);
}
else
{
sd->nolock_loop_count++;
}
FORCE_SCHEDULING();
for (j = 0; j < BUSYLOOP; j++);
loopc++;
}
return 0;
}
uint32_t concurrent_trylock_thread (_In_opt_ void *arg)
{
int j;
int loopc = 0;
int printed = 0;
os_result result;
while (!sd->stop)
{
if (arg)
{
while ((result = os_mutexTryLock (&sd->global_mutex))
!= os_resultSuccess)
{
if (result == os_resultBusy)
{
sd->trylock_busy_count++;
}
FORCE_SCHEDULING();
}
}
sd->global_data = os_threadIdSelf();
FORCE_SCHEDULING();
for (j = 0; j < BUSYLOOP; j++);
if (os_threadIdToInteger(sd->global_data) !=
os_threadIdToInteger(os_threadIdSelf()))
{
if (arg)
{
sd->trylock_corrupt_count++;
}
else
{
sd->nolock_corrupt_count++;
}
if (!printed) {
printed++;
}
}
if (arg)
{
sd->trylock_loop_count++;
os_mutexUnlock (&sd->global_mutex);
}
else
{
sd->nolock_loop_count++;
}
FORCE_SCHEDULING();
for (j = 0; j < BUSYLOOP; j++);
loopc++;
}
return 0;
}
CU_Init(os_mutex)
2018-04-10 17:03:59 +02:00
{
printf ( "Run os_mutex_Initialize\n" );
os_osInit();
return 0;
}
CU_Clean(os_mutex)
2018-04-10 17:03:59 +02:00
{
printf("Run os_mutex_Cleanup\n");
os_osExit();
return 0;
}
/* This test only checks a single-threaded use-case; just API availability.*/
CU_Test(os_mutex, basic)
2018-04-10 17:03:59 +02:00
{
os_mutex m;
os_result r;
printf("Starting os_mutex_basic\n");
os_mutexInit(&m);
os_mutexLock(&m);
os_mutexUnlock(&m);
r = os_mutexLock_s(&m);
CU_ASSERT_EQUAL(r, os_resultSuccess); /* Failure can't be forced */
os_mutexUnlock(&m);
os_mutexDestroy(&m);
printf("Ending os_mutex_basic\n");
}
#define RUNTIME_SEC (4)
#define NUM_THREADS (8)
#define OS_STRESS_STOP (0)
#define OS_STRESS_GO (1)
#define THREAD_NAME_LEN (8)
struct os_mutex_stress {
os_threadId tid;
os_mutex m;
os_atomic_uint32_t * flag;
char name[THREAD_NAME_LEN];
};
static uint32_t
os_mutex_init_thr(
void *args)
{
struct os_mutex_stress *state = (struct os_mutex_stress *)args;
os_result r;
uint32_t iterations = 0;
do {
os_mutexInit(&state->m);
r = os_mutexLock_s(&state->m); /* Use the mutex to check that all is OK. */
CU_ASSERT_EQUAL(r, os_resultSuccess); /* Failure can't be forced. */
os_mutexUnlock(&state->m);
os_mutexDestroy(&state->m);
iterations++;
} while ( os_atomic_ld32(state->flag) != OS_STRESS_STOP && r == os_resultSuccess);
printf("%s <%"PRIxMAX">: Performed %u iterations. Stopping now.\n", state->name, os_threadIdToInteger(os_threadIdSelf()), iterations);
return r != os_resultSuccess; /* Return true on faulure */
}
CU_Test(os_mutex, init_stress)
2018-04-10 17:03:59 +02:00
{
struct os_mutex_stress threads[NUM_THREADS];
os_threadAttr tattr;
unsigned i;
os_atomic_uint32_t flag = OS_ATOMIC_UINT32_INIT(OS_STRESS_GO);
os_time runtime = { .tv_sec = RUNTIME_SEC, .tv_nsec = 0 };
printf("Starting os_mutex_init_stress\n");
os_threadAttrInit(&tattr);
for ( i = 0; i < NUM_THREADS; i++ ) {
(void) snprintf(&threads[i].name[0], THREAD_NAME_LEN, "thr%u", i);
threads[i].flag = &flag;
os_threadCreate(&threads[i].tid, threads[i].name, &tattr, &os_mutex_init_thr, &threads[i]);
printf("main <%"PRIxMAX">: Started thread '%s' with thread-id %" PRIxMAX "\n", os_threadIdToInteger(os_threadIdSelf()), threads[i].name, os_threadIdToInteger(threads[i].tid));
}
printf("main <%"PRIxMAX">: Test will run for ~%ds with %d threads\n", os_threadIdToInteger(os_threadIdSelf()), RUNTIME_SEC, NUM_THREADS);
os_nanoSleep(runtime);
os_atomic_st32(&flag, OS_STRESS_STOP);
for ( ; i != 0; i-- ) {
uint32_t thread_failed;
os_threadWaitExit(threads[i - 1].tid, &thread_failed);
printf("main <%"PRIxMAX">: Thread %s <%" PRIxMAX "> stopped with result %s.\n", os_threadIdToInteger(os_threadIdSelf()), threads[i - 1].name, os_threadIdToInteger(threads[i - 1].tid), thread_failed ? "FAILED" : "PASS");
CU_ASSERT_FALSE(thread_failed);
}
printf("Ending os_mutex_init_stress\n");
}
CU_Test(os_mutex, lock, false)
2018-04-10 17:03:59 +02:00
{
/* Test critical section access with locking and PRIVATE scope */
printf ("Starting tc_os_mutex_lock_001\n");
os_threadAttrInit (&mutex_os_threadAttr);
FORCE_SCHEDULING();
delay1.tv_sec = 3;
printf ("Testing for %d.%9.9d seconds without lock\n", delay1.tv_sec, delay1.tv_nsec);
sd->stop = 0;
sd->nolock_corrupt_count = 0;
sd->nolock_loop_count = 0;
sd->lock_corrupt_count = 0;
sd->lock_loop_count = 0;
sd->trylock_corrupt_count = 0;
sd->trylock_loop_count = 0;
sd->trylock_busy_count = 0;
os_threadCreate (&mutex_os_threadId[0], "thr0", &mutex_os_threadAttr, &concurrent_lock_thread, NULL);
os_threadCreate (&mutex_os_threadId[1], "thr1", &mutex_os_threadAttr, &concurrent_lock_thread, NULL);
os_threadCreate (&mutex_os_threadId[2], "thr2", &mutex_os_threadAttr, &concurrent_trylock_thread, NULL);
os_threadCreate (&mutex_os_threadId[3], "thr3", &mutex_os_threadAttr, &concurrent_trylock_thread, NULL);
os_nanoSleep (delay1);
sd->stop = 1;
os_threadWaitExit (mutex_os_threadId[0], NULL);
os_threadWaitExit (mutex_os_threadId[1], NULL);
os_threadWaitExit (mutex_os_threadId[2], NULL);
os_threadWaitExit (mutex_os_threadId[3], NULL);
printf ("All threads stopped\n");
delay1.tv_sec = 3;
printf ("Testing for %d.%9.9d seconds with lock\n", delay1.tv_sec, delay1.tv_nsec);
sd->stop = 0;
sd->nolock_corrupt_count = 0;
sd->nolock_loop_count = 0;
sd->lock_corrupt_count = 0;
sd->lock_loop_count = 0;
sd->trylock_corrupt_count = 0;
sd->trylock_loop_count = 0;
sd->trylock_busy_count = 0;
os_threadCreate (&mutex_os_threadId[0], "thr0", &mutex_os_threadAttr, &concurrent_lock_thread, (void *)1);
os_threadCreate (&mutex_os_threadId[1], "thr1", &mutex_os_threadAttr, &concurrent_lock_thread, (void *)1);
os_threadCreate (&mutex_os_threadId[2], "thr2", &mutex_os_threadAttr, &concurrent_trylock_thread, (void *)1);
os_threadCreate (&mutex_os_threadId[3], "thr3", &mutex_os_threadAttr, &concurrent_trylock_thread, (void *)1);
os_nanoSleep (delay1);
sd->stop = 1;
os_threadWaitExit (mutex_os_threadId[0], NULL);
os_threadWaitExit (mutex_os_threadId[1], NULL);
os_threadWaitExit (mutex_os_threadId[2], NULL);
os_threadWaitExit (mutex_os_threadId[3], NULL);
printf ("All threads stopped\n");
CU_ASSERT (sd->lock_corrupt_count == 0 || sd->lock_loop_count > 0);
/* Lock mutex with PRIVATE scope and Success result */
printf ("Starting tc_os_mutex_lock_002\n");
os_mutexLock (&sd->global_mutex); //Cannot be checked
os_mutexUnlock (&sd->global_mutex);
/* Lock mutex with PRIVATE scope and Fail result */
printf ("Starting tc_os_mutex_lock_003\n");
printf ("N.A - Failure cannot be forced\n");
/* mutexLock_s with PRIVATE scope and Success result */
printf ("Starting tc_os_mutex_lock_004\n");
CU_ASSERT (os_mutexLock_s (&sd->global_mutex) == os_resultSuccess);
os_mutexUnlock (&sd->global_mutex);
printf ("Ending os_mutex_lock\n");
}
CU_Test(os_mutex, trylock, false)
2018-04-10 17:03:59 +02:00
{
os_result result;
/* Test critical section access with trylocking and PRIVATE scope */
printf ("Starting os_mutex_trylock_001\n");
CU_ASSERT (sd->trylock_corrupt_count == 0 || sd->trylock_loop_count > 0);
/* TryLock mutex with PRIVATE scope and Success result */
printf ("Starting os_mutex_trylock_002\n");
result = os_mutexTryLock (&sd->global_mutex);
CU_ASSERT (result == os_resultSuccess);
/* TryLock mutex with PRIVATE scope and Busy result */
printf ("Starting os_mutex_trylock_003\n");
#if defined(__VXWORKS__) && !defined(_WRS_KERNEL)
printf ("N.A - Mutexes are recursive on VxWorks RTP so this test is disabled\n");
#endif
result = os_mutexTryLock (&sd->global_mutex);
CU_ASSERT (result == os_resultBusy);
printf ("Ending os_mutex_trylock\n");
}
CU_Test(os_mutex, destroy, false)
2018-04-10 17:03:59 +02:00
{
/* Deinitialize mutex with PRIVATE scope and Success result */
printf ("Starting os_mutex_destroy_001\n");
os_mutexDestroy(&sd->global_mutex); // Cannot be checked directly - Success is assumed
/* Deinitialize mutex with PRIVATE scope and Fail result */
printf ("Starting os_mutex_destroy_002\n");
printf ("N.A - Failure cannot be forced\n");
printf ("Ending os_mutex_destroy\n");
}