Chris@16
|
1 //////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
2 //
|
Chris@16
|
3 // (C) Copyright Ion Gaztanaga 2009-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_LOCKING_HELPERS_HPP
|
Chris@16
|
12 #define BOOST_INTERPROCESS_FILE_LOCKING_HELPERS_HPP
|
Chris@16
|
13
|
Chris@101
|
14 #ifndef BOOST_CONFIG_HPP
|
Chris@101
|
15 # include <boost/config.hpp>
|
Chris@101
|
16 #endif
|
Chris@101
|
17 #
|
Chris@101
|
18 #if defined(BOOST_HAS_PRAGMA_ONCE)
|
Chris@16
|
19 #pragma once
|
Chris@16
|
20 #endif
|
Chris@16
|
21
|
Chris@16
|
22 #include <boost/interprocess/detail/config_begin.hpp>
|
Chris@16
|
23 #include <boost/interprocess/detail/workaround.hpp>
|
Chris@16
|
24
|
Chris@16
|
25 #include <sstream>
|
Chris@16
|
26 #include <string>
|
Chris@16
|
27 #include <sys/types.h>
|
Chris@16
|
28 #include <sys/stat.h>
|
Chris@16
|
29 #include <errno.h>
|
Chris@16
|
30 #include <cstddef>
|
Chris@16
|
31 #include <boost/interprocess/detail/os_file_functions.hpp>
|
Chris@16
|
32
|
Chris@101
|
33 #include <boost/interprocess/detail/shared_dir_helpers.hpp>
|
Chris@16
|
34
|
Chris@16
|
35 #if defined(BOOST_INTERPROCESS_WINDOWS)
|
Chris@16
|
36
|
Chris@16
|
37 #include <fcntl.h>
|
Chris@16
|
38 #include <io.h>
|
Chris@16
|
39 #include <sys/locking.h>
|
Chris@16
|
40
|
Chris@16
|
41 #else //defined(BOOST_INTERPROCESS_WINDOWS)
|
Chris@16
|
42
|
Chris@16
|
43 #include <fcntl.h>
|
Chris@16
|
44 #include <sys/stat.h>
|
Chris@16
|
45 #include <unistd.h>
|
Chris@16
|
46
|
Chris@16
|
47 #endif //defined(BOOST_INTERPROCESS_WINDOWS)
|
Chris@16
|
48
|
Chris@16
|
49 namespace boost{
|
Chris@16
|
50 namespace interprocess{
|
Chris@16
|
51 namespace ipcdetail{
|
Chris@16
|
52
|
Chris@16
|
53 #if defined(BOOST_INTERPROCESS_WINDOWS)
|
Chris@16
|
54
|
Chris@16
|
55 struct locking_file_serial_id
|
Chris@16
|
56 {
|
Chris@16
|
57 int fd;
|
Chris@16
|
58 unsigned long dwVolumeSerialNumber;
|
Chris@16
|
59 unsigned long nFileIndexHigh;
|
Chris@16
|
60 unsigned long nFileIndexLow;
|
Chris@16
|
61 //This reference count counts the number of modules attached
|
Chris@16
|
62 //to the shared memory and lock file. This serves to unlink
|
Chris@16
|
63 //the locking file and shared memory when all modules are
|
Chris@16
|
64 //done with the global memory (shared memory)
|
Chris@16
|
65 volatile boost::uint32_t modules_attached_to_gmem_count;
|
Chris@16
|
66 };
|
Chris@16
|
67
|
Chris@16
|
68 inline bool lock_locking_file(int fd)
|
Chris@16
|
69 {
|
Chris@16
|
70 int ret = 0;
|
Chris@16
|
71 while(ret != 0 && errno == EDEADLK){
|
Chris@16
|
72 ret = _locking(fd, _LK_LOCK, 1/*lock_file_contents_length()*/);
|
Chris@16
|
73 }
|
Chris@16
|
74 return 0 == ret;
|
Chris@16
|
75 }
|
Chris@16
|
76
|
Chris@16
|
77 inline bool try_lock_locking_file(int fd)
|
Chris@16
|
78 {
|
Chris@16
|
79 return 0 == _locking(fd, _LK_NBLCK , 1);
|
Chris@16
|
80 }
|
Chris@16
|
81
|
Chris@16
|
82 inline int open_or_create_and_lock_file(const char *name)
|
Chris@16
|
83 {
|
Chris@16
|
84 permissions p;
|
Chris@16
|
85 p.set_unrestricted();
|
Chris@16
|
86 while(1){
|
Chris@16
|
87 file_handle_t handle = create_or_open_file(name, read_write, p);
|
Chris@16
|
88 int fd = _open_osfhandle((intptr_t)handle, _O_TEXT);
|
Chris@16
|
89 if(fd < 0){
|
Chris@16
|
90 close_file(handle);
|
Chris@16
|
91 return fd;
|
Chris@16
|
92 }
|
Chris@16
|
93 if(!try_lock_locking_file(fd)){
|
Chris@16
|
94 _close(fd);
|
Chris@16
|
95 return -1;
|
Chris@16
|
96 }
|
Chris@16
|
97 struct _stat s;
|
Chris@16
|
98 if(0 == _stat(name, &s)){
|
Chris@16
|
99 return fd;
|
Chris@16
|
100 }
|
Chris@16
|
101 else{
|
Chris@16
|
102 _close(fd);
|
Chris@16
|
103 }
|
Chris@16
|
104 }
|
Chris@16
|
105 }
|
Chris@16
|
106
|
Chris@16
|
107 inline int try_open_and_lock_file(const char *name)
|
Chris@16
|
108 {
|
Chris@16
|
109 file_handle_t handle = open_existing_file(name, read_write);
|
Chris@16
|
110 int fd = _open_osfhandle((intptr_t)handle, _O_TEXT);
|
Chris@16
|
111 if(fd < 0){
|
Chris@16
|
112 close_file(handle);
|
Chris@16
|
113 return fd;
|
Chris@16
|
114 }
|
Chris@16
|
115 if(!try_lock_locking_file(fd)){
|
Chris@16
|
116 _close(fd);
|
Chris@16
|
117 return -1;
|
Chris@16
|
118 }
|
Chris@16
|
119 return fd;
|
Chris@16
|
120 }
|
Chris@16
|
121
|
Chris@16
|
122 inline void close_lock_file(int fd)
|
Chris@16
|
123 { _close(fd); }
|
Chris@16
|
124
|
Chris@16
|
125 inline bool is_valid_fd(int fd)
|
Chris@16
|
126 {
|
Chris@16
|
127 struct _stat s;
|
Chris@16
|
128 return EBADF != _fstat(fd, &s);
|
Chris@16
|
129 }
|
Chris@16
|
130
|
Chris@16
|
131 inline bool is_normal_file(int fd)
|
Chris@16
|
132 {
|
Chris@16
|
133 if(_isatty(fd))
|
Chris@16
|
134 return false;
|
Chris@16
|
135 struct _stat s;
|
Chris@16
|
136 if(0 != _fstat(fd, &s))
|
Chris@16
|
137 return false;
|
Chris@16
|
138 return 0 != (s.st_mode & _S_IFREG);
|
Chris@16
|
139 }
|
Chris@16
|
140
|
Chris@16
|
141 inline std::size_t get_size(int fd)
|
Chris@16
|
142 {
|
Chris@16
|
143 struct _stat s;
|
Chris@16
|
144 if(0 != _fstat(fd, &s))
|
Chris@16
|
145 return 0u;
|
Chris@16
|
146 return (std::size_t)s.st_size;
|
Chris@16
|
147 }
|
Chris@16
|
148
|
Chris@16
|
149 inline bool fill_file_serial_id(int fd, locking_file_serial_id &id)
|
Chris@16
|
150 {
|
Chris@16
|
151 winapi::interprocess_by_handle_file_information info;
|
Chris@16
|
152 if(!winapi::get_file_information_by_handle((void*)_get_osfhandle(fd), &info))
|
Chris@16
|
153 return false;
|
Chris@16
|
154 id.fd = fd;
|
Chris@16
|
155 id.dwVolumeSerialNumber = info.dwVolumeSerialNumber;
|
Chris@16
|
156 id.nFileIndexHigh = info.nFileIndexHigh;
|
Chris@16
|
157 id.nFileIndexLow = info.nFileIndexLow;
|
Chris@16
|
158 id.modules_attached_to_gmem_count = 1; //Initialize attached count
|
Chris@16
|
159 return true;
|
Chris@16
|
160 }
|
Chris@16
|
161
|
Chris@16
|
162 inline bool compare_file_serial(int fd, const locking_file_serial_id &id)
|
Chris@16
|
163 {
|
Chris@16
|
164 winapi::interprocess_by_handle_file_information info;
|
Chris@16
|
165 if(!winapi::get_file_information_by_handle((void*)_get_osfhandle(fd), &info))
|
Chris@16
|
166 return false;
|
Chris@16
|
167
|
Chris@16
|
168 return id.dwVolumeSerialNumber == info.dwVolumeSerialNumber &&
|
Chris@16
|
169 id.nFileIndexHigh == info.nFileIndexHigh &&
|
Chris@16
|
170 id.nFileIndexLow == info.nFileIndexLow;
|
Chris@16
|
171 }
|
Chris@16
|
172
|
Chris@16
|
173 #else //UNIX
|
Chris@16
|
174
|
Chris@16
|
175 struct locking_file_serial_id
|
Chris@16
|
176 {
|
Chris@16
|
177 int fd;
|
Chris@16
|
178 dev_t st_dev;
|
Chris@16
|
179 ino_t st_ino;
|
Chris@16
|
180 //This reference count counts the number of modules attached
|
Chris@16
|
181 //to the shared memory and lock file. This serves to unlink
|
Chris@16
|
182 //the locking file and shared memory when all modules are
|
Chris@16
|
183 //done with the global memory (shared memory)
|
Chris@16
|
184 volatile boost::uint32_t modules_attached_to_gmem_count;
|
Chris@16
|
185 };
|
Chris@16
|
186
|
Chris@16
|
187 inline bool lock_locking_file(int fd)
|
Chris@16
|
188 {
|
Chris@16
|
189 int ret = 0;
|
Chris@16
|
190 while(ret != 0 && errno != EINTR){
|
Chris@16
|
191 struct flock lock;
|
Chris@16
|
192 lock.l_type = F_WRLCK;
|
Chris@16
|
193 lock.l_whence = SEEK_SET;
|
Chris@16
|
194 lock.l_start = 0;
|
Chris@16
|
195 lock.l_len = 1;
|
Chris@16
|
196 ret = fcntl (fd, F_SETLKW, &lock);
|
Chris@16
|
197 }
|
Chris@16
|
198 return 0 == ret;
|
Chris@16
|
199 }
|
Chris@16
|
200
|
Chris@16
|
201 inline bool try_lock_locking_file(int fd)
|
Chris@16
|
202 {
|
Chris@16
|
203 struct flock lock;
|
Chris@16
|
204 lock.l_type = F_WRLCK;
|
Chris@16
|
205 lock.l_whence = SEEK_SET;
|
Chris@16
|
206 lock.l_start = 0;
|
Chris@16
|
207 lock.l_len = 1;
|
Chris@16
|
208 return 0 == fcntl (fd, F_SETLK, &lock);
|
Chris@16
|
209 }
|
Chris@16
|
210
|
Chris@16
|
211 inline int open_or_create_and_lock_file(const char *name)
|
Chris@16
|
212 {
|
Chris@16
|
213 permissions p;
|
Chris@16
|
214 p.set_unrestricted();
|
Chris@16
|
215 while(1){
|
Chris@16
|
216 int fd = create_or_open_file(name, read_write, p);
|
Chris@16
|
217 if(fd < 0){
|
Chris@16
|
218 return fd;
|
Chris@16
|
219 }
|
Chris@16
|
220 if(!try_lock_locking_file(fd)){
|
Chris@16
|
221 close(fd);
|
Chris@16
|
222 return -1;
|
Chris@16
|
223 }
|
Chris@16
|
224 struct stat s;
|
Chris@16
|
225 if(0 == stat(name, &s)){
|
Chris@16
|
226 return fd;
|
Chris@16
|
227 }
|
Chris@16
|
228 else{
|
Chris@16
|
229 close(fd);
|
Chris@16
|
230 }
|
Chris@16
|
231 }
|
Chris@16
|
232 }
|
Chris@16
|
233
|
Chris@16
|
234 inline int try_open_and_lock_file(const char *name)
|
Chris@16
|
235 {
|
Chris@16
|
236 int fd = open_existing_file(name, read_write);
|
Chris@16
|
237 if(fd < 0){
|
Chris@16
|
238 return fd;
|
Chris@16
|
239 }
|
Chris@16
|
240 if(!try_lock_locking_file(fd)){
|
Chris@16
|
241 close(fd);
|
Chris@16
|
242 return -1;
|
Chris@16
|
243 }
|
Chris@16
|
244 return fd;
|
Chris@16
|
245 }
|
Chris@16
|
246
|
Chris@16
|
247 inline void close_lock_file(int fd)
|
Chris@16
|
248 { close(fd); }
|
Chris@16
|
249
|
Chris@16
|
250 inline bool is_valid_fd(int fd)
|
Chris@16
|
251 {
|
Chris@16
|
252 struct stat s;
|
Chris@16
|
253 return EBADF != fstat(fd, &s);
|
Chris@16
|
254 }
|
Chris@16
|
255
|
Chris@16
|
256 inline bool is_normal_file(int fd)
|
Chris@16
|
257 {
|
Chris@16
|
258 struct stat s;
|
Chris@16
|
259 if(0 != fstat(fd, &s))
|
Chris@16
|
260 return false;
|
Chris@16
|
261 return 0 != (s.st_mode & S_IFREG);
|
Chris@16
|
262 }
|
Chris@16
|
263
|
Chris@16
|
264 inline std::size_t get_size(int fd)
|
Chris@16
|
265 {
|
Chris@16
|
266 struct stat s;
|
Chris@16
|
267 if(0 != fstat(fd, &s))
|
Chris@16
|
268 return 0u;
|
Chris@16
|
269 return (std::size_t)s.st_size;
|
Chris@16
|
270 }
|
Chris@16
|
271
|
Chris@16
|
272 inline bool fill_file_serial_id(int fd, locking_file_serial_id &id)
|
Chris@16
|
273 {
|
Chris@16
|
274 struct stat s;
|
Chris@16
|
275 if(0 != fstat(fd, &s))
|
Chris@16
|
276 return false;
|
Chris@16
|
277 id.fd = fd;
|
Chris@16
|
278 id.st_dev = s.st_dev;
|
Chris@16
|
279 id.st_ino = s.st_ino;
|
Chris@16
|
280 id.modules_attached_to_gmem_count = 1; //Initialize attached count
|
Chris@16
|
281 return true;
|
Chris@16
|
282 }
|
Chris@16
|
283
|
Chris@16
|
284 inline bool compare_file_serial(int fd, const locking_file_serial_id &id)
|
Chris@16
|
285 {
|
Chris@16
|
286 struct stat info;
|
Chris@16
|
287 if(0 != fstat(fd, &info))
|
Chris@16
|
288 return false;
|
Chris@16
|
289
|
Chris@16
|
290 return id.st_dev == info.st_dev &&
|
Chris@16
|
291 id.st_ino == info.st_ino;
|
Chris@16
|
292 }
|
Chris@16
|
293
|
Chris@101
|
294 #endif
|
Chris@16
|
295
|
Chris@16
|
296 } //namespace ipcdetail{
|
Chris@16
|
297 } //namespace interprocess{
|
Chris@16
|
298 } //namespace boost{
|
Chris@16
|
299
|
Chris@16
|
300 #include <boost/interprocess/detail/config_end.hpp>
|
Chris@16
|
301
|
Chris@16
|
302 #endif //BOOST_INTERPROCESS_FILE_LOCKING_HELPERS_HPP
|