added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / util / interprocess_condvar.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 #ifndef REALM_UTIL_INTERPROCESS_CONDVAR
20 #define REALM_UTIL_INTERPROCESS_CONDVAR
21
22
23 #include <realm/util/features.h>
24 #include <realm/util/thread.hpp>
25 #include <realm/util/interprocess_mutex.hpp>
26 #include <cstdint>
27 #include <fcntl.h>
28 #include <sys/stat.h>
29 #include <mutex>
30
31 // Condvar Emulation is required if RobustMutex emulation is enabled
32 #if defined(REALM_ROBUST_MUTEX_EMULATION) || defined(_WIN32)
33 #define REALM_CONDVAR_EMULATION
34 #endif
35
36 namespace realm {
37 namespace util {
38
39
40 /// Condition variable for use in synchronization monitors.
41 /// This condition variable uses emulation based on named pipes
42 /// for the inter-process case, if enabled by REALM_CONDVAR_EMULATION.
43 ///
44 /// FIXME: This implementation will never release/delete pipes. This is unlikely
45 /// to be a problem as long as only a modest number of different database names
46 /// are in use
47 ///
48 /// A InterprocessCondVar is always process shared.
49 class InterprocessCondVar {
50 public:
51     InterprocessCondVar();
52     ~InterprocessCondVar() noexcept;
53
54     // Disable copying. Copying an open file will create a scenario
55     // where the same file descriptor will be opened once but closed twice.
56     InterprocessCondVar(const InterprocessCondVar&) = delete;
57     InterprocessCondVar& operator=(const InterprocessCondVar&) = delete;
58
59 /// To use the InterprocessCondVar, you also must place a structure of type
60 /// InterprocessCondVar::SharedPart in memory shared by multiple processes
61 /// or in a memory mapped file, and use set_shared_part() to associate
62 /// the condition variable with it's shared part. You must initialize
63 /// the shared part using InterprocessCondVar::init_shared_part(), but only before
64 /// first use and only when you have exclusive access to the shared part.
65
66 #ifdef REALM_CONDVAR_EMULATION
67     struct SharedPart {
68 #ifdef _WIN32
69         // Number of waiting threads.
70         int32_t m_waiters_count;
71         size_t m_was_broadcast;
72 #else
73         uint64_t signal_counter;
74         uint64_t wait_counter;
75 #endif
76     };
77 #else
78     typedef CondVar SharedPart;
79 #endif
80
81     /// You need to bind the emulation to a SharedPart in shared/mmapped memory.
82     /// The SharedPart is assumed to have been initialized (possibly by another process)
83     /// earlier through a call to init_shared_part.
84     void set_shared_part(SharedPart& shared_part, std::string path, std::string condvar_name, std::string tmp_path);
85
86     /// Initialize the shared part of a process shared condition variable.
87     /// A process shared condition variables may be represented by any number of
88     /// InterprocessCondVar instances in any number of different processes,
89     /// all sharing a common SharedPart instance, which must be in shared memory.
90     static void init_shared_part(SharedPart& shared_part);
91
92     /// Release any system resources allocated for the shared part. This should
93     /// be used *only* when you are certain, that nobody is using it.
94     void release_shared_part();
95
96     /// Wait for someone to call notify() or notify_all() on this condition
97     /// variable. The call to wait() may return spuriously, so the caller should
98     /// always re-evaluate the condition on which to wait and loop on wait()
99     /// if necessary.
100     void wait(InterprocessMutex& m, const struct timespec* tp);
101
102     /// If any threads are waiting for this condition, wake up at least one.
103     /// (Current implementation may actually wake all :-O ). The caller must
104     /// hold the lock associated with the condvar at the time of calling notify()
105     void notify() noexcept;
106
107     /// Wake up every thread that is currently waiting on this condition.
108     /// The caller must hold the lock associated with the condvar at the time
109     /// of calling notify_all().
110     void notify_all() noexcept;
111
112     /// Cleanup and release system resources if possible.
113     void close() noexcept;
114
115 private:
116     // non-zero if a shared part has been registered (always 0 on process local instances)
117     SharedPart* m_shared_part = nullptr;
118 #ifdef REALM_CONDVAR_EMULATION
119     // keep the path to allocated system resource so we can remove them again
120     std::string m_resource_path;
121     // pipe used for emulation. When using a named pipe, m_fd_read is read-write and m_fd_write is unused.
122     // When using an anonymous pipe (currently only for tvOS) m_fd_read is read-only and m_fd_write is write-only.
123     int m_fd_read = -1;
124     int m_fd_write = -1;
125
126 #ifdef _WIN32
127     // Semaphore used to queue up threads waiting for the condition to
128     // become signaled. 
129     HANDLE m_sema = 0;
130     // An auto-reset event used by the broadcast/signal thread to wait
131     // for all the waiting thread(s) to wake up and be released from the
132     // semaphore. 
133     HANDLE m_waiters_done = 0;
134     std::string m_name;
135
136     // Serialize access to m_waiters_count
137     InterprocessMutex m_waiters_lockcount;
138 #endif
139
140 #endif
141 };
142
143
144 // Implementation:
145
146
147 } // namespace util
148 } // namespace realm
149
150
151 #endif