aboutsummaryrefslogtreecommitdiffstats
path: root/util/system/event.cpp
blob: 3d4780ea10856aa4555a6aabb562b70d87090672 (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); 
}