diff options
Diffstat (limited to 'test/threads.cpp')
-rw-r--r-- | test/threads.cpp | 111 |
1 files changed, 98 insertions, 13 deletions
diff --git a/test/threads.cpp b/test/threads.cpp index 0454761d..8d6ee151 100644 --- a/test/threads.cpp +++ b/test/threads.cpp @@ -2,14 +2,20 @@ /* * Copyright (C) 2019, Google Inc. * - * threads.cpp - Threads test + * Threads test */ #include <chrono> #include <iostream> +#include <memory> +#include <pthread.h> +#include <sched.h> #include <thread> +#include <time.h> + +#include <libcamera/base/object.h> +#include <libcamera/base/thread.h> -#include "thread.h" #include "test.h" using namespace std; @@ -33,6 +39,56 @@ private: chrono::steady_clock::duration duration_; }; +class CancelThread : public Thread +{ +public: + CancelThread(bool &cancelled) + : cancelled_(cancelled) + { + } + +protected: + void run() + { + cancelled_ = true; + + /* + * Cancel the thread and call a guaranteed cancellation point + * (nanosleep). + */ + pthread_cancel(pthread_self()); + + struct timespec req{ 0, 100*000*000 }; + nanosleep(&req, nullptr); + + cancelled_ = false; + } + +private: + bool &cancelled_; +}; + +class CpuSetTester : public Object +{ +public: + CpuSetTester(unsigned int cpuset) + : cpuset_(cpuset) {} + + bool testCpuSet() + { + int ret = sched_getcpu(); + if (static_cast<int>(cpuset_) != ret) { + cout << "Invalid cpuset: " << ret << ", expecting: " << cpuset_ << endl; + return false; + } + + return true; + } + +private: + const unsigned int cpuset_; +}; + class ThreadTest : public Test { protected: @@ -44,23 +100,23 @@ protected: int run() { /* Test Thread() retrieval for the main thread. */ - Thread *thread = Thread::current(); - if (!thread) { + Thread *mainThread = Thread::current(); + if (!mainThread) { cout << "Thread::current() failed to main thread" << endl; return TestFail; } - if (!thread->isRunning()) { + if (!mainThread->isRunning()) { cout << "Main thread is not running" << endl; return TestFail; } /* Test starting the main thread, the test shall not crash. */ - thread->start(); + mainThread->start(); /* Test the running state of a custom thread. */ - thread = new Thread(); + std::unique_ptr<Thread> thread = std::make_unique<Thread>(); thread->start(); if (!thread->isRunning()) { @@ -78,10 +134,8 @@ protected: return TestFail; } - delete thread; - /* Test waiting for completion with a timeout. */ - thread = new DelayThread(chrono::milliseconds(500)); + thread = std::make_unique<DelayThread>(chrono::milliseconds(500)); thread->start(); thread->exit(0); @@ -99,10 +153,8 @@ protected: return TestFail; } - delete thread; - /* Test waiting on a thread that isn't running. */ - thread = new Thread(); + thread = std::make_unique<Thread>(); timeout = !thread->wait(); if (timeout) { @@ -120,6 +172,39 @@ protected: return TestFail; } + /* Test thread cleanup upon abnormal termination. */ + bool cancelled = false; + bool finished = false; + + thread = std::make_unique<CancelThread>(cancelled); + thread->finished.connect(this, [&finished]() { finished = true; }); + + thread->start(); + thread->exit(0); + thread->wait(chrono::milliseconds(1000)); + + if (!cancelled || !finished) { + cout << "Cleanup failed upon abnormal termination" << endl; + return TestFail; + } + + const unsigned int numCpus = std::thread::hardware_concurrency(); + for (unsigned int i = 0; i < numCpus; ++i) { + thread = std::make_unique<Thread>(); + const std::array<const unsigned int, 1> cpus{ i }; + thread->setThreadAffinity(cpus); + thread->start(); + + CpuSetTester tester(i); + tester.moveToThread(thread.get()); + + if (!tester.invokeMethod(&CpuSetTester::testCpuSet, ConnectionTypeBlocking)) + return TestFail; + + thread->exit(0); + thread->wait(); + } + return TestPass; } |