1 ////////////////////////////////////////////////////////////////////////////
3 // Copyright 2016 Realm Inc.
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
9 // http://www.apache.org/licenses/LICENSE-2.0
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.
17 ////////////////////////////////////////////////////////////////////////////
20 #include <CoreFoundation/CFRunLoop.h>
24 template<typename Callback>
25 class EventLoopSignal {
27 EventLoopSignal(Callback&& callback)
29 struct RefCountedRunloopCallback {
31 std::atomic<size_t> ref_count;
34 CFRunLoopSourceContext ctx{};
35 ctx.info = new RefCountedRunloopCallback{std::move(callback), {0}};
36 ctx.perform = [](void* info) {
37 static_cast<RefCountedRunloopCallback*>(info)->callback();
39 ctx.retain = [](const void* info) {
40 static_cast<RefCountedRunloopCallback*>(const_cast<void*>(info))->ref_count.fetch_add(1, std::memory_order_relaxed);
43 ctx.release = [](const void* info) {
44 auto ptr = static_cast<RefCountedRunloopCallback*>(const_cast<void*>(info));
45 if (ptr->ref_count.fetch_add(-1, std::memory_order_acq_rel) == 1) {
50 m_runloop = CFRunLoopGetCurrent();
52 m_signal = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &ctx);
53 CFRunLoopAddSource(m_runloop, m_signal, kCFRunLoopDefaultMode);
58 CFRunLoopSourceInvalidate(m_signal);
63 EventLoopSignal(EventLoopSignal&&) = delete;
64 EventLoopSignal& operator=(EventLoopSignal&&) = delete;
65 EventLoopSignal(EventLoopSignal const&) = delete;
66 EventLoopSignal& operator=(EventLoopSignal const&) = delete;
70 CFRunLoopSourceSignal(m_signal);
71 // Signalling the source makes it run the next time the runloop gets
72 // to it, but doesn't make the runloop start if it's currently idle
74 CFRunLoopWakeUp(m_runloop);
78 CFRunLoopRef m_runloop;
79 CFRunLoopSourceRef m_signal;