From b9c2a0ec2d920aa23007a36b02a39a9b1e27e724 Mon Sep 17 00:00:00 2001 From: ajesh Date: Tue, 6 Aug 2019 14:42:29 +0530 Subject: [PATCH] gpu: nvgpu: add unit test for cond unit Add unit test cases for cond unit. Jira NVGPU-2661 Change-Id: Id0bdd069787d567f99d53a9d69eaba1a6e7de97d Signed-off-by: ajesh Reviewed-on: https://git-master.nvidia.com/r/2169112 Reviewed-by: mobile promotions Tested-by: mobile promotions --- Makefile.umbrella.tmk | 1 + drivers/gpu/nvgpu/libnvgpu-drv_safe.export | 11 + userspace/Makefile.sources | 1 + userspace/units/posix/cond/Makefile | 26 ++ .../units/posix/cond/Makefile.interface.tmk | 35 ++ userspace/units/posix/cond/Makefile.tmk | 39 ++ userspace/units/posix/cond/posix-cond.c | 438 ++++++++++++++++++ userspace/units/posix/cond/posix-cond.h | 183 ++++++++ 8 files changed, 734 insertions(+) create mode 100644 userspace/units/posix/cond/Makefile create mode 100644 userspace/units/posix/cond/Makefile.interface.tmk create mode 100644 userspace/units/posix/cond/Makefile.tmk create mode 100644 userspace/units/posix/cond/posix-cond.c create mode 100644 userspace/units/posix/cond/posix-cond.h diff --git a/Makefile.umbrella.tmk b/Makefile.umbrella.tmk index e04f5e1d8..3ee97ffb4 100644 --- a/Makefile.umbrella.tmk +++ b/Makefile.umbrella.tmk @@ -42,6 +42,7 @@ NV_REPOSITORY_COMPONENTS += userspace/units/posix/bug NV_REPOSITORY_COMPONENTS += userspace/units/posix/sizes NV_REPOSITORY_COMPONENTS += userspace/units/init NV_REPOSITORY_COMPONENTS += userspace/units/posix/thread +NV_REPOSITORY_COMPONENTS += userspace/units/posix/cond NV_REPOSITORY_COMPONENTS += userspace/units/interface/bsearch NV_REPOSITORY_COMPONENTS += userspace/units/interface/lock NV_REPOSITORY_COMPONENTS += userspace/units/interface/atomic diff --git a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export index fdd4b5e34..6e5a4daf4 100644 --- a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export +++ b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export @@ -112,6 +112,17 @@ nvgpu_channel_refch_from_inst_ptr nvgpu_channel_setup_sw nvgpu_channel_sync_create nvgpu_check_gpu_state +nvgpu_cond_broadcast +nvgpu_cond_broadcast_interruptible +nvgpu_cond_broadcast_locked +nvgpu_cond_destroy +nvgpu_cond_init +nvgpu_cond_lock +nvgpu_cond_signal +nvgpu_cond_signal_interruptible +nvgpu_cond_signal_locked +nvgpu_cond_timedwait +nvgpu_cond_unlock nvgpu_detect_chip nvgpu_dma_alloc nvgpu_dma_alloc_get_fault_injection diff --git a/userspace/Makefile.sources b/userspace/Makefile.sources index f34c8857a..67c763644 100644 --- a/userspace/Makefile.sources +++ b/userspace/Makefile.sources @@ -49,6 +49,7 @@ UNITS := \ $(UNIT_SRC)/posix/bug \ $(UNIT_SRC)/posix/sizes \ $(UNIT_SRC)/posix/thread \ + $(UNIT_SRC)/posix/cond \ $(UNIT_SRC)/pramin \ $(UNIT_SRC)/init \ $(UNIT_SRC)/interface/bsearch \ diff --git a/userspace/units/posix/cond/Makefile b/userspace/units/posix/cond/Makefile new file mode 100644 index 000000000..debb7b97a --- /dev/null +++ b/userspace/units/posix/cond/Makefile @@ -0,0 +1,26 @@ +# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +.SUFFIXES: + +OBJS = posix-cond.o +MODULE = posix-cond + +include ../../Makefile.units diff --git a/userspace/units/posix/cond/Makefile.interface.tmk b/userspace/units/posix/cond/Makefile.interface.tmk new file mode 100644 index 000000000..3518828af --- /dev/null +++ b/userspace/units/posix/cond/Makefile.interface.tmk @@ -0,0 +1,35 @@ +################################### tell Emacs this is a -*- makefile-gmake -*- +# +# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# tmake for SW Mobile component makefile +# +############################################################################### + +NVGPU_UNIT_NAME=posix-cond + +include $(NV_COMPONENT_DIR)/../../Makefile.units.common.interface.tmk + +# Local Variables: +# indent-tabs-mode: t +# tab-width: 8 +# End: +# vi: set tabstop=8 noexpandtab: diff --git a/userspace/units/posix/cond/Makefile.tmk b/userspace/units/posix/cond/Makefile.tmk new file mode 100644 index 000000000..8a12eb5e6 --- /dev/null +++ b/userspace/units/posix/cond/Makefile.tmk @@ -0,0 +1,39 @@ +################################### tell Emacs this is a -*- makefile-gmake -*- +# +# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# tmake for SW Mobile component makefile +# +############################################################################### + +NVGPU_UNIT_NAME=posix-cond + +ifneq ($(NV_BUILD_CONFIGURATION_OS_IS_QNX),1) +NVGPU_UNIT_SHARED_LIBRARIES += pthread +endif + +include $(NV_COMPONENT_DIR)/../../Makefile.units.common.tmk + +# Local Variables: +# indent-tabs-mode: t +# tab-width: 8 +# End: +# vi: set tabstop=8 noexpandtab: diff --git a/userspace/units/posix/cond/posix-cond.c b/userspace/units/posix/cond/posix-cond.c new file mode 100644 index 000000000..c64ac5e39 --- /dev/null +++ b/userspace/units/posix/cond/posix-cond.c @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include +#include + +#include +#include "posix-cond.h" + +#define MISMATCH_ERROR 1000 + +struct test_cond_args { + bool use_broadcast; + bool use_int; + bool use_wait_int; + bool use_wait_locked; + bool use_signal_locked; + bool use_timedwait; + bool use_condition; +}; + +struct unit_test_cond_data { + int use_broadcast; + int use_int; + int use_wait_int; + int use_wait_locked; + int use_signal_locked; + int use_timedwait; + int use_condition; +}; + +struct unit_test_cond_data test_data; +struct nvgpu_cond test_cond; + +static struct test_cond_args signal_normal = { + .use_broadcast = false, + .use_int = false, + .use_wait_int = false, + .use_wait_locked = false, + .use_signal_locked = false, + .use_timedwait = false, + .use_condition = false +}; + +static struct test_cond_args signal_int = { + .use_broadcast = false, + .use_int = true, + .use_wait_int = false, + .use_wait_locked = false, + .use_signal_locked = false, + .use_timedwait = false, + .use_condition = false +}; + +static struct test_cond_args signal_locked = { + .use_broadcast = false, + .use_int = false, + .use_wait_int = false, + .use_wait_locked = false, + .use_signal_locked = true, + .use_timedwait = false, + .use_condition = false +}; + +static struct test_cond_args broadcast_normal = { + .use_broadcast = true, + .use_int = false, + .use_wait_int = false, + .use_wait_locked = false, + .use_signal_locked = false, + .use_timedwait = false, + .use_condition = false +}; + +static struct test_cond_args broadcast_int = { + .use_broadcast = true, + .use_int = true, + .use_wait_int = false, + .use_wait_locked = false, + .use_signal_locked = false, + .use_timedwait = false, + .use_condition = false +}; + +static struct test_cond_args broadcast_locked = { + .use_broadcast = true, + .use_int = false, + .use_wait_int = false, + .use_wait_locked = false, + .use_signal_locked = true, + .use_timedwait = false, + .use_condition = false +}; + +static struct test_cond_args timed_wait = { + .use_broadcast = false, + .use_int = false, + .use_wait_int = false, + .use_wait_locked = false, + .use_signal_locked = false, + .use_timedwait = true, + .use_condition = false +}; + +static struct test_cond_args condition_wait = { + .use_broadcast = false, + .use_int = false, + .use_wait_int = false, + .use_wait_locked = false, + .use_signal_locked = false, + .use_timedwait = false, + .use_condition = true +}; + +static struct test_cond_args condition_wait_locked = { + .use_broadcast = false, + .use_int = false, + .use_wait_int = false, + .use_wait_locked = true, + .use_signal_locked = false, + .use_timedwait = false, + .use_condition = true +}; + +static struct test_cond_args condition_wait_int = { + .use_broadcast = false, + .use_int = false, + .use_wait_int = true, + .use_wait_locked = false, + .use_signal_locked = false, + .use_timedwait = false, + .use_condition = true +}; + +bool read_wait = 0; +bool bcst_read_wait = 0; +int read_status = 0; +int bcst_read_status = 0; + +char test_code[4]; + +static void *test_cond_write_thread(void *args) +{ + int i; + struct unit_test_cond_data *data; + + data = (struct unit_test_cond_data *)args; + + while (!read_wait) { + usleep(10); + } + + if (data->use_broadcast) { + while (!bcst_read_wait) { + usleep(10); + } + } + + for (i = 0; i < 4; i++) { + test_code[i] = 0x55; + } + + read_wait = false; + + if (data->use_broadcast) { + bcst_read_wait = false; + + if (data->use_int) { + nvgpu_cond_broadcast_interruptible(&test_cond); + } else { + if (data->use_signal_locked) { + nvgpu_cond_lock(&test_cond); + nvgpu_cond_broadcast_locked(&test_cond); + nvgpu_cond_unlock(&test_cond); + } else { + nvgpu_cond_broadcast(&test_cond); + } + } + } else { + if (data->use_int) { + nvgpu_cond_signal_interruptible(&test_cond); + } else { + if (data->use_signal_locked) { + nvgpu_cond_lock(&test_cond); + nvgpu_cond_signal_locked(&test_cond); + nvgpu_cond_unlock(&test_cond); + } else { + nvgpu_cond_signal(&test_cond); + } + } + } + + return NULL; +} + +static void *test_cond_read_thread(void *args) +{ + int ret; + int i; + unsigned int timeout; + struct unit_test_cond_data *data; + + data = (struct unit_test_cond_data *)args; + + read_wait = true; + + if (data->use_timedwait) { + timeout = 50; + } else { + timeout = NVGPU_COND_WAIT_TIMEOUT_MAX_MS; + } + + if (data->use_condition) { + if (data->use_wait_int) { + ret = NVGPU_COND_WAIT_INTERRUPTIBLE(&test_cond, + test_code[3] == 0x55, 0); + } else if (data->use_wait_locked) { + nvgpu_cond_lock(&test_cond); + ret = NVGPU_COND_WAIT_LOCKED(&test_cond, + test_code[3] == 0x55, 0); + nvgpu_cond_unlock(&test_cond); + } else { + ret = NVGPU_COND_WAIT(&test_cond, + test_code[3] == 0x55, 0); + } + + if (ret != 0) { + read_status = ret; + } + } else { + nvgpu_cond_lock(&test_cond); + + ret = nvgpu_cond_timedwait(&test_cond, &timeout); + if (ret != 0) { + read_status = ret; + nvgpu_cond_unlock(&test_cond); + return NULL; + } + + nvgpu_cond_unlock(&test_cond); + + for (i = 0; i < 4; i++) { + if (test_code[i] != 0x55) { + read_status = MISMATCH_ERROR; + return NULL; + } + } + } + + return NULL; +} + +static void *test_cond_bcst_read_thread(void *args) +{ + int ret; + int i; + unsigned int timeout; + struct unit_test_cond_data *data; + + data = (struct unit_test_cond_data *)args; + + bcst_read_wait = true; + + if (data->use_timedwait) { + timeout = 50; + } else { + timeout = NVGPU_COND_WAIT_TIMEOUT_MAX_MS; + } + + nvgpu_cond_lock(&test_cond); + + ret = nvgpu_cond_timedwait(&test_cond, &timeout); + if (ret != 0) { + bcst_read_status = ret; + nvgpu_cond_unlock(&test_cond); + return NULL; + } + + nvgpu_cond_unlock(&test_cond); + + for (i = 0; i < 4; i++) { + if (test_code[i] != 0x55) { + bcst_read_status = MISMATCH_ERROR; + return NULL; + } + } + + return NULL; +} + +int test_cond_init_destroy(struct unit_module *m, + struct gk20a *g, void *args) +{ + int ret; + + memset(&test_cond, 0, sizeof(struct nvgpu_cond)); + + ret = nvgpu_cond_init(&test_cond); + if (ret != 0) { + unit_return_fail(m, "Cond init failed\n"); + } + + if (test_cond.initialized != true) { + unit_return_fail(m, "Init flag not set\n"); + } + + nvgpu_cond_destroy(&test_cond); + + if (test_cond.initialized != false) { + unit_return_fail(m, "Cond destroy failed\n"); + } + + return UNIT_SUCCESS; +} + +int test_cond_signal(struct unit_module *m, + struct gk20a *g, void *args) +{ + int ret; + pthread_t thread_write, thread_read, thread_bcst_read; + struct test_cond_args *test_args = (struct test_cond_args *)args; + + memset(&test_cond, 0, sizeof(struct nvgpu_cond)); + memset(&test_code, 0, sizeof(test_code)); + memset(&test_data, 0, sizeof(struct unit_test_cond_data)); + + ret = nvgpu_cond_init(&test_cond); + if (ret != 0) { + unit_return_fail(m, "Cond init failed\n"); + } + + test_data.use_broadcast = test_args->use_broadcast; + test_data.use_int = test_args->use_int; + test_data.use_wait_int = test_args->use_wait_int; + test_data.use_wait_locked = test_args->use_wait_locked; + test_data.use_signal_locked = test_args->use_signal_locked; + test_data.use_timedwait = test_args->use_timedwait; + test_data.use_condition = test_args->use_condition; + + read_status = 0; + bcst_read_status = 0; + + ret = pthread_create(&thread_read, NULL, + &test_cond_read_thread, &test_data); + if (ret != 0) { + nvgpu_cond_destroy(&test_cond); + unit_return_fail(m, "Cond read thread fail\n"); + } + + if (test_args->use_broadcast) { + ret = pthread_create(&thread_bcst_read, NULL, + &test_cond_bcst_read_thread, &test_data); + if (ret != 0) { + nvgpu_cond_destroy(&test_cond); + pthread_cancel(thread_read); + pthread_join(thread_read, NULL); + unit_return_fail(m, "Cond bcst read thread fail\n"); + } + } + + ret = pthread_create(&thread_write, NULL, + &test_cond_write_thread, &test_data); + if (ret != 0) { + nvgpu_cond_destroy(&test_cond); + pthread_cancel(thread_read); + pthread_join(thread_read, NULL); + if (test_args->use_broadcast) { + pthread_cancel(thread_bcst_read); + pthread_join(thread_bcst_read, NULL); + } + unit_return_fail(m, "Cond write thread fail\n"); + } + + pthread_join(thread_write, NULL); + pthread_join(thread_read, NULL); + + if (test_args->use_broadcast) { + pthread_join(thread_bcst_read, NULL); + } + + if (read_status != 0) { + nvgpu_cond_destroy(&test_cond); + unit_return_fail(m, "Cond read status fail %d\n", + read_status); + } + + if (test_args->use_broadcast) { + if (bcst_read_status != 0) { + nvgpu_cond_destroy(&test_cond); + unit_return_fail(m, + "Cond bcst read status fail %d\n", + bcst_read_status); + } + } + + nvgpu_cond_destroy(&test_cond); + + return UNIT_SUCCESS; +} + +struct unit_module_test posix_cond_tests[] = { + UNIT_TEST(init, test_cond_init_destroy, NULL, 0), + UNIT_TEST(wait_signal, test_cond_signal, &signal_normal, 0), + UNIT_TEST(wait_signal_int, test_cond_signal, &signal_int, 0), + UNIT_TEST(wait_signal_locked, test_cond_signal, &signal_locked, 0), + UNIT_TEST(timedwait_signal, test_cond_signal, &timed_wait, 0), + UNIT_TEST(wait_broadcast, test_cond_signal, &broadcast_normal, 0), + UNIT_TEST(wait_broadcast_int, test_cond_signal, &broadcast_int, 0), + UNIT_TEST(wait_broadcast_locked, test_cond_signal, &broadcast_locked, 0), + UNIT_TEST(wait_condition, test_cond_signal, &condition_wait, 0), + UNIT_TEST(wait_condition_int, test_cond_signal, &condition_wait_int, 0), + UNIT_TEST(wait_condition_locked, test_cond_signal, &condition_wait_locked, 0), +}; + +UNIT_MODULE(posix_cond, posix_cond_tests, UNIT_PRIO_POSIX_TEST); diff --git a/userspace/units/posix/cond/posix-cond.h b/userspace/units/posix/cond/posix-cond.h new file mode 100644 index 000000000..f89a9ec1a --- /dev/null +++ b/userspace/units/posix/cond/posix-cond.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * @addtogroup SWUTS-posix.cond + * @{ + * + * Software Unit Test Specification for posix.cond + */ + +#ifndef __UNIT_POSIX_COND_H__ +#define __UNIT_POSIX_COND_H__ + +/** + * Test specification for test_cond_init_destroy + * + * Description: Test cond init and cleanup routine. + * + * Test Type: Feature based. + * + * Inputs: + * 1) Global instance of struct nvgpu_cond. + * + * Steps: + * 1) Reset the global instance of struct nvgpu_cond with 0s. + * 2) Call nvgpu_cond_init to initialise the condition variable. + * 3) Check the return value for any error. + * 4) If step 3 passes, confirm the initialisation of cond variable + * by checking the value of variable in struct nvgpu_cond. + * 5) Cleanup the condition variable by calling function nvgpu_cond_destroy. + * 6) Confirm the cleanup action by checking the value of variable inside + * struct nvgpu_cond + * + * Output: + * The test returns PASS if cond variable initiaisation and cleanup functions + * returns expected success values and internal variables in cond variable + * structure is initialised with proper values. + * The test returns FAIL if either initialisation or cleanup routine fails. + * It also returns FAIL if the internal variables in cond variable structure + * is not set with corresponding value for init and cleanup. + * + */ +int test_cond_init_destroy(struct unit_module *m, + struct gk20a *g, void *args); + +/** + * Test specification for test_cond_signal + * + * Description: Functionalities of cond unit that are tested as + * part of this function are as follows, + * - Waiting and signaling using normal signaling, interruptible signaling + * and signaling protected by explicit acquire/release of the locks. + * - Waiting and signaling using normal broadcast, interruptible broadcast + * and broadcast protected by explicit acquire/release of the locks. + * - Waiting and signaling using a condition check. + * + * Test Type: Feature based. + * + * Inputs: + * 1) Global instance of struct nvgpu_cond. + * 2) Global array test_code. + * 3) Global instance of struct unit_test_cond_data. + * 4) Global variables read_status, bcst_read_status. + * 5) Global variables read_wait, bcst_read_wait. + * 6) Function argument of type pointer to struct test_cond_args. + * + * Steps: + * All the above mentioned functionalities are tested by this function based + * on the input arguments. Steps for various tests are as mentioned below, + * + * a) Wait and Signal + * Three threads are involved in this test case. + * A main thread which creates a write thread and a read thread and then + * waits for the created threads to exit. + * + * - Main Thread: + * 1) Main thread resets the global variables test_code, test_cond + * and test_data. + * 2) Initialise the condition variabe by calling nvgpu_cond_init. + * 3) Return failure if the init function returns error. + * 4) Copy the test args into global structure instance of unit_test_cond_data. + * 5) Reset global variables read_status and bcst_read_status to 0. + * 6) Create the read thread. + * 7) Cleanup the initialised cond variable and return failure if read thread + * creation fails. + * 8) Create the write thread. + * 9) Cleanup the initialised cond variable, cancel the read thread and return + * failure if write thread creation fails. + * 10) Wait for both read and write thread to exit using pthread_join. + * 11) Check for global variable read_status and return FAIL if the value + * indicates an error. + * 12) Return test PASS. + * + * - Read Thread: + * 1) Set global variable read_wait as true. This is used by write thread + * to continue further. + * 2) Wait on the condition variable. + * 3) On getting signalled, check for the pattern in test_code. + * 4) If the data does not match the written value, update read_status + * with error code. + * 5) Return from the thread handler. + * + * - Write Thread: + * 1) Wait on global variable read_wait to be true before proceeding further. + * 2) Update the global array test_code with a defined value. + * 3) Reset read_wait to 0. + * 4) Signal the condition variable. + * 5) Return from the thread handler. + * + * b) Wait and Signal interruptible + * The steps followed are the same as case a. But the signaling API + * used by write thread in step 4 is nvgpu_cond_signal_interruptible. + * Although functionality wise both nvgpu_cond_signal and + * nvgpu_cond_signal_interruptible are same, this test just ensures + * better code coverage. + * + * c) Wait and Signal locked + * The steps followed are the same as case a. But the write thread + * needs to explicitly acquire the mutex lock before signalling the + * read thread. The lock has to be released explicitly once the signal + * API is called. + * + * d) Timed Wait and Signal + * The test differs from case a on the duration of time used to wait for + * the signal. In this case the wait is limited to a predefined duration of + * time rather than wait forever as it is in case a. + * + * e) Wait and Broadcast + * In broadcast test cases an extra read thread is created by the main + * thread. Both the read threads will get blocked on the codition variable. + * The write thread has to broadcast the signal, which should bring both + * the read threads out of blocked state. The main thread needs to wait for + * the extra read thread also to exit in this case. + * + * f) Wait and Broadcast interruptible + * The write thread uses the nvgpu_cond_broadcast_interruptible API to + * broadcast the signal. + * + * g) Wait and Broadcast locked + * The write thread has to explicitly acquire the lock before broadcasting + * the signal and needs to release the lock explicitly after broadcast. + * + * h) Wait on condition + * The read thread waits for a particular condition to be met, rather than + * just blocking on the condition variable. + * + * i) Wait on condition interruptible + * The read thread uses the interruptible version of wait in this scenario. + * + * j) Wait on condition locked + * The read thread needs to explicitly acquire the lock before issuing a wait + * on the condition variable. And also needs to explicitly release the lock + * after getting unblocked. + * + * Output: + * All the tests return PASS if the condition variable is properly signalled + * by the write thread and further verification of shared data shows a + * succesful update from write thread with a predefined value. + * The tests return FAIL, if any of the above conditions are not met. + * + */ +int test_cond_signal(struct unit_module *m, + struct gk20a *g, void *args); +#endif /* __UNIT_POSIX_COND_H__ */