summaryrefslogtreecommitdiff
path: root/test/threads.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/threads.cpp')
-rw-r--r--test/threads.cpp111
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;
}