303 lines
6.9 KiB
C++
303 lines
6.9 KiB
C++
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// (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 <boost/config.hpp>
|
|
#endif
|
|
#
|
|
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
|
#pragma once
|
|
#endif
|
|
|
|
#include <boost/interprocess/detail/config_begin.hpp>
|
|
#include <boost/interprocess/detail/workaround.hpp>
|
|
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
#include <cstddef>
|
|
#include <boost/interprocess/detail/os_file_functions.hpp>
|
|
|
|
#include <boost/interprocess/detail/shared_dir_helpers.hpp>
|
|
|
|
#if defined(BOOST_INTERPROCESS_WINDOWS)
|
|
|
|
#include <fcntl.h>
|
|
#include <io.h>
|
|
#include <sys/locking.h>
|
|
|
|
#else //defined(BOOST_INTERPROCESS_WINDOWS)
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#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 <boost/interprocess/detail/config_end.hpp>
|
|
|
|
#endif //BOOST_INTERPROCESS_FILE_LOCKING_HELPERS_HPP
|