Huang Qi 16a16a9543 ostest: Implement mutex move test functionality
Add a new test for moving mutexes to verify behavior when a mutex is relocated.
* Introduced mutex_thread_args_t structure for thread arguments
* Created moved_mutex_thread_func to handle mutex operations in threads
* Updated mutex_test to include mutex_move_test for comprehensive testing

Signed-off-by: Huang Qi <huangqi3@xiaomi.com>
2025-03-24 20:34:54 +08:00

279 lines
7.4 KiB
C

/****************************************************************************
* apps/testing/ostest/mutex.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include "ostest.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define NLOOPS 32
#define NYIELDS 10
/****************************************************************************
* Private Types
****************************************************************************/
typedef struct
{
pthread_mutex_t *mutex_ptr;
volatile int *mutex_value;
int *nloops;
int *nerrors;
int thread_id;
} mutex_thread_args_t;
/****************************************************************************
* Private Functions
****************************************************************************/
static void *mutex_thread_func(FAR void *parameter)
{
FAR mutex_thread_args_t *args = (FAR mutex_thread_args_t *)parameter;
int id = args->thread_id;
int ndx = id - 1;
int i;
int local_loops = 0;
for (local_loops = 0; local_loops < NLOOPS; local_loops++)
{
int status = pthread_mutex_lock(args->mutex_ptr);
if (status != 0)
{
printf("ERROR thread %d: pthread_mutex_lock failed, "
"status=%d\n", id, status);
ASSERT(false);
}
if (*(args->mutex_value) == 1)
{
printf("ERROR thread=%d: "
"mutex value should be zero, "
"instead mutex value=%d\n",
id, *(args->mutex_value));
ASSERT(false);
args->nerrors[ndx]++;
}
*(args->mutex_value) = 1;
for (i = 0; i < NYIELDS; i++)
{
pthread_yield();
}
*(args->mutex_value) = 0;
status = pthread_mutex_unlock(args->mutex_ptr);
if (status != 0)
{
printf("ERROR thread %d: pthread_mutex_unlock failed, "
"status=%d\n", id, status);
ASSERT(false);
}
}
args->nloops[ndx] = local_loops;
pthread_exit(NULL);
return NULL;
}
/****************************************************************************
* Name: mutex_move_test
*
* Description:
* Test the mutex move functionality. This test creates a mutex, moves
* it to a new location, and then starts two threads that use the moved
* mutex.
* POSIX specification does not define the behavior of a mutex that is
* moved. This test is intended to verify that the mutex can be moved,
* which is useful for some cases, see the discussion in
* https://github.com/rust-lang/rust/pull/138400
*
****************************************************************************/
static void mutex_move_test(void)
{
pthread_t thread1;
pthread_t thread2;
int status;
pthread_mutex_t initial_mutex;
pthread_mutex_t moved_mutex;
volatile int moved_mutex_value = 0;
int moved_nloops[2] =
{
0,
0
};
int moved_nerrors[2] =
{
0,
0
};
printf("\nTesting moved mutex\n");
/* Allocate and initialize first mutex */
pthread_mutex_init(&initial_mutex, NULL);
/* Copy the mutex to new location */
memcpy(&moved_mutex, &initial_mutex, sizeof(pthread_mutex_t));
/* Destroy the original mutex */
pthread_mutex_destroy(&initial_mutex);
mutex_thread_args_t thread1_args;
mutex_thread_args_t thread2_args;
thread1_args.mutex_ptr = &moved_mutex;
thread1_args.mutex_value = &moved_mutex_value;
thread1_args.nloops = moved_nloops;
thread1_args.nerrors = moved_nerrors;
thread1_args.thread_id = 1;
thread2_args.mutex_ptr = &moved_mutex;
thread2_args.mutex_value = &moved_mutex_value;
thread2_args.nloops = moved_nloops;
thread2_args.nerrors = moved_nerrors;
thread2_args.thread_id = 2;
/* Start two threads using the moved mutex */
printf("Starting moved mutex thread 1\n");
status = pthread_create(&thread1, NULL, mutex_thread_func,
&thread1_args);
if (status != 0)
{
printf("ERROR in moved mutex thread#1 creation\n");
ASSERT(false);
}
printf("Starting moved mutex thread 2\n");
status = pthread_create(&thread2, NULL, mutex_thread_func,
&thread2_args);
if (status != 0)
{
printf("ERROR in moved mutex thread#2 creation\n");
ASSERT(false);
}
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
pthread_mutex_destroy(&moved_mutex);
printf("\t\tThread1\tThread2\n");
printf("\tMoved Loops\t%u\t%u\n", moved_nloops[0], moved_nloops[1]);
printf("\tMoved Errors\t%u\t%u\n", moved_nerrors[0], moved_nerrors[1]);
}
void mutex_simple_test(void)
{
pthread_t thread1;
pthread_t thread2;
int status;
mutex_thread_args_t thread1_args;
mutex_thread_args_t thread2_args;
pthread_mutex_t mut;
volatile int my_mutex = 0;
int nloops[2] =
{
0,
0
};
int nerrors[2] =
{
0,
0
};
/* Initialize the mutex */
printf("Initializing mutex\n");
pthread_mutex_init(&mut, NULL);
/* Set up thread arguments */
thread1_args.mutex_ptr = &mut;
thread1_args.mutex_value = &my_mutex;
thread1_args.nloops = nloops;
thread1_args.nerrors = nerrors;
thread1_args.thread_id = 1;
thread2_args.mutex_ptr = &mut;
thread2_args.mutex_value = &my_mutex;
thread2_args.nloops = nloops;
thread2_args.nerrors = nerrors;
thread2_args.thread_id = 2;
/* Start two thread instances */
printf("Starting thread 1\n");
status = pthread_create(&thread1, NULL, mutex_thread_func, &thread1_args);
if (status != 0)
{
printf("ERROR in thread#1 creation\n");
ASSERT(false);
}
printf("Starting thread 2\n");
status = pthread_create(&thread2, NULL, mutex_thread_func, &thread2_args);
if (status != 0)
{
printf("ERROR in thread#2 creation\n");
ASSERT(false);
}
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
pthread_mutex_destroy(&mut);
printf("\t\tThread1\tThread2\n");
printf("\tLoops\t%u\t%u\n", nloops[0], nloops[1]);
printf("\tErrors\t%u\t%u\n", nerrors[0], nerrors[1]);
}
/****************************************************************************
* Public Functions
****************************************************************************/
void mutex_test(void)
{
mutex_simple_test();
mutex_move_test();
}