00001 // Copyright (C) 2002 Petter Urkedal (petter.urkedal@matfys.lth.se) 00002 // 00003 // This file is free software; you can redistribute it and/or modify 00004 // it under the terms of the GNU General Public License as published by 00005 // the Free Software Foundation; either version 2 of the License, or 00006 // (at your option) any later version. 00007 // 00008 // This file is distributed in the hope that it will be useful, 00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 // GNU General Public License for more details. 00012 // 00013 // You should have received a copy of the GNU General Public License 00014 // along with this program; if not, write to the Free Software 00015 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00016 // 00017 // As a special exception, you may use this file as part of a free 00018 // software library without restriction. Specifically, if other files 00019 // instantiate templates or use macros or inline functions from this 00020 // file, or you compile this file and link it with other files to 00021 // produce an executable, this file does not by itself cause the 00022 // resulting executable to be covered by the GNU General Public 00023 // License. This exception does not however invalidate any other 00024 // reasons why the executable file might be covered by the GNU General 00025 // Public License. 00026 // 00027 // $Id: lock_file.h,v 1.1 2002/05/30 18:01:37 petter_urkedal Exp $ 00028 00029 00030 #ifndef MORE_IO_LOCK_FILE_H 00031 #define MORE_IO_LOCK_FILE_H 00032 00033 #include <more/gen/utility.h> 00034 00035 00036 namespace more { 00037 namespace io { 00038 00039 enum access_t 00040 { 00041 access_none = 0, 00042 access_x = 1, 00043 access_w = 2, 00044 access_wx = 3, 00045 access_r = 4, 00046 access_rx = 5, 00047 access_rw = 6, 00048 access_rwx = 7 00049 }; 00050 inline access_t operator~(access_t acc) { return access_t(~int(acc)); } 00051 inline access_t operator&(access_t x, access_t y) 00052 { 00053 return access_t(int(x) & int(y)); 00054 } 00055 inline access_t operator|(access_t x, access_t y) 00056 { 00057 return access_t(int(x) | int(y)); 00058 } 00059 inline access_t& operator&=(access_t& x, access_t y) { return x = x & y; } 00060 inline access_t& operator|=(access_t& x, access_t y) { return x = x | y; } 00061 00062 extern struct infinite_tag {} const infinite; 00063 00064 /** A handle to a lock file. Read-only locks are not NFS safe 00065 ** (TODO). A workaround is to use \c access_rw also when only read 00066 ** access is needed. */ 00067 struct lock_file : gen::noncopyable 00068 { 00069 /** Construct an undefined lock file handle. */ 00070 lock_file() 00071 : m_access(access_none) {} 00072 00073 /** Construct a handle for a named lock file, but do not create 00074 ** the file yet. */ 00075 explicit lock_file(std::string path) 00076 : m_path(path), 00077 m_access(access_none) {} 00078 00079 // /** Partially copy \a lf. The path and access are copied, but 00080 // ** not the lock status. 00081 // ** \post <tt>this.have_lock() == false</tt> */ 00082 // lock_file(lock_file const& lf) 00083 // : m_path(lf.m_path), 00084 // m_access(access_none) {} 00085 00086 /** Calls unlock(). */ 00087 ~lock_file() { release(); } 00088 00089 /** Set or change the file name of the lock. This causes an 00090 ** unlock. */ 00091 void set_file_name(std::string); 00092 00093 /** Return the current access of the lock. */ 00094 access_t access() const { return m_access; } 00095 00096 /** Try to obtain the lock without blocking, and return true if 00097 ** successful. The valid arguments for \a access are \c 00098 ** access_none, which causes an unlock, \c access_r which gives 00099 ** read access, and \c access_rw which gives read write access. 00100 ** In addition \c access_w will be changed to \c access_rw. */ 00101 bool adjust(access_t access); 00102 00103 /** Return \c adjust(acc | access()). */ 00104 bool aquire(access_t acc) { return adjust(acc | access()); } 00105 00106 /** Attempt every \a dt seconds for \a t seconds to \c 00107 ** aquire(access). Return true if the lock was obtained. See 00108 ** <tt>adjust(access_t)</tt> for constraint on \a access. */ 00109 bool aquire(access_t access, double t, double dt = 1.0); 00110 00111 /** Attempt every \a dt seconds indefinitely to \c 00112 ** aquire(access). See <tt>adjust(access_t)</tt> for 00113 ** constraint on \a access. */ 00114 bool aquire(access_t access, infinite_tag, double dt = 1.0); 00115 00116 /** Release all access. This function should ideally neither 00117 ** hang nor fail. In the case of read-only locks, however, it 00118 ** may in exceptional cases hang for a few seconds, and 00119 ** possibly fail. This may be the case if another program was 00120 ** interrupted at the critical stage while adjusting its own 00121 ** read-only lock, or if the lock files were tampered with. */ 00122 void release(access_t access = access_rw); 00123 00124 /** Swap two locks. */ 00125 void swap(lock_file& lk) 00126 { 00127 std::swap(m_path, lk.m_path); 00128 std::swap(m_access, lk.m_access); 00129 } 00130 00131 /** \depreciated Same ass release(). */ 00132 void unlock() { release(); } 00133 00134 /** \depreciated Use another constructor. 00135 ** Construct a handle and create the lock file with the given 00136 ** name if possible. If blocking=true it will hang until it 00137 ** manages to create the lock. */ 00138 lock_file(std::string path, bool blocking) 00139 : m_access(access_rw) 00140 { 00141 lock(path, blocking); 00142 } 00143 /** \depreciated Use \c access(). 00144 ** Returns true after successful locking and before 00145 ** unlock(). */ 00146 bool have_lock() const { return m_access == access_rw; } 00147 00148 /** \depreciated 00149 ** Establish the lock with the given file name. */ 00150 void lock(std::string path, bool blocking); 00151 00152 private: 00153 std::string m_path; 00154 access_t m_access; 00155 int* m_cnt; 00156 }; 00157 00158 struct lock_file_restorer 00159 { 00160 explicit lock_file_restorer(lock_file& lk) 00161 : m_lk(lk), m_acc(lk.access()) {} 00162 00163 ~lock_file_restorer() { m_lk.adjust(m_acc); } 00164 00165 private: 00166 lock_file& m_lk; 00167 access_t m_acc; 00168 }; 00169 00170 }} 00171 00172 #endif