aboutsummaryrefslogtreecommitdiffstats
path: root/util/system/event.cpp
blob: 6f70a37e05507b2cf6dc5c613c5f9f9c907cc12e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "datetime.h"
#include "defaults.h"

#include <cstdio>

#include "atomic.h"
#include "event.h"
#include "mutex.h"
#include "condvar.h"

#ifdef _win_
    #include "winint.h"
#endif

class TSystemEvent::TEvImpl: public TAtomicRefCount<TSystemEvent::TEvImpl> {
public:
#ifdef _win_
    inline TEvImpl(ResetMode rmode) {
        cond = CreateEvent(nullptr, rmode == rManual ? true : false, false, nullptr);
    }

    inline ~TEvImpl() { 
        CloseHandle(cond);
    }

    inline void Reset() noexcept { 
        ResetEvent(cond);
    }

    inline void Signal() noexcept { 
        SetEvent(cond);
    }

    inline bool WaitD(TInstant deadLine) noexcept { 
        if (deadLine == TInstant::Max()) {
            return WaitForSingleObject(cond, INFINITE) == WAIT_OBJECT_0;
        }

        const TInstant now = Now();

        if (now < deadLine) {
            //TODO
            return WaitForSingleObject(cond, (deadLine - now).MilliSeconds()) == WAIT_OBJECT_0;
        }

        return (WaitForSingleObject(cond, 0) == WAIT_OBJECT_0);
    }
#else
    inline TEvImpl(ResetMode rmode)
        : Manual(rmode == rManual ? true : false)
    {
    }

    inline void Signal() noexcept { 
        if (Manual && AtomicGet(Signaled)) {
            return; // shortcut
        }

        with_lock (Mutex) {
            AtomicSet(Signaled, 1);
        }

        if (Manual) {
            Cond.BroadCast();
        } else {
            Cond.Signal();
        }
    }

    inline void Reset() noexcept { 
        AtomicSet(Signaled, 0);
    }

    inline bool WaitD(TInstant deadLine) noexcept { 
        if (Manual && AtomicGet(Signaled)) {
            return true; // shortcut
        }

        bool resSignaled = true;

        with_lock (Mutex) {
            while (!AtomicGet(Signaled)) {
                if (!Cond.WaitD(Mutex, deadLine)) {
                    resSignaled = AtomicGet(Signaled); // timed out, but Signaled could have been set

                    break;
                }
            }

            if (!Manual) {
                AtomicSet(Signaled, 0);
            }
        }

        return resSignaled;
    }
#endif

private:
#ifdef _win_
    HANDLE cond;
#else
    TCondVar Cond;
    TMutex Mutex;
    TAtomic Signaled = 0;
    bool Manual;
#endif
};

TSystemEvent::TSystemEvent(ResetMode rmode)
    : EvImpl_(new TEvImpl(rmode))
{
}

TSystemEvent::TSystemEvent(const TSystemEvent& other) noexcept
    : EvImpl_(other.EvImpl_)
{
}

TSystemEvent& TSystemEvent::operator=(const TSystemEvent& other) noexcept {
    EvImpl_ = other.EvImpl_;
    return *this;
}

TSystemEvent::~TSystemEvent() = default;

void TSystemEvent::Reset() noexcept {
    EvImpl_->Reset();
}

void TSystemEvent::Signal() noexcept {
    EvImpl_->Signal();
}

bool TSystemEvent::WaitD(TInstant deadLine) noexcept {
    return EvImpl_->WaitD(deadLine);
}