summaryrefslogtreecommitdiffstats
path: root/util/system/mutex_ut.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/mutex_ut.cpp
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/mutex_ut.cpp')
-rw-r--r--util/system/mutex_ut.cpp129
1 files changed, 129 insertions, 0 deletions
diff --git a/util/system/mutex_ut.cpp b/util/system/mutex_ut.cpp
new file mode 100644
index 00000000000..c8d7caafa1a
--- /dev/null
+++ b/util/system/mutex_ut.cpp
@@ -0,0 +1,129 @@
+#include "mutex.h"
+#include "atomic.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/thread/pool.h>
+#include <util/random/random.h>
+
+class TMutexTest: public TTestBase {
+ UNIT_TEST_SUITE(TMutexTest);
+ UNIT_TEST(TestBasics)
+ UNIT_TEST(TestFake)
+ UNIT_TEST(TestRecursive)
+ UNIT_TEST_SUITE_END();
+
+ struct TSharedData {
+ TSharedData()
+ : sharedCounter(0)
+ , failed(false)
+ {
+ }
+
+ volatile ui32 sharedCounter;
+ TMutex mutex;
+ TFakeMutex fakeMutex;
+
+ bool failed;
+ };
+
+ class TThreadTask: public IObjectInQueue {
+ public:
+ using PFunc = void (TThreadTask::*)(void);
+
+ TThreadTask(PFunc func, TSharedData& data, size_t id)
+ : Func_(func)
+ , Data_(data)
+ , Id_(id)
+ {
+ }
+
+ void Process(void*) override {
+ THolder<TThreadTask> This(this);
+
+ (this->*Func_)();
+ }
+
+#define FAIL_ASSERT(cond) \
+ if (!(cond)) { \
+ Data_.failed = true; \
+ }
+ void RunBasics() {
+ Data_.mutex.Acquire();
+
+ ui32 oldCounter = ui32(Data_.sharedCounter + Id_);
+ Data_.sharedCounter = oldCounter;
+ usleep(10 + RandomNumber<ui32>() % 10);
+ FAIL_ASSERT(Data_.sharedCounter == oldCounter);
+
+ Data_.mutex.Release();
+ }
+
+ void RunFakeMutex() {
+ bool res = Data_.fakeMutex.TryAcquire();
+ FAIL_ASSERT(res);
+ }
+
+ void RunRecursiveMutex() {
+ for (size_t i = 0; i < Id_ + 1; ++i) {
+ Data_.mutex.Acquire();
+ ++Data_.sharedCounter;
+ usleep(1);
+ }
+ FAIL_ASSERT(Data_.sharedCounter == Id_ + 1);
+
+ bool res = Data_.mutex.TryAcquire();
+ FAIL_ASSERT(res);
+ Data_.mutex.Release();
+
+ for (size_t i = 0; i < Id_; ++i) {
+ --Data_.sharedCounter;
+ Data_.mutex.Release();
+ }
+ FAIL_ASSERT(Data_.sharedCounter == 1);
+ --Data_.sharedCounter;
+ Data_.mutex.Release();
+ }
+
+#undef FAIL_ASSERT
+
+ private:
+ PFunc Func_;
+ TSharedData& Data_;
+ size_t Id_;
+ };
+
+private:
+#define RUN_CYCLE(what, count) \
+ Q_.Start(count); \
+ for (size_t i = 0; i < count; ++i) { \
+ UNIT_ASSERT(Q_.Add(new TThreadTask(&TThreadTask::what, Data_, i))); \
+ } \
+ Q_.Stop(); \
+ bool b = Data_.failed; \
+ Data_.failed = false; \
+ UNIT_ASSERT(!b);
+
+ void TestBasics() {
+ RUN_CYCLE(RunBasics, 5);
+
+ UNIT_ASSERT(Data_.sharedCounter == 10);
+ Data_.sharedCounter = 0;
+ }
+
+ void TestFake() {
+ RUN_CYCLE(RunFakeMutex, 3);
+ }
+
+ void TestRecursive() {
+ RUN_CYCLE(RunRecursiveMutex, 4);
+ }
+
+#undef RUN_CYCLE
+
+private:
+ TSharedData Data_;
+ TThreadPool Q_;
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TMutexTest)