• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / kraen.hansen_76

26 Aug 2024 12:57PM UTC coverage: 91.097% (+0.002%) from 91.095%
kraen.hansen_76

Pull #7903

Evergreen

web-flow
Merge branch 'master' into kh/passing-scheduler
Pull Request #7903: Passing scheduler to `EventLoopDispatcher`, `schedulerWrapBlockingFunction` and through `RealmConfig`

102818 of 181636 branches covered (56.61%)

0 of 4 new or added lines in 1 file covered. (0.0%)

58 existing lines in 17 files now uncovered.

217376 of 238621 relevant lines covered (91.1%)

5956990.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.19
/test/object-store/util/event_loop.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2016 Realm Inc.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 * http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 **************************************************************************/
18

19
#include "util/event_loop.hpp"
20

21
#include <realm/object-store/util/scheduler.hpp>
22
#include <realm/object-store/util/event_loop_dispatcher.hpp>
23
#include <realm/util/scope_exit.hpp>
24
#include <realm/util/features.h>
25

26
#include <mutex>
27
#include <stdexcept>
28
#include <vector>
29

30
#if TEST_SCHEDULER_UV
31
#include <uv.h>
32
#elif REALM_PLATFORM_APPLE
33
#include <realm/util/cf_ptr.hpp>
34
#include <CoreFoundation/CoreFoundation.h>
35
#elif REALM_ANDROID
36
// TODO: implement event loop for android: see Scheduler::make_alooper()
37
#elif defined(__EMSCRIPTEN__)
38
// TODO: implement event loop for Emscripten
39
#else
40
#error "No EventLoop implementation selected, tests will fail"
41
#endif
42

43
using namespace realm::util;
44

45
namespace {
46
template <typename Desired, typename Actual>
47
void static_assert_EventLoopDispatcher_guide(const EventLoopDispatcher<Actual>&)
48
{
×
49
    static_assert(std::is_same_v<Actual, Desired>);
×
50
}
×
51

52
[[maybe_unused]] void check_EventLoopDispatcher_guides()
53
{
×
54
    // This doesn't actually run, the only "test" is that it compiles.
×
55
    static_assert_EventLoopDispatcher_guide<void()>(EventLoopDispatcher([] {}));
×
56
    static_assert_EventLoopDispatcher_guide<void()>(EventLoopDispatcher(+[] {}));
×
57
    static_assert_EventLoopDispatcher_guide<void()>(EventLoopDispatcher([]() mutable {}));
×
58
    static_assert_EventLoopDispatcher_guide<void()>(EventLoopDispatcher(+[]() mutable {}));
×
59
    static_assert_EventLoopDispatcher_guide<void()>(EventLoopDispatcher([]() noexcept {}));
×
60
    static_assert_EventLoopDispatcher_guide<void()>(EventLoopDispatcher(+[]() noexcept {}));
×
61
    static_assert_EventLoopDispatcher_guide<void()>(EventLoopDispatcher([]() mutable noexcept {}));
×
62
    static_assert_EventLoopDispatcher_guide<void()>(EventLoopDispatcher(+[]() mutable noexcept {}));
×
63

×
64
    static_assert_EventLoopDispatcher_guide<void(int)>(EventLoopDispatcher([](int) {}));
×
65
    static_assert_EventLoopDispatcher_guide<void(int)>(EventLoopDispatcher(+[](int) {}));
×
66
    static_assert_EventLoopDispatcher_guide<void(int, const double&)>(EventLoopDispatcher([](int, const double&) {}));
×
67
    static_assert_EventLoopDispatcher_guide<void(int, const double&)>(
×
68
        EventLoopDispatcher(+[](int, const double&) {}));
×
69

×
70
    struct Funcy {
×
71
        void operator()(int) const& noexcept {}
×
72
    };
×
73
    static_assert_EventLoopDispatcher_guide<void(int)>(EventLoopDispatcher(Funcy()));
×
NEW
74

×
NEW
75
    // Passing a scheduler as second argument
×
NEW
76
    auto scheduler = Scheduler::make_dummy();
×
NEW
77
    static_assert_EventLoopDispatcher_guide<void()>(EventLoopDispatcher([] {}, scheduler));
×
UNCOV
78
}
×
79
} // namespace
80

81
struct EventLoop::Impl {
82
    // Returns the main event loop.
83
    static std::unique_ptr<Impl> main();
84

85
    // Run the event loop until the given return predicate returns true
86
    void run_until(util::FunctionRef<bool()> predicate);
87

88
    // Schedule execution of the given function on the event loop.
89
    void perform(util::UniqueFunction<void()>);
90

91
    // Run the event loop until all currently pending work has been run.
92
    void run_pending();
93

94
    ~Impl();
95

96
private:
97
#if TEST_SCHEDULER_UV
98
    Impl(uv_loop_t* loop);
99

100
    std::vector<util::UniqueFunction<void()>> m_pending_work;
101
    std::mutex m_mutex;
102
    uv_loop_t* m_loop;
103
    uv_async_t m_perform_work;
104
#elif REALM_PLATFORM_APPLE
105
    Impl(util::CFPtr<CFRunLoopRef> loop)
106
        : m_loop(std::move(loop))
107
    {
2✔
108
    }
2✔
109

110
    util::CFPtr<CFRunLoopRef> m_loop;
111
#endif
112
};
113

114
EventLoop& EventLoop::main()
115
{
678✔
116
    static EventLoop main(Impl::main());
678✔
117
    return main;
678✔
118
}
678✔
119

120
EventLoop::EventLoop(std::unique_ptr<Impl> impl)
121
    : m_impl(std::move(impl))
2✔
122
{
4✔
123
}
4✔
124

125
EventLoop::~EventLoop() = default;
4✔
126

127
void EventLoop::run_until(util::FunctionRef<bool()> predicate)
128
{
674✔
129
    return m_impl->run_until(predicate);
674✔
130
}
674✔
131

132
void EventLoop::perform(util::UniqueFunction<void()> function)
133
{
×
134
    return m_impl->perform(std::move(function));
×
135
}
×
136

137
void EventLoop::run_pending()
138
{
4✔
139
    return m_impl->run_pending();
4✔
140
}
4✔
141

142
#if TEST_SCHEDULER_UV
143

144
bool EventLoop::has_implementation()
145
{
2,048✔
146
    return true;
2,048✔
147
}
2,048✔
148

149
std::unique_ptr<EventLoop::Impl> EventLoop::Impl::main()
150
{
2✔
151
    return std::unique_ptr<Impl>(new Impl(uv_default_loop()));
2✔
152
}
2✔
153

154
EventLoop::Impl::Impl(uv_loop_t* loop)
155
    : m_loop(loop)
2✔
156
{
2✔
157
    m_perform_work.data = this;
2✔
158
    uv_async_init(uv_default_loop(), &m_perform_work, [](uv_async_t* handle) {
2✔
159
        std::vector<util::UniqueFunction<void()>> pending_work;
160
        {
161
            Impl& self = *static_cast<Impl*>(handle->data);
162
            std::lock_guard<std::mutex> lock(self.m_mutex);
163
            std::swap(pending_work, self.m_pending_work);
164
        }
165

166
        for (auto& f : pending_work)
×
167
            f();
168
    });
169
}
2✔
170

171
EventLoop::Impl::~Impl()
172
{
2✔
173
    uv_close((uv_handle_t*)&m_perform_work, [](uv_handle_t*) {});
2✔
174
    uv_loop_close(m_loop);
2✔
175
}
2✔
176

177
struct IdleHandler {
178
    uv_idle_t* idle = new uv_idle_t;
179

180
    IdleHandler(uv_loop_t* loop)
181
    {
210✔
182
        uv_idle_init(loop, idle);
210✔
183
    }
210✔
184
    ~IdleHandler()
185
    {
210✔
186
        uv_close(reinterpret_cast<uv_handle_t*>(idle), [](uv_handle_t* handle) {
210✔
187
            delete reinterpret_cast<uv_idle_t*>(handle);
208✔
188
        });
208✔
189
    }
210✔
190
};
191

192
void EventLoop::Impl::run_until(util::FunctionRef<bool()> predicate)
193
{
330✔
194
    if (predicate())
330✔
195
        return;
120✔
196

197
    IdleHandler observer(m_loop);
210✔
198
    observer.idle->data = &predicate;
210✔
199

200
    uv_idle_start(observer.idle, [](uv_idle_t* handle) {
187,035,449✔
201
        auto& predicate = *static_cast<util::FunctionRef<bool()>*>(handle->data);
187,035,449✔
202
        if (predicate()) {
187,035,449✔
203
            uv_stop(handle->loop);
207✔
204
        }
207✔
205
    });
187,035,449✔
206

207
    auto cleanup = make_scope_exit([&]() noexcept {
210✔
208
        uv_idle_stop(observer.idle);
210✔
209
    });
210✔
210
    uv_run(m_loop, UV_RUN_DEFAULT);
210✔
211
}
210✔
212

213
void EventLoop::Impl::perform(util::UniqueFunction<void()> f)
214
{
215
    {
216
        std::lock_guard<std::mutex> lock(m_mutex);
217
        m_pending_work.push_back(std::move(f));
218
    }
219
    uv_async_send(&m_perform_work);
220
}
221

222
void EventLoop::Impl::run_pending()
223
{
2✔
224
    uv_run(m_loop, UV_RUN_NOWAIT);
2✔
225
}
2✔
226

227
#elif REALM_PLATFORM_APPLE
228

229
bool EventLoop::has_implementation()
230
{
2,048✔
231
    return true;
2,048✔
232
}
2,048✔
233

234
std::unique_ptr<EventLoop::Impl> EventLoop::Impl::main()
235
{
2✔
236
    return std::unique_ptr<Impl>(new Impl(retainCF(CFRunLoopGetMain())));
2✔
237
}
2✔
238

239
EventLoop::Impl::~Impl() = default;
2✔
240

241
void EventLoop::Impl::run_until(util::FunctionRef<bool()> predicate)
242
{
344✔
243
    REALM_ASSERT(m_loop.get() == CFRunLoopGetCurrent());
344✔
244

245
    auto callback = [](CFRunLoopObserverRef, CFRunLoopActivity, void* info) {
440,343✔
246
        if ((*static_cast<util::FunctionRef<bool()>*>(info))()) {
440,343✔
247
            CFRunLoopStop(CFRunLoopGetCurrent());
1,115✔
248
        }
1,115✔
249
    };
440,343✔
250
    CFRunLoopObserverContext ctx{};
344✔
251
    ctx.info = &predicate;
344✔
252
    auto observer =
344✔
253
        adoptCF(CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, true, 0, callback, &ctx));
344✔
254
    auto timer = adoptCF(CFRunLoopTimerCreateWithHandler(
344✔
255
        kCFAllocatorDefault, CFAbsoluteTimeGetCurrent(), 0.0005, 0, 0,
344✔
256
        ^(CFRunLoopTimerRef){
109,411✔
257
            // Do nothing. The timer firing is sufficient to cause our runloop observer to run.
258
        }));
109,411✔
259
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer.get(), kCFRunLoopCommonModes);
344✔
260
    CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer.get(), kCFRunLoopCommonModes);
344✔
261
    auto cleanup = make_scope_exit([&]() noexcept {
344✔
262
        CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer.get(), kCFRunLoopCommonModes);
344✔
263
        CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), observer.get(), kCFRunLoopCommonModes);
344✔
264
    });
344✔
265
    CFRunLoopRun();
344✔
266
}
344✔
267

268
void EventLoop::Impl::perform(util::UniqueFunction<void()> func)
269
{
270
    __block auto f = std::move(func);
271
    CFRunLoopPerformBlock(m_loop.get(), kCFRunLoopDefaultMode, ^{
272
        f();
273
    });
274
    CFRunLoopWakeUp(m_loop.get());
275
}
276

277
void EventLoop::Impl::run_pending()
278
{
2✔
279
    while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource)
4✔
280
        ;
2✔
281
}
2✔
282

283
#else
284

285
bool EventLoop::has_implementation()
286
{
287
    return false;
288
}
289
std::unique_ptr<EventLoop::Impl> EventLoop::Impl::main()
290
{
291
    return nullptr;
292
}
293
EventLoop::Impl::~Impl() = default;
294
void EventLoop::Impl::run_until(util::FunctionRef<bool()>)
295
{
296
    printf("WARNING: there is no event loop implementation and nothing is happening.\n");
297
}
298
void EventLoop::Impl::perform(util::UniqueFunction<void()>)
299
{
300
    printf("WARNING: there is no event loop implementation and nothing is happening.\n");
301
}
302
void EventLoop::Impl::run_pending()
303
{
304
    printf("WARNING: there is no event loop implementation and nothing is happening.\n");
305
}
306

307
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc