////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// #ifndef BOOST_INTERPROCESS_FILE_LOCKING_HELPERS_HPP #define BOOST_INTERPROCESS_FILE_LOCKING_HELPERS_HPP #ifndef BOOST_CONFIG_HPP # include #endif # #if defined(BOOST_HAS_PRAGMA_ONCE) #pragma once #endif #include #include #include #include #include #include #include #include #include #include #if defined(BOOST_INTERPROCESS_WINDOWS) #include #include #include #else //defined(BOOST_INTERPROCESS_WINDOWS) #include #include #include #endif //defined(BOOST_INTERPROCESS_WINDOWS) namespace boost{ namespace interprocess{ namespace ipcdetail{ #if defined(BOOST_INTERPROCESS_WINDOWS) struct locking_file_serial_id { int fd; unsigned long dwVolumeSerialNumber; unsigned long nFileIndexHigh; unsigned long nFileIndexLow; //This reference count counts the number of modules attached //to the shared memory and lock file. This serves to unlink //the locking file and shared memory when all modules are //done with the global memory (shared memory) volatile boost::uint32_t modules_attached_to_gmem_count; }; inline bool lock_locking_file(int fd) { int ret = 0; while(ret != 0 && errno == EDEADLK){ ret = _locking(fd, _LK_LOCK, 1/*lock_file_contents_length()*/); } return 0 == ret; } inline bool try_lock_locking_file(int fd) { return 0 == _locking(fd, _LK_NBLCK , 1); } inline int open_or_create_and_lock_file(const char *name) { permissions p; p.set_unrestricted(); while(1){ file_handle_t handle = create_or_open_file(name, read_write, p); int fd = _open_osfhandle((intptr_t)handle, _O_TEXT); if(fd < 0){ close_file(handle); return fd; } if(!try_lock_locking_file(fd)){ _close(fd); return -1; } struct _stat s; if(0 == _stat(name, &s)){ return fd; } else{ _close(fd); } } } inline int try_open_and_lock_file(const char *name) { file_handle_t handle = open_existing_file(name, read_write); int fd = _open_osfhandle((intptr_t)handle, _O_TEXT); if(fd < 0){ close_file(handle); return fd; } if(!try_lock_locking_file(fd)){ _close(fd); return -1; } return fd; } inline void close_lock_file(int fd) { _close(fd); } inline bool is_valid_fd(int fd) { struct _stat s; return EBADF != _fstat(fd, &s); } inline bool is_normal_file(int fd) { if(_isatty(fd)) return false; struct _stat s; if(0 != _fstat(fd, &s)) return false; return 0 != (s.st_mode & _S_IFREG); } inline std::size_t get_size(int fd) { struct _stat s; if(0 != _fstat(fd, &s)) return 0u; return (std::size_t)s.st_size; } inline bool fill_file_serial_id(int fd, locking_file_serial_id &id) { winapi::interprocess_by_handle_file_information info; if(!winapi::get_file_information_by_handle((void*)_get_osfhandle(fd), &info)) return false; id.fd = fd; id.dwVolumeSerialNumber = info.dwVolumeSerialNumber; id.nFileIndexHigh = info.nFileIndexHigh; id.nFileIndexLow = info.nFileIndexLow; id.modules_attached_to_gmem_count = 1; //Initialize attached count return true; } inline bool compare_file_serial(int fd, const locking_file_serial_id &id) { winapi::interprocess_by_handle_file_information info; if(!winapi::get_file_information_by_handle((void*)_get_osfhandle(fd), &info)) return false; return id.dwVolumeSerialNumber == info.dwVolumeSerialNumber && id.nFileIndexHigh == info.nFileIndexHigh && id.nFileIndexLow == info.nFileIndexLow; } #else //UNIX struct locking_file_serial_id { int fd; dev_t st_dev; ino_t st_ino; //This reference count counts the number of modules attached //to the shared memory and lock file. This serves to unlink //the locking file and shared memory when all modules are //done with the global memory (shared memory) volatile boost::uint32_t modules_attached_to_gmem_count; }; inline bool lock_locking_file(int fd) { int ret = 0; while(ret != 0 && errno != EINTR){ struct flock lock; lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 1; ret = fcntl (fd, F_SETLKW, &lock); } return 0 == ret; } inline bool try_lock_locking_file(int fd) { struct flock lock; lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 1; return 0 == fcntl (fd, F_SETLK, &lock); } inline int open_or_create_and_lock_file(const char *name) { permissions p; p.set_unrestricted(); while(1){ int fd = create_or_open_file(name, read_write, p); if(fd < 0){ return fd; } if(!try_lock_locking_file(fd)){ close(fd); return -1; } struct stat s; if(0 == stat(name, &s)){ return fd; } else{ close(fd); } } } inline int try_open_and_lock_file(const char *name) { int fd = open_existing_file(name, read_write); if(fd < 0){ return fd; } if(!try_lock_locking_file(fd)){ close(fd); return -1; } return fd; } inline void close_lock_file(int fd) { close(fd); } inline bool is_valid_fd(int fd) { struct stat s; return EBADF != fstat(fd, &s); } inline bool is_normal_file(int fd) { struct stat s; if(0 != fstat(fd, &s)) return false; return 0 != (s.st_mode & S_IFREG); } inline std::size_t get_size(int fd) { struct stat s; if(0 != fstat(fd, &s)) return 0u; return (std::size_t)s.st_size; } inline bool fill_file_serial_id(int fd, locking_file_serial_id &id) { struct stat s; if(0 != fstat(fd, &s)) return false; id.fd = fd; id.st_dev = s.st_dev; id.st_ino = s.st_ino; id.modules_attached_to_gmem_count = 1; //Initialize attached count return true; } inline bool compare_file_serial(int fd, const locking_file_serial_id &id) { struct stat info; if(0 != fstat(fd, &info)) return false; return id.st_dev == info.st_dev && id.st_ino == info.st_ino; } #endif } //namespace ipcdetail{ } //namespace interprocess{ } //namespace boost{ #include #endif //BOOST_INTERPROCESS_FILE_LOCKING_HELPERS_HPP