aboutsummaryrefslogblamecommitdiffstats
path: root/util/system/rwlock_ut.cpp
blob: 5dd225af678481c95ef1ccd2d2f763605994d04c (plain) (tree)
1
2
3
4
5
6
7
8
9
                   
 
                                                  
 
                             
                               
                 
                                      
                                  
                                 

                          
                                          
 
                            

                       

                                              
                                                  
 





                                                                           
 
                                      


                                            
 

                              
     
                                      
 
                              
                        
                                                          
                        
                              
 
                                      
 


                                                 
 
                                                             
                                                     
                                      
 



                                                 
 
                                                                                            
                                                     
                                      
 
                                               
                 
         
                  



                           
      









                                                                                    
 

                                 
 

                                        
                
                      
                   

                                          
#include "rwlock.h"

#include <library/cpp/testing/unittest/registar.h>

#include <util/thread/pool.h>
#include <util/random/random.h>

#include <atomic>

class TRWMutexTest: public TTestBase {
    UNIT_TEST_SUITE(TRWMutexTest);
    UNIT_TEST(TestReaders)
    UNIT_TEST(TestReadersWriters)
    UNIT_TEST_SUITE_END();

    struct TSharedData {
        std::atomic<size_t> writersIn = 0;
        std::atomic<size_t> readersIn = 0;

        bool failed = false;

        TRWMutex mutex;
    };

    class TThreadTask: public IObjectInQueue {
    public:
        using PFunc = void (TThreadTask::*)(void);

        TThreadTask(PFunc func, TSharedData& data, size_t id, size_t total)
            : Func_(func)
            , Data_(data)
            , Id_(id)
            , Total_(total)
        {
        }

        void Process(void*) override {
            THolder<TThreadTask> This(this);

            (this->*Func_)();
        }

#define FAIL_ASSERT(cond)    \
    if (!(cond)) {           \
        Data_.failed = true; \
    }
        void RunReaders() {
            Data_.mutex.AcquireRead();

            ++Data_.readersIn;
            usleep(100);
            FAIL_ASSERT(Data_.readersIn.load() == Total_);
            usleep(100);
            --Data_.readersIn;

            Data_.mutex.ReleaseRead();
        }

        void RunReadersWriters() {
            if (Id_ % 2 == 0) {
                for (size_t i = 0; i < 10; ++i) {
                    Data_.mutex.AcquireRead();

                    ++Data_.readersIn;
                    FAIL_ASSERT(Data_.writersIn.load() == 0);
                    usleep(RandomNumber<ui32>() % 5);
                    --Data_.readersIn;

                    Data_.mutex.ReleaseRead();
                }
            } else {
                for (size_t i = 0; i < 10; ++i) {
                    Data_.mutex.AcquireWrite();

                    ++Data_.writersIn;
                    FAIL_ASSERT(Data_.readersIn.load() == 0 && Data_.writersIn.load() == 1);
                    usleep(RandomNumber<ui32>() % 5);
                    --Data_.writersIn;

                    Data_.mutex.ReleaseWrite();
                }
            }
        }
#undef FAIL_ASSERT

    private:
        PFunc Func_;
        TSharedData& Data_;
        size_t Id_;
        size_t Total_;
    };

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, count))); \
    }                                                                              \
    Q_.Stop();                                                                     \
    bool b = Data_.failed;                                                         \
    Data_.failed = false;                                                          \
    UNIT_ASSERT(!b);

    void TestReaders() {
        RUN_CYCLE(RunReaders, 1);
    }

    void TestReadersWriters() {
        RUN_CYCLE(RunReadersWriters, 1);
    }

#undef RUN_CYCLE
private:
    TSharedData Data_;
    TThreadPool Q_;
};

UNIT_TEST_SUITE_REGISTRATION(TRWMutexTest)