added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / util / apple / event_loop_signal.hpp
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 <atomic>
20 #include <CoreFoundation/CFRunLoop.h>
21
22 namespace realm {
23 namespace util {
24 template<typename Callback>
25 class EventLoopSignal {
26 public:
27     EventLoopSignal(Callback&& callback)
28     {
29         struct RefCountedRunloopCallback {
30             Callback callback;
31             std::atomic<size_t> ref_count;
32         };
33
34         CFRunLoopSourceContext ctx{};
35         ctx.info = new RefCountedRunloopCallback{std::move(callback), {0}};
36         ctx.perform = [](void* info) {
37             static_cast<RefCountedRunloopCallback*>(info)->callback();
38         };
39         ctx.retain = [](const void* info) {
40             static_cast<RefCountedRunloopCallback*>(const_cast<void*>(info))->ref_count.fetch_add(1, std::memory_order_relaxed);
41             return info;
42         };
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) {
46                 delete ptr;
47             }
48         };
49
50         m_runloop = CFRunLoopGetCurrent();
51         CFRetain(m_runloop);
52         m_signal = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &ctx);
53         CFRunLoopAddSource(m_runloop, m_signal, kCFRunLoopDefaultMode);
54     }
55
56     ~EventLoopSignal()
57     {
58         CFRunLoopSourceInvalidate(m_signal);
59         CFRelease(m_signal);
60         CFRelease(m_runloop);
61     }
62
63     EventLoopSignal(EventLoopSignal&&) = delete;
64     EventLoopSignal& operator=(EventLoopSignal&&) = delete;
65     EventLoopSignal(EventLoopSignal const&) = delete;
66     EventLoopSignal& operator=(EventLoopSignal const&) = delete;
67
68     void notify()
69     {
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
73         // waiting for events
74         CFRunLoopWakeUp(m_runloop);
75     }
76
77 private:
78     CFRunLoopRef m_runloop;
79     CFRunLoopSourceRef m_signal;
80 };
81 } // namespace util
82 } // namespace realm