diff --git a/Makefile.umbrella.tmk b/Makefile.umbrella.tmk index a63cc4e40..eca4417a0 100644 --- a/Makefile.umbrella.tmk +++ b/Makefile.umbrella.tmk @@ -40,6 +40,7 @@ NV_REPOSITORY_COMPONENTS += userspace/units/posix/mockio NV_REPOSITORY_COMPONENTS += userspace/units/posix/fault-injection NV_REPOSITORY_COMPONENTS += userspace/units/posix/bug NV_REPOSITORY_COMPONENTS += userspace/units/init +NV_REPOSITORY_COMPONENTS += userspace/units/posix/thread 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 fd6775816..c10d66f29 100644 --- a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export +++ b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export @@ -257,6 +257,12 @@ nvgpu_spinlock_acquire nvgpu_spinlock_init nvgpu_spinlock_release nvgpu_sw_quiesce +nvgpu_thread_create +nvgpu_thread_create_priority +nvgpu_thread_is_running +nvgpu_thread_should_stop +nvgpu_thread_stop +nvgpu_thread_stop_graceful nvgpu_userd_init_slabs nvgpu_usermode_writel nvgpu_vfree_impl diff --git a/userspace/Makefile.sources b/userspace/Makefile.sources index 975f2ecec..7afec3db3 100644 --- a/userspace/Makefile.sources +++ b/userspace/Makefile.sources @@ -47,6 +47,7 @@ UNITS := \ $(UNIT_SRC)/posix/mockio \ $(UNIT_SRC)/posix/fault-injection \ $(UNIT_SRC)/posix/bug \ + $(UNIT_SRC)/posix/thread \ $(UNIT_SRC)/pramin \ $(UNIT_SRC)/init \ $(UNIT_SRC)/interface/bsearch \ diff --git a/userspace/units/posix/thread/Makefile b/userspace/units/posix/thread/Makefile new file mode 100644 index 000000000..ea6b0c73a --- /dev/null +++ b/userspace/units/posix/thread/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-thread.o +MODULE = posix-thread + +include ../../Makefile.units diff --git a/userspace/units/posix/thread/Makefile.interface.tmk b/userspace/units/posix/thread/Makefile.interface.tmk new file mode 100644 index 000000000..ba6c828fd --- /dev/null +++ b/userspace/units/posix/thread/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-thread + +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/thread/Makefile.tmk b/userspace/units/posix/thread/Makefile.tmk new file mode 100644 index 000000000..d534350fa --- /dev/null +++ b/userspace/units/posix/thread/Makefile.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-thread + +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/thread/posix-thread.c b/userspace/units/posix/thread/posix-thread.c new file mode 100644 index 000000000..2c14727c1 --- /dev/null +++ b/userspace/units/posix/thread/posix-thread.c @@ -0,0 +1,138 @@ +/* + * 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 "posix-thread.h" + +static int test_thread_fn(void *args) +{ + int policy; + struct sched_param param; + struct unit_test_thread_data *data; + + (void) memset(¶m, 0, sizeof(struct sched_param)); + + data = (struct unit_test_thread_data *)args; + + if (data->check_priority) { + pthread_getschedparam(pthread_self(), &policy, ¶m); + data->thread_priority = param.sched_priority; + } + + data->thread_created = 1; + + if (data->check_stop) { + while (!nvgpu_thread_should_stop(&test_thread)) { + usleep(2); + } + } + + return 0; +} + +static void test_thread_stop_graceful_callback(void *args) +{ + struct unit_test_thread_data *data; + + data = (struct unit_test_thread_data *)args; + + data->callback_invoked = 1; +} + +int test_thread_cycle(struct unit_module *m, struct gk20a *g, void *args) +{ + int ret; + struct test_thread_args *test_args = (struct test_thread_args *)args; + + memset(&test_thread, 0, sizeof(struct nvgpu_thread)); + memset(&test_data, 0, sizeof(struct unit_test_thread_data)); + + if (test_args->check_stop == true) { + test_data.check_stop = 1; + } + + if (test_args->use_priority == false) { + ret = nvgpu_thread_create(&test_thread, &test_data, + test_thread_fn, + "test_thread"); + } else { + test_data.check_priority = 1; + + ret = nvgpu_thread_create_priority(&test_thread, + &test_data, test_thread_fn, + UNIT_TEST_THREAD_PRIORITY, + "test_thread_priority"); + } + + if (ret != 0) { + if (test_args->use_priority == true && ret == 1) { + unit_info(m, "No permission to set thread priority\n"); + unit_info(m, "Return PASS\n"); + return UNIT_SUCCESS; + } + unit_return_fail(m, "Thread creation failed %d\n", ret); + } + + while (!test_data.thread_created) { + unit_info(m, "Waiting for thread creation\n"); + usleep(10); + } + + if (test_args->use_priority == true) { + if (test_data.thread_priority != UNIT_TEST_THREAD_PRIORITY) { + unit_return_fail(m, "Thread priority %d mismatch\n", + test_data.thread_priority); + } + } + + if (test_args->check_stop == true) { + if (!nvgpu_thread_is_running(&test_thread)) { + unit_return_fail(m, "Thread running status is wrong\n"); + } + + if (test_args->stop_graceful == false) { + nvgpu_thread_stop(&test_thread); + } else { + nvgpu_thread_stop_graceful(&test_thread, + test_thread_stop_graceful_callback, + &test_data); + if (!test_data.callback_invoked) { + unit_return_fail(m, "Callback not invoked\n"); + } + } + } + + return UNIT_SUCCESS; +} + +struct unit_module_test posix_thread_tests[] = { + UNIT_TEST(create, test_thread_cycle, &create_normal, 0), + UNIT_TEST(create_priority, test_thread_cycle, &create_priority, 0), + UNIT_TEST(cycle, test_thread_cycle, &check_stop, 0), + UNIT_TEST(stop_graceful, test_thread_cycle, &stop_graceful, 0), +}; + +UNIT_MODULE(posix_thread, posix_thread_tests, UNIT_PRIO_POSIX_TEST); diff --git a/userspace/units/posix/thread/posix-thread.h b/userspace/units/posix/thread/posix-thread.h new file mode 100644 index 000000000..d577e172b --- /dev/null +++ b/userspace/units/posix/thread/posix-thread.h @@ -0,0 +1,158 @@ +/* + * 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. + */ + +/** + * @file + * + * Software Unit Test Specification for posix.thread + * + * @page swuts-posix.thread + */ +#ifndef __UNIT_POSIX_THREAD_H__ +#define __UNIT_POSIX_THREAD_H__ + +#include + +#define UNIT_TEST_THREAD_PRIORITY 5 + +struct test_thread_args { + bool use_priority; + bool check_stop; + bool stop_graceful; +}; + +static struct test_thread_args create_normal = { + .use_priority = false, + .check_stop = false, + .stop_graceful = false +}; + +static struct test_thread_args create_priority = { + .use_priority = true, + .check_stop = false, + .stop_graceful = false +}; + +static struct test_thread_args check_stop = { + .use_priority = false, + .check_stop = true, + .stop_graceful = false +}; + +static struct test_thread_args stop_graceful = { + .use_priority = false, + .check_stop = true, + .stop_graceful = true +}; + +struct unit_test_thread_data { + int thread_created; + int check_priority; + int thread_priority; + int check_stop; + int callback_invoked; +}; + +struct nvgpu_thread test_thread; +struct unit_test_thread_data test_data; + +/** + * Test specification for test_thread_cycle + * + * Description: Test the various functionalities provided by Threads unit. + * Main functionalities that has to be tested in Threads unit are as follows, + * 1) Thread creation + * 2) Thread creation with a priority value + * 3) Thread stop + * 4) Stop thread gracefully + * test_thread_cycle function tests all the above mentioned functionalities + * based on the input arguments. + * + * Test Type: Feature based. + * + * Inputs: + * 1) Pointer to test_thread_args as function parameter + * 2) Global instance of struct nvgpu_thread + * 3) Global instance of struct unit_test_thread_data + * + * Steps: + * Thread creation + * 1) Reset all global and shared variables to 0. + * 2) Create thread using nvgpu_thread_create. + * 3) Check the return value from nvgpu_thread_create for error. + * 4) Wait for the thread to be created by polling for a shared variable. + * 5) Return Success once the thread function is called and the shared + * variable is set which indicates a succesful thread creation. + * + * Thread creation with a priority value + * 1) Reset all global and shared variables to 0. + * 2) Create thread using nvgpu_thread_create_priority + * 3) Check the return value from nvgpu_thread_create_priority for error. + * 4) Wait for the thread to be created by polling for a shared variable. + * 5) Upon succesful creation of the thread, confirm the priority of the + * thread to be same as requested priority. + * 6) In some host machines, permission is not granted to create threads + * with priority. In that case skip the test by returning PASS. + * 7) Return PASS if the thread is created with requested priority. + * + * Thread stop + * 1) Follow steps 1 - 4 of Thread creation scenario. + * 2) The created thread does not exit unconditionally in this case. + * 3) It polls for the stop flag to be set. + * 4) The main thread checks the status of the created thread and confirms + * it to be running. + * 5) Request the thread to stop by calling nvgpu_thread_stop. + * 6) Created thread detects this inside the poll loop and exits. + * 7) Main thread continues once the created thread exits and returns PASS. + * + * Stop thread gracefully + * 1) Follow steps 1 - 4 of Thread stop scenario. + * 2) Call the api nvgpu_thread_stop_graceful and pass the function to be + * called for graceful exit. + * 3) Created thread detects the stop request and exits. + * 4) Main thread continues after the created thread exits and + * confirms if the call back function was called by checking a shared variable. + * 5) Main thread returns PASS is step 4 passes, else returns FAIL. + * + * Output: + * The output for each test scenario is as follows, + * 1) Thread creation + * Return PASS if thread creation is succesful else return FAIL. + * + * 2) Thread creation with a priority value + * Return PASS if thread creation with priority is succesful + * else return FAIL. ALso return PASS if permission is denied for creating + * a thread with priority. + * + * 3) Thread stop + * Return PASS if the created thread is stopped based on the request from + * main thread. Else return FAIL. + * + * 4) Stop thread gracefully + * Return PASS if the callback function is called and the created thread is + * stopped based on the request from main thread. + * + */ +int test_thread_cycle(struct unit_module *m, + struct gk20a *g, void *args); + +#endif /* __UNIT_POSIX_THREAD_H__ */