Author: dmacvicar
Date: Thu Mar 20 18:49:50 2008
New Revision: 9244
URL: http://svn.opensuse.org/viewcvs/zypp?rev=9244&view=rev
Log:
backup prototype of granular locking. Dont look at it yet
Added:
trunk/libzypp/tests/zypp/base/InterProcessMutex2_test.cc
trunk/libzypp/tests/zypp/base/InterProcessMutex_test.cc
trunk/libzypp/zypp/base/InterProcessMutex.cc
trunk/libzypp/zypp/base/InterProcessMutex.h
Modified:
trunk/libzypp/tests/zypp/base/CMakeLists.txt
trunk/libzypp/zypp/CMakeLists.txt
Modified: trunk/libzypp/tests/zypp/base/CMakeLists.txt
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/tests/zypp/base/CMakeLists.txt?rev=9244&r1=9243&r2=9244&view=diff
==============================================================================
--- trunk/libzypp/tests/zypp/base/CMakeLists.txt (original)
+++ trunk/libzypp/tests/zypp/base/CMakeLists.txt Thu Mar 20 18:49:50 2008
@@ -1,2 +1,2 @@
-ADD_TESTS(Sysconfig)
\ No newline at end of file
+ADD_TESTS(Sysconfig InterProcessMutex InterProcessMutex2)
Added: trunk/libzypp/tests/zypp/base/InterProcessMutex2_test.cc
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/tests/zypp/base/InterProcessMutex2_test.cc?rev=9244&view=auto
==============================================================================
--- trunk/libzypp/tests/zypp/base/InterProcessMutex2_test.cc (added)
+++ trunk/libzypp/tests/zypp/base/InterProcessMutex2_test.cc Thu Mar 20 18:49:50 2008
@@ -0,0 +1,68 @@
+
+#include
+
+#include <iostream>
+#include <fstream>
+#include <map>
+#include <string>
+#include <cstdio>
+
+#include
+
+#include "zypp/base/Logger.h"
+#include "zypp/base/Exception.h"
+#include "zypp/TmpPath.h"
+#include "zypp/PathInfo.h"
+
+#include "zypp/base/Sysconfig.h"
+#include "zypp/base/InterProcessMutex.h"
+
+
+using boost::unit_test::test_suite;
+using boost::unit_test::test_case;
+using namespace boost::unit_test;
+
+using namespace std;
+using namespace zypp;
+using namespace zypp::base;
+
+
+BOOST_AUTO_TEST_CASE(Abort)
+{
+ int r = 0;
+ int status = 0;
+ {
+ MIL << "ready to fork" << endl;
+
+ r = fork();
+
+ if ( r < 0 )
+ {
+ BOOST_ERROR("Can't fork process");
+ return;
+ }
+ else if ( r == 0 )
+ {
+ MIL << "child, PID: " << getpid() << endl;
+ // child
+ sleep(3);
+ BOOST_REQUIRE_THROW( InterProcessMutex("testcase", 0), ZYppLockedException);
+ //InterProcessMutex mutex2("testcase");
+ }
+ else
+ {
+ MIL << "parent: " << getpid() << endl;
+ InterProcessMutex mutex("testcase");
+ // parent
+ sleep(6);
+ waitpid(r, &status, 0);
+ MIL << "first lock will go out of scope" << endl;
+
+ }
+ }
+ //if ( r > 0 )
+
+}
+
+
+
Added: trunk/libzypp/tests/zypp/base/InterProcessMutex_test.cc
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/tests/zypp/base/InterProcessMutex_test.cc?rev=9244&view=auto
==============================================================================
--- trunk/libzypp/tests/zypp/base/InterProcessMutex_test.cc (added)
+++ trunk/libzypp/tests/zypp/base/InterProcessMutex_test.cc Thu Mar 20 18:49:50 2008
@@ -0,0 +1,70 @@
+
+#include
+
+#include <iostream>
+#include <fstream>
+#include <map>
+#include <string>
+#include <cstdio>
+
+#include
+
+#include "zypp/base/Logger.h"
+#include "zypp/base/Exception.h"
+#include "zypp/TmpPath.h"
+#include "zypp/PathInfo.h"
+
+#include "zypp/base/Sysconfig.h"
+#include "zypp/base/InterProcessMutex.h"
+
+
+using boost::unit_test::test_suite;
+using boost::unit_test::test_case;
+using namespace boost::unit_test;
+
+using namespace std;
+using namespace zypp;
+using namespace zypp::base;
+
+#define DATADIR (Pathname(TESTS_SRC_DIR) + "/zypp/base/data/Sysconfig")
+
+BOOST_AUTO_TEST_CASE(WaitForTheOther)
+{
+ int r = 0;
+ int status = 0;
+ {
+ MIL << "ready to fork" << endl;
+
+ r = fork();
+
+ if ( r < 0 )
+ {
+ BOOST_ERROR("Can't fork process");
+ return;
+ }
+ else if ( r == 0 )
+ {
+ MIL << "child, PID: " << getpid() << endl;
+ // child
+ //BOOST_REQUIRE_THROW( InterProcessMutex("testcase"), ZYppLockedException);
+ sleep(3);
+ InterProcessMutex mutex2("testcase");
+ }
+ else
+ {
+ MIL << "parent: " << getpid() << endl;
+ InterProcessMutex mutex("testcase");
+ // parent
+ sleep(3);
+
+ MIL << "first lock will go out of scope" << endl;
+
+ }
+ }
+ //if ( r > 0 )
+ // waitpid(r, &status, 0);
+}
+
+
+
+
Modified: trunk/libzypp/zypp/CMakeLists.txt
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/zypp/CMakeLists.txt?rev=9244&r1=9243&r2=9244&view=diff
==============================================================================
--- trunk/libzypp/zypp/CMakeLists.txt (original)
+++ trunk/libzypp/zypp/CMakeLists.txt Thu Mar 20 18:49:50 2008
@@ -182,6 +182,7 @@
INSTALL( FILES ${zypp_HEADERS} DESTINATION "${CMAKE_INSTALL_PREFIX}/include/zypp" )
SET( zypp_base_SRCS
+ base/InterProcessMutex.cc
base/SerialNumber.cc
base/Random.cc
base/Measure.cc
@@ -203,6 +204,7 @@
)
SET( zypp_base_HEADERS
+ base/InterProcessMutex.h
base/Collector.h
base/SerialNumber.h
base/Easy.h
Added: trunk/libzypp/zypp/base/InterProcessMutex.cc
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/zypp/base/InterProcessMutex.cc?rev=9244&view=auto
==============================================================================
--- trunk/libzypp/zypp/base/InterProcessMutex.cc (added)
+++ trunk/libzypp/zypp/base/InterProcessMutex.cc Thu Mar 20 18:49:50 2008
@@ -0,0 +1,302 @@
+
+extern "C"
+{
+#include
+}
+#include <iostream>
+#include <fstream>
+
+#include "zypp/base/Logger.h"
+#include "zypp/base/Gettext.h"
+#include "zypp/base/IOStream.h"
+#include "zypp/base/InterProcessMutex.h"
+#include "zypp/base/String.h"
+
+#include "zypp/Pathname.h"
+#include "zypp/PathInfo.h"
+
+#define ZYPP_LOCK_FILE "/var/run/zypp.pid"
+#define LMIL MIL << "LOCK [" << _name << "] "
+
+using namespace std;
+
+namespace zypp
+{
+namespace base
+{
+
+ ZYppLockedException::ZYppLockedException( const std::string & msg_r,
+ const std::string &name,
+ pid_t locker_pid )
+ : Exception(msg_r)
+ , _locker_pid (locker_pid)
+ , _name(name)
+{}
+
+ZYppLockedException::~ZYppLockedException() throw()
+{}
+
+
+InterProcessMutex::InterProcessMutex( const std::string &name,
+ int timeout )
+ : _clean_lock(false)
+ , _zypp_lockfile(0)
+ , _locker_pid(0)
+ , _name(name)
+ , _timeout(timeout)
+{
+
+ // get the current pid
+ pid_t curr_pid = getpid();
+ Pathname lock_file = lockFilePath();
+ int totalslept = 0;
+
+ while (1)
+ {
+ if ( PathInfo(lock_file).isExist() )
+ {
+ LMIL << "found lockfile " << lock_file << std::endl;
+ openLockFile("r");
+ shLockFile();
+
+ pid_t locker_pid = lockerPid();
+ pid_t curr_pid = getpid();
+ LMIL << "Locker pid is " << locker_pid << " (our pid: " << curr_pid << ") "<< std::endl;
+ _locker_pid = locker_pid;
+ // if the same pid has the lock it means we are trying from a new
+ // thread and we have to wait.
+ // if it is a different one and it is running, then we have to wait
+ // too, otherwise we can just take ownership of the lock
+ bool locker_running = isProcessRunning(locker_pid);
+ LMIL << "locker program is " << (locker_running ? "" : " not") << " running." << endl;
+
+ // if the locker process runs and we are not root
+ // we can give access without risk.
+ if ( locker_running && ( geteuid() != 0 ) )
+ {
+ LMIL << locker_pid << " is running and has a lock. Access as normal user allowed." << std::endl;
+ break;
+ }
+ // if the locker process is not running we have different cases
+ // if we are root, we can clean its lock file, and take ownership of
+ // it, which may work or not depending on result of unlink.
+ // if the process is not running, and we are not root, we are not able to
+ // do much, so we are allowed to continue.
+ else if ( ! locker_running )
+ {
+ if ( geteuid() == 0 )
+ {
+ LMIL << locker_pid
+ <<" has a lock, but process is not running. Cleaning lock file."
+ << std::endl;
+
+ if ( filesystem::unlink(lock_file) == 0 )
+ {
+ createLockFile();
+ // now open it for reading
+ openLockFile("r");
+ shLockFile();
+ break;
+ }
+ else
+ {
+ ERR << "can't clean lockfile. Sorry, can't create a new lock. Lock ["
+ << _name << "] still locked."
+ << std::endl;
+ ZYPP_THROW(ZYppLockedException(
+ _("Can't clean lockfile. Sorry, can't create a new lock. Zypp still locked."),
+ _name, locker_pid));
+ }
+ }
+ else
+ {
+ LMIL << locker_pid
+ << " not running and has a lock. Access as normal user allowed."
+ << std::endl;
+ break;
+ }
+ }
+ // if the locker process is running and we are root, we have to wait
+ // or go away
+ else /* if ( locker_running && ( geteuid() == 0 ) ) */
+ {
+ LMIL << locker_pid << " is running and has a lock." << std::endl;
+
+ // abort if we have slept more or equal than the timeout, but
+ // not for the case where timeout is negative which means no
+ // timeout and therefore we never abort.
+ if ( (totalslept >= _timeout) && (_timeout >= 0 ) )
+ ZYPP_THROW(ZYppLockedException(
+ _("This action is being run by another program already."),
+ _name, locker_pid));
+
+ // if not, let sleep one second and count it
+ LMIL << "waiting 1 second..." << endl;
+ unLockFile();
+ closeLockFile();
+ sleep(1);
+ ++totalslept;
+ continue;
+ }
+ }
+ else
+ {
+ MIL << "no lockfile " << lock_file << " found" << std::endl;
+ if ( geteuid() == 0 )
+ {
+ MIL << "running as root. Will attempt to create " << lock_file << std::endl;
+ createLockFile();
+ // now open it for reading
+ openLockFile("r");
+ shLockFile();
+ }
+ else
+ {
+ MIL << "running as user. Skipping creating " << lock_file << std::endl;
+ }
+ break;
+ }
+ break;
+ }
+ MIL << "Finish constructor" << endl;
+
+}
+
+InterProcessMutex::~InterProcessMutex()
+{
+ try
+ {
+ pid_t curr_pid = getpid();
+ if ( _zypp_lockfile )
+ {
+ Pathname lock_file = lockFilePath();
+ unLockFile();
+ closeLockFile();
+
+ if ( _clean_lock )
+ {
+ MIL << "LOCK [" << _name << "] : cleaning lock file. (" << curr_pid << ")" << std::endl;
+ if ( filesystem::unlink(lock_file) == 0 )
+ MIL << "LOCK [" << _name << "] : lockfile cleaned. (" << curr_pid << ")" << std::endl;
+ else
+ ERR << "LOCK [" << _name << "] : cant clean lockfile. (" << curr_pid << ")" << std::endl;
+ }
+ }
+ }
+ catch(...) {} // let no exception escape.
+}
+
+
+Pathname InterProcessMutex::lockFilePath() const
+{
+ return Pathname("/var/run/zypp-" + _name + ".pid");
+}
+
+pid_t
+InterProcessMutex::locker_pid() const
+{
+ return _locker_pid;
+}
+
+void InterProcessMutex::openLockFile(const char *mode)
+{
+ Pathname lock_file = lockFilePath();
+ _zypp_lockfile = fopen(lock_file.asString().c_str(), mode);
+ if (_zypp_lockfile == 0)
+ ZYPP_THROW (Exception( "Cant open " + lock_file.asString() + " in mode " + std::string(mode) ) );
+}
+
+void InterProcessMutex::closeLockFile()
+{
+ fclose(_zypp_lockfile);
+}
+
+void InterProcessMutex::shLockFile()
+{
+ int fd = fileno(_zypp_lockfile);
+ int lock_error = flock(fd, LOCK_SH);
+ if (lock_error != 0)
+ ZYPP_THROW (Exception( "Cant get shared lock"));
+ else
+ XXX << "locked (shared)" << std::endl;
+}
+
+void InterProcessMutex::exLockFile()
+{
+ int fd = fileno(_zypp_lockfile);
+ // lock access to the file
+ int lock_error = flock(fd, LOCK_EX);
+ if (lock_error != 0)
+ ZYPP_THROW (Exception( "Cant get exclusive lock" ));
+ else
+ XXX << "locked (exclusive)" << std::endl;
+}
+
+void InterProcessMutex::unLockFile()
+{
+ int fd = fileno(_zypp_lockfile);
+ // lock access to the file
+ int lock_error = flock(fd, LOCK_UN);
+ if (lock_error != 0)
+ ZYPP_THROW (Exception( "Cant release lock" ));
+ else
+ XXX << "unlocked" << std::endl;
+}
+
+void InterProcessMutex::createLockFile()
+{
+ pid_t curr_pid = getpid();
+ openLockFile("w");
+ exLockFile();
+ fprintf(_zypp_lockfile, "%ld\n", (long) curr_pid);
+ fflush(_zypp_lockfile);
+ unLockFile();
+ MIL << "written lockfile with pid " << curr_pid << std::endl;
+ closeLockFile();
+}
+
+bool InterProcessMutex::isProcessRunning(pid_t pid_r)
+{
+ // it is another program, not me, see if it is still running
+ Pathname procdir( Pathname("/proc") / str::numstring(pid_r) );
+
+ PathInfo status( procdir/"status" );
+ XXX << "Checking " << status << endl;
+ bool still_running = status.isExist();
+
+ if ( still_running )
+ {
+ Pathname p( procdir/"exe" );
+ XXX << p << " -> " << filesystem::readlink( p ) << endl;
+
+ p = procdir/"cmdline";
+ XXX << p << ": ";
+ std::ifstream infile( p.c_str() );
+ for( iostr::EachLine in( infile ); in; in.next() )
+ {
+ XXX << *in << endl;
+ }
+ }
+
+ return still_running;
+}
+
+pid_t InterProcessMutex::lockerPid()
+{
+ pid_t locker_pid = 0;
+ long readpid = 0;
+
+ fscanf(_zypp_lockfile, "%ld", &readpid);
+ locker_pid = (pid_t) readpid;
+ return locker_pid;
+}
+
+bool InterProcessMutex::locked()
+{
+ return true;
+}
+
+}
+}
+
+
Added: trunk/libzypp/zypp/base/InterProcessMutex.h
URL: http://svn.opensuse.org/viewcvs/zypp/trunk/libzypp/zypp/base/InterProcessMutex.h?rev=9244&view=auto
==============================================================================
--- trunk/libzypp/zypp/base/InterProcessMutex.h (added)
+++ trunk/libzypp/zypp/base/InterProcessMutex.h Thu Mar 20 18:49:50 2008
@@ -0,0 +1,87 @@
+
+#ifndef ZYPP_BASE_INTER_PROCESS_MUTEX_H
+#define ZYPP_BASE_INTER_PROCESS_MUTEX_H
+
+#include <string>
+#include "zypp/base/Exception.h"
+#include "zypp/Pathname.h"
+
+namespace zypp
+{
+namespace base
+{
+
+class ZYppLockedException : public Exception
+{
+public:
+ ZYppLockedException( const std::string & msg_r,
+ const std::string &name,
+ pid_t locker_pid );
+ virtual ~ZYppLockedException() throw();
+ pid_t locker_pid() const { return _locker_pid; }
+ std::string name() const { return _name; }
+private:
+ pid_t _locker_pid;
+ std::string _name;
+};
+
+
+/**
+ * Inter process scoped lock implementation
+ *
+ * This mutex will allow only one process to
+ * reach a critical region protected by a mutex
+ * of the same name.
+ *
+ */
+class InterProcessMutex
+{
+public:
+ /**
+ * Creates a mutex with a name and a timeout.
+ *
+ * default timeout is -1 which means no timeout
+ * at all, and the mutex will wait forever if
+ * other process is accessing the critical region
+ * for a mutex in with the same name.
+ *
+ * If the timeout is 0, then if the lock is acquired
+ * an exception will be thrown inmediately.
+ *
+ * Otherwise, the timeout exception will come after
+ * the timeout is reached.
+ *
+ */
+ InterProcessMutex( const std::string &name = "zypp",
+ int timeout = -1 );
+
+ ~InterProcessMutex();
+
+ pid_t locker_pid() const;
+
+private:
+ void openLockFile(const char *mode);
+ void closeLockFile();
+
+ void shLockFile();
+ void exLockFile();
+ void unLockFile();
+ void createLockFile();
+ bool isProcessRunning(pid_t pid_r);
+ pid_t lockerPid();
+ bool locked();
+ Pathname lockFilePath() const;
+private:
+ bool _clean_lock;
+ FILE *_zypp_lockfile;
+ pid_t _locker_pid;
+ std::string _name;
+ int _timeout;
+};
+
+
+} }
+
+
+#endif
+
--
To unsubscribe, e-mail: zypp-commit+unsubscribe@opensuse.org
For additional commands, e-mail: zypp-commit+help@opensuse.org