librostlab
1.0.20
|
00001 /* 00002 Copyright (C) 2011 Laszlo Kajan, Technical University of Munich, Germany 00003 00004 This file is part of librostlab. 00005 00006 librostlab is free software: you can redistribute it and/or modify 00007 it under the terms of the GNU Lesser General Public License as published by 00008 the Free Software Foundation, either version 3 of the License, or 00009 (at your option) any later version. 00010 00011 This program is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU Lesser General Public License for more details. 00015 00016 You should have received a copy of the GNU Lesser General Public License 00017 along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 */ 00019 #ifndef ROSTLAB_FLOCK_RESOURCE 00020 #define ROSTLAB_FLOCK_RESOURCE 00021 00022 #include <errno.h> 00023 #include <fcntl.h> 00024 #include <iostream> 00025 #include <stdio.h> 00026 #include <string.h> 00027 #include <unistd.h> 00028 00029 #include "rostlab/rostlab_stdexcept.h" 00030 00031 namespace rostlab { 00032 00037 class file_lock_resource 00038 { 00039 private: 00040 std::string _filename; 00041 FILE* _fh; 00042 // this is a resource - disable copy contructor and copy assignment 00043 file_lock_resource( const file_lock_resource& ){}; 00044 file_lock_resource& 00045 operator=(const file_lock_resource&){return *this;}; 00046 public: 00047 bool dbg; 00048 00049 class wouldblock : public exception {}; 00050 00051 public: 00052 file_lock_resource() : _fh(NULL), dbg(false) {}; 00053 00056 file_lock_resource( const std::string& __file, const std::string& __mode = "r", int __cmd = F_SETLKW, short __type = F_RDLCK, bool __dbg = false ) : _fh(NULL), dbg(__dbg) 00057 { 00058 acquire( __file, __mode, __cmd, __type, __dbg ); 00059 } 00060 00061 inline void acquire( const std::string& __file, const std::string& __mode = "r", int __cmd = F_SETLKW, short __type = F_RDLCK, bool __dbg = false ) throw ( runtime_error, wouldblock ) 00062 { 00063 dbg = __dbg; 00064 release(); 00065 // 00066 _filename = __file; 00067 _fh = fopen( _filename.c_str(), __mode.c_str() ); 00068 if( !_fh ) throw runtime_error( strerror( errno ) ); 00069 00070 // instead of flock us fcntl()/POSIX locking so that it works with NFS as well 00071 flock lock; 00072 lock.l_type = __type; 00073 lock.l_whence = SEEK_SET; 00074 lock.l_start = 0; 00075 lock.l_len = 0; 00076 00077 if( fcntl( fileno(_fh), __cmd, &lock ) ) 00078 { 00079 int fcntl_errno = errno; 00080 fclose(_fh); _fh = NULL; 00081 if( fcntl_errno == EACCES || fcntl_errno == EAGAIN ) throw wouldblock(); 00082 else throw runtime_error( strerror( fcntl_errno ) ); 00083 } 00084 else if(dbg) std::cerr << "LOCK_" << __mode << " " << __cmd << " " << __type << " '" << _filename << "'\n"; 00085 } 00086 00087 inline void release() throw (runtime_error) 00088 { 00089 if( _fh ) 00090 { 00091 // lkajan: no need to explicitly release the lock: it is released when the file is closed 00092 if( fclose(_fh) ) throw runtime_error( strerror( errno ) ); 00093 if(dbg) std::cerr << "LOCK_UN '" << _filename << "'\n"; 00094 _fh = NULL; 00095 } 00096 } 00097 00098 virtual ~file_lock_resource() 00099 { 00100 release(); 00101 } 00102 00103 operator FILE* () { return _fh; } 00104 00105 inline const std::string& 00106 filename() const { return _filename; } 00107 }; 00108 00109 }; 00110 00111 #endif // ROSTLAB_FLOCK_RESOURCE 00112 // vim:et:ts=2:ai: