Chris@16
|
1 //////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
2 //
|
Chris@16
|
3 // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
|
Chris@16
|
4 // Software License, Version 1.0. (See accompanying file
|
Chris@16
|
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
6 //
|
Chris@16
|
7 // See http://www.boost.org/libs/interprocess for documentation.
|
Chris@16
|
8 //
|
Chris@16
|
9 //////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
10
|
Chris@16
|
11 #ifndef BOOST_INTERPROCESS_FILE_LOCK_HPP
|
Chris@16
|
12 #define BOOST_INTERPROCESS_FILE_LOCK_HPP
|
Chris@16
|
13
|
Chris@16
|
14 #if (defined _MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
15 # pragma once
|
Chris@16
|
16 #endif
|
Chris@16
|
17
|
Chris@16
|
18 #include <boost/interprocess/detail/config_begin.hpp>
|
Chris@16
|
19 #include <boost/interprocess/detail/workaround.hpp>
|
Chris@16
|
20 #include <boost/interprocess/exceptions.hpp>
|
Chris@16
|
21 #include <boost/interprocess/detail/os_file_functions.hpp>
|
Chris@16
|
22 #include <boost/interprocess/detail/os_thread_functions.hpp>
|
Chris@16
|
23 #include <boost/interprocess/detail/posix_time_types_wrk.hpp>
|
Chris@16
|
24 #include <boost/interprocess/sync/spin/wait.hpp>
|
Chris@16
|
25 #include <boost/move/move.hpp>
|
Chris@16
|
26
|
Chris@16
|
27 //!\file
|
Chris@16
|
28 //!Describes a class that wraps file locking capabilities.
|
Chris@16
|
29
|
Chris@16
|
30 namespace boost {
|
Chris@16
|
31 namespace interprocess {
|
Chris@16
|
32
|
Chris@16
|
33
|
Chris@16
|
34 //!A file lock, is a mutual exclusion utility similar to a mutex using a
|
Chris@16
|
35 //!file. A file lock has sharable and exclusive locking capabilities and
|
Chris@16
|
36 //!can be used with scoped_lock and sharable_lock classes.
|
Chris@16
|
37 //!A file lock can't guarantee synchronization between threads of the same
|
Chris@16
|
38 //!process so just use file locks to synchronize threads from different processes.
|
Chris@16
|
39 class file_lock
|
Chris@16
|
40 {
|
Chris@16
|
41 /// @cond
|
Chris@16
|
42 //Non-copyable
|
Chris@16
|
43 BOOST_MOVABLE_BUT_NOT_COPYABLE(file_lock)
|
Chris@16
|
44 /// @endcond
|
Chris@16
|
45
|
Chris@16
|
46 public:
|
Chris@16
|
47 //!Constructs an empty file mapping.
|
Chris@16
|
48 //!Does not throw
|
Chris@16
|
49 file_lock()
|
Chris@16
|
50 : m_file_hnd(file_handle_t(ipcdetail::invalid_file()))
|
Chris@16
|
51 {}
|
Chris@16
|
52
|
Chris@16
|
53 //!Opens a file lock. Throws interprocess_exception if the file does not
|
Chris@16
|
54 //!exist or there are no operating system resources.
|
Chris@16
|
55 file_lock(const char *name);
|
Chris@16
|
56
|
Chris@16
|
57 //!Moves the ownership of "moved"'s file mapping object to *this.
|
Chris@16
|
58 //!After the call, "moved" does not represent any file mapping object.
|
Chris@16
|
59 //!Does not throw
|
Chris@16
|
60 file_lock(BOOST_RV_REF(file_lock) moved)
|
Chris@16
|
61 : m_file_hnd(file_handle_t(ipcdetail::invalid_file()))
|
Chris@16
|
62 { this->swap(moved); }
|
Chris@16
|
63
|
Chris@16
|
64 //!Moves the ownership of "moved"'s file mapping to *this.
|
Chris@16
|
65 //!After the call, "moved" does not represent any file mapping.
|
Chris@16
|
66 //!Does not throw
|
Chris@16
|
67 file_lock &operator=(BOOST_RV_REF(file_lock) moved)
|
Chris@16
|
68 {
|
Chris@16
|
69 file_lock tmp(boost::move(moved));
|
Chris@16
|
70 this->swap(tmp);
|
Chris@16
|
71 return *this;
|
Chris@16
|
72 }
|
Chris@16
|
73
|
Chris@16
|
74 //!Closes a file lock. Does not throw.
|
Chris@16
|
75 ~file_lock();
|
Chris@16
|
76
|
Chris@16
|
77 //!Swaps two file_locks.
|
Chris@16
|
78 //!Does not throw.
|
Chris@16
|
79 void swap(file_lock &other)
|
Chris@16
|
80 {
|
Chris@16
|
81 file_handle_t tmp = m_file_hnd;
|
Chris@16
|
82 m_file_hnd = other.m_file_hnd;
|
Chris@16
|
83 other.m_file_hnd = tmp;
|
Chris@16
|
84 }
|
Chris@16
|
85
|
Chris@16
|
86 //Exclusive locking
|
Chris@16
|
87
|
Chris@16
|
88 //!Effects: The calling thread tries to obtain exclusive ownership of the mutex,
|
Chris@16
|
89 //! and if another thread has exclusive, or sharable ownership of
|
Chris@16
|
90 //! the mutex, it waits until it can obtain the ownership.
|
Chris@16
|
91 //!Throws: interprocess_exception on error.
|
Chris@16
|
92 void lock();
|
Chris@16
|
93
|
Chris@16
|
94 //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
|
Chris@16
|
95 //! without waiting. If no other thread has exclusive, or sharable
|
Chris@16
|
96 //! ownership of the mutex this succeeds.
|
Chris@16
|
97 //!Returns: If it can acquire exclusive ownership immediately returns true.
|
Chris@16
|
98 //! If it has to wait, returns false.
|
Chris@16
|
99 //!Throws: interprocess_exception on error.
|
Chris@16
|
100 bool try_lock();
|
Chris@16
|
101
|
Chris@16
|
102 //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
|
Chris@16
|
103 //! waiting if necessary until no other thread has exclusive, or sharable
|
Chris@16
|
104 //! ownership of the mutex or abs_time is reached.
|
Chris@16
|
105 //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
|
Chris@16
|
106 //!Throws: interprocess_exception on error.
|
Chris@16
|
107 bool timed_lock(const boost::posix_time::ptime &abs_time);
|
Chris@16
|
108
|
Chris@16
|
109 //!Precondition: The thread must have exclusive ownership of the mutex.
|
Chris@16
|
110 //!Effects: The calling thread releases the exclusive ownership of the mutex.
|
Chris@16
|
111 //!Throws: An exception derived from interprocess_exception on error.
|
Chris@16
|
112 void unlock();
|
Chris@16
|
113
|
Chris@16
|
114 //Sharable locking
|
Chris@16
|
115
|
Chris@16
|
116 //!Effects: The calling thread tries to obtain sharable ownership of the mutex,
|
Chris@16
|
117 //! and if another thread has exclusive ownership of the mutex, waits until
|
Chris@16
|
118 //! it can obtain the ownership.
|
Chris@16
|
119 //!Throws: interprocess_exception on error.
|
Chris@16
|
120 void lock_sharable();
|
Chris@16
|
121
|
Chris@16
|
122 //!Effects: The calling thread tries to acquire sharable ownership of the mutex
|
Chris@16
|
123 //! without waiting. If no other thread has exclusive ownership of the
|
Chris@16
|
124 //! mutex this succeeds.
|
Chris@16
|
125 //!Returns: If it can acquire sharable ownership immediately returns true. If it
|
Chris@16
|
126 //! has to wait, returns false.
|
Chris@16
|
127 //!Throws: interprocess_exception on error.
|
Chris@16
|
128 bool try_lock_sharable();
|
Chris@16
|
129
|
Chris@16
|
130 //!Effects: The calling thread tries to acquire sharable ownership of the mutex
|
Chris@16
|
131 //! waiting if necessary until no other thread has exclusive ownership of
|
Chris@16
|
132 //! the mutex or abs_time is reached.
|
Chris@16
|
133 //!Returns: If acquires sharable ownership, returns true. Otherwise returns false.
|
Chris@16
|
134 //!Throws: interprocess_exception on error.
|
Chris@16
|
135 bool timed_lock_sharable(const boost::posix_time::ptime &abs_time);
|
Chris@16
|
136
|
Chris@16
|
137 //!Precondition: The thread must have sharable ownership of the mutex.
|
Chris@16
|
138 //!Effects: The calling thread releases the sharable ownership of the mutex.
|
Chris@16
|
139 //!Throws: An exception derived from interprocess_exception on error.
|
Chris@16
|
140 void unlock_sharable();
|
Chris@16
|
141 /// @cond
|
Chris@16
|
142 private:
|
Chris@16
|
143 file_handle_t m_file_hnd;
|
Chris@16
|
144
|
Chris@16
|
145 bool timed_acquire_file_lock
|
Chris@16
|
146 (file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time)
|
Chris@16
|
147 {
|
Chris@16
|
148 //Obtain current count and target time
|
Chris@16
|
149 boost::posix_time::ptime now = microsec_clock::universal_time();
|
Chris@16
|
150 using namespace boost::detail;
|
Chris@16
|
151
|
Chris@16
|
152 if(now >= abs_time) return false;
|
Chris@16
|
153 spin_wait swait;
|
Chris@16
|
154 do{
|
Chris@16
|
155 if(!ipcdetail::try_acquire_file_lock(hnd, acquired))
|
Chris@16
|
156 return false;
|
Chris@16
|
157
|
Chris@16
|
158 if(acquired)
|
Chris@16
|
159 return true;
|
Chris@16
|
160 else{
|
Chris@16
|
161 now = microsec_clock::universal_time();
|
Chris@16
|
162
|
Chris@16
|
163 if(now >= abs_time){
|
Chris@16
|
164 acquired = false;
|
Chris@16
|
165 return true;
|
Chris@16
|
166 }
|
Chris@16
|
167 // relinquish current time slice
|
Chris@16
|
168 swait.yield();
|
Chris@16
|
169 }
|
Chris@16
|
170 }while (true);
|
Chris@16
|
171 }
|
Chris@16
|
172
|
Chris@16
|
173 bool timed_acquire_file_lock_sharable
|
Chris@16
|
174 (file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time)
|
Chris@16
|
175 {
|
Chris@16
|
176 //Obtain current count and target time
|
Chris@16
|
177 boost::posix_time::ptime now = microsec_clock::universal_time();
|
Chris@16
|
178 using namespace boost::detail;
|
Chris@16
|
179
|
Chris@16
|
180 if(now >= abs_time) return false;
|
Chris@16
|
181
|
Chris@16
|
182 spin_wait swait;
|
Chris@16
|
183 do{
|
Chris@16
|
184 if(!ipcdetail::try_acquire_file_lock_sharable(hnd, acquired))
|
Chris@16
|
185 return false;
|
Chris@16
|
186
|
Chris@16
|
187 if(acquired)
|
Chris@16
|
188 return true;
|
Chris@16
|
189 else{
|
Chris@16
|
190 now = microsec_clock::universal_time();
|
Chris@16
|
191
|
Chris@16
|
192 if(now >= abs_time){
|
Chris@16
|
193 acquired = false;
|
Chris@16
|
194 return true;
|
Chris@16
|
195 }
|
Chris@16
|
196 // relinquish current time slice
|
Chris@16
|
197 swait.yield();
|
Chris@16
|
198 }
|
Chris@16
|
199 }while (true);
|
Chris@16
|
200 }
|
Chris@16
|
201 /// @endcond
|
Chris@16
|
202 };
|
Chris@16
|
203
|
Chris@16
|
204 inline file_lock::file_lock(const char *name)
|
Chris@16
|
205 {
|
Chris@16
|
206 m_file_hnd = ipcdetail::open_existing_file(name, read_write);
|
Chris@16
|
207
|
Chris@16
|
208 if(m_file_hnd == ipcdetail::invalid_file()){
|
Chris@16
|
209 error_info err(system_error_code());
|
Chris@16
|
210 throw interprocess_exception(err);
|
Chris@16
|
211 }
|
Chris@16
|
212 }
|
Chris@16
|
213
|
Chris@16
|
214 inline file_lock::~file_lock()
|
Chris@16
|
215 {
|
Chris@16
|
216 if(m_file_hnd != ipcdetail::invalid_file()){
|
Chris@16
|
217 ipcdetail::close_file(m_file_hnd);
|
Chris@16
|
218 m_file_hnd = ipcdetail::invalid_file();
|
Chris@16
|
219 }
|
Chris@16
|
220 }
|
Chris@16
|
221
|
Chris@16
|
222 inline void file_lock::lock()
|
Chris@16
|
223 {
|
Chris@16
|
224 if(!ipcdetail::acquire_file_lock(m_file_hnd)){
|
Chris@16
|
225 error_info err(system_error_code());
|
Chris@16
|
226 throw interprocess_exception(err);
|
Chris@16
|
227 }
|
Chris@16
|
228 }
|
Chris@16
|
229
|
Chris@16
|
230 inline bool file_lock::try_lock()
|
Chris@16
|
231 {
|
Chris@16
|
232 bool result;
|
Chris@16
|
233 if(!ipcdetail::try_acquire_file_lock(m_file_hnd, result)){
|
Chris@16
|
234 error_info err(system_error_code());
|
Chris@16
|
235 throw interprocess_exception(err);
|
Chris@16
|
236 }
|
Chris@16
|
237 return result;
|
Chris@16
|
238 }
|
Chris@16
|
239
|
Chris@16
|
240 inline bool file_lock::timed_lock(const boost::posix_time::ptime &abs_time)
|
Chris@16
|
241 {
|
Chris@16
|
242 if(abs_time == boost::posix_time::pos_infin){
|
Chris@16
|
243 this->lock();
|
Chris@16
|
244 return true;
|
Chris@16
|
245 }
|
Chris@16
|
246 bool result;
|
Chris@16
|
247 if(!this->timed_acquire_file_lock(m_file_hnd, result, abs_time)){
|
Chris@16
|
248 error_info err(system_error_code());
|
Chris@16
|
249 throw interprocess_exception(err);
|
Chris@16
|
250 }
|
Chris@16
|
251 return result;
|
Chris@16
|
252 }
|
Chris@16
|
253
|
Chris@16
|
254 inline void file_lock::unlock()
|
Chris@16
|
255 {
|
Chris@16
|
256 if(!ipcdetail::release_file_lock(m_file_hnd)){
|
Chris@16
|
257 error_info err(system_error_code());
|
Chris@16
|
258 throw interprocess_exception(err);
|
Chris@16
|
259 }
|
Chris@16
|
260 }
|
Chris@16
|
261
|
Chris@16
|
262 inline void file_lock::lock_sharable()
|
Chris@16
|
263 {
|
Chris@16
|
264 if(!ipcdetail::acquire_file_lock_sharable(m_file_hnd)){
|
Chris@16
|
265 error_info err(system_error_code());
|
Chris@16
|
266 throw interprocess_exception(err);
|
Chris@16
|
267 }
|
Chris@16
|
268 }
|
Chris@16
|
269
|
Chris@16
|
270 inline bool file_lock::try_lock_sharable()
|
Chris@16
|
271 {
|
Chris@16
|
272 bool result;
|
Chris@16
|
273 if(!ipcdetail::try_acquire_file_lock_sharable(m_file_hnd, result)){
|
Chris@16
|
274 error_info err(system_error_code());
|
Chris@16
|
275 throw interprocess_exception(err);
|
Chris@16
|
276 }
|
Chris@16
|
277 return result;
|
Chris@16
|
278 }
|
Chris@16
|
279
|
Chris@16
|
280 inline bool file_lock::timed_lock_sharable(const boost::posix_time::ptime &abs_time)
|
Chris@16
|
281 {
|
Chris@16
|
282 if(abs_time == boost::posix_time::pos_infin){
|
Chris@16
|
283 this->lock_sharable();
|
Chris@16
|
284 return true;
|
Chris@16
|
285 }
|
Chris@16
|
286 bool result;
|
Chris@16
|
287 if(!this->timed_acquire_file_lock_sharable(m_file_hnd, result, abs_time)){
|
Chris@16
|
288 error_info err(system_error_code());
|
Chris@16
|
289 throw interprocess_exception(err);
|
Chris@16
|
290 }
|
Chris@16
|
291 return result;
|
Chris@16
|
292 }
|
Chris@16
|
293
|
Chris@16
|
294 inline void file_lock::unlock_sharable()
|
Chris@16
|
295 {
|
Chris@16
|
296 if(!ipcdetail::release_file_lock_sharable(m_file_hnd)){
|
Chris@16
|
297 error_info err(system_error_code());
|
Chris@16
|
298 throw interprocess_exception(err);
|
Chris@16
|
299 }
|
Chris@16
|
300 }
|
Chris@16
|
301
|
Chris@16
|
302 } //namespace interprocess {
|
Chris@16
|
303 } //namespace boost {
|
Chris@16
|
304
|
Chris@16
|
305 #include <boost/interprocess/detail/config_end.hpp>
|
Chris@16
|
306
|
Chris@16
|
307 #endif //BOOST_INTERPROCESS_FILE_LOCK_HPP
|