Imported Upstream version 16.0.2
[platform/upstream/libzypp.git] / zypp / ZYppFactory.cc
index ef6c27d..03ea897 100644 (file)
@@ -15,11 +15,13 @@ extern "C"
 }
 #include <iostream>
 #include <fstream>
+#include <signal.h>
 
 #include "zypp/base/Logger.h"
 #include "zypp/base/Gettext.h"
 #include "zypp/base/IOStream.h"
 #include "zypp/base/Functional.h"
+#include "zypp/base/Backtrace.h"
 #include "zypp/PathInfo.h"
 
 #include "zypp/ZYppFactory.h"
@@ -40,6 +42,19 @@ using std::endl;
 namespace zypp
 { /////////////////////////////////////////////////////////////////
 
+  namespace
+  {
+    void sigsegvHandler( int sig );
+    ::sighandler_t lastSigsegvHandler = ::signal( SIGSEGV, sigsegvHandler );
+
+    /** SIGSEGV handler to log stack trace */
+    void sigsegvHandler( int sig )
+    {
+      INT << "Error: signal " << sig << endl << dumpBacktrace << endl;
+      ::signal( SIGSEGV, lastSigsegvHandler );
+    }
+  }
+
   namespace env
   {
     /** Hack to circumvent the currently poor --root support. */
@@ -51,7 +66,7 @@ namespace zypp
   namespace zypp_readonly_hack
   { /////////////////////////////////////////////////////////////////
 
-    static bool active = false;
+    static bool active = getenv("ZYPP_READONLY_HACK");
 
     void IWantIt()
     {
@@ -59,6 +74,11 @@ namespace zypp
       MIL << "ZYPP_READONLY promised." <<  endl;
     }
 
+    bool IGotIt()
+    {
+      return active;
+    }
+
     /////////////////////////////////////////////////////////////////
   } // namespace zypp_readonly_hack
   ///////////////////////////////////////////////////////////////////
@@ -72,10 +92,10 @@ namespace zypp
   {
   public:
     ZYppGlobalLock()
-    : _cleanLock( false )
-    , _zyppLockFilePath( env::ZYPP_LOCKFILE_ROOT() / "/var/run/zypp.pid" )
+    : _zyppLockFilePath( env::ZYPP_LOCKFILE_ROOT() / "/var/run/zypp.pid" )
     , _zyppLockFile( NULL )
     , _lockerPid( 0 )
+    , _cleanLock( false )
     {
       filesystem::assert_dir(_zyppLockFilePath.dirname() );
     }
@@ -262,14 +282,35 @@ namespace zypp
 
   };
 
+  ///////////////////////////////////////////////////////////////////
   namespace
   {
-    static ZYppGlobalLock & globalLock()
+    static weak_ptr<ZYpp>              _theZYppInstance;
+    static scoped_ptr<ZYppGlobalLock>  _theGlobalLock;         // on/off in sync with _theZYppInstance
+
+    ZYppGlobalLock & globalLock()
     {
-      static ZYppGlobalLock lock;
-      return lock;
+      if ( !_theGlobalLock )
+       _theGlobalLock.reset( new ZYppGlobalLock );
+      return *_theGlobalLock;
     }
-    bool           _haveZYpp = false;
+  } //namespace
+  ///////////////////////////////////////////////////////////////////
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  //   CLASS NAME : ZYpp
+  //
+  ///////////////////////////////////////////////////////////////////
+
+  ZYpp::ZYpp( const Impl_Ptr & impl_r )
+  : _pimpl( impl_r )
+  {
+  }
+
+  ZYpp::~ZYpp()
+  {
+    _theGlobalLock.reset();
   }
 
   ///////////////////////////////////////////////////////////////////
@@ -293,31 +334,12 @@ namespace zypp
   //
   ///////////////////////////////////////////////////////////////////
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : ZYppFactory::instance
-  //   METHOD TYPE : ZYppFactory
-  //
   ZYppFactory ZYppFactory::instance()
-  {
-    return ZYppFactory();
-  }
+  { return ZYppFactory(); }
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : ZYppFactory::ZYppFactory
-  //   METHOD TYPE : Ctor
-  //
   ZYppFactory::ZYppFactory()
-  {
-
-  }
+  {}
 
-  ///////////////////////////////////////////////////////////////////
-  //
-  //   METHOD NAME : ZYppFactory::~ZYppFactory
-  //   METHOD TYPE : Dtor
-  //
   ZYppFactory::~ZYppFactory()
   {}
 
@@ -325,8 +347,7 @@ namespace zypp
   //
   ZYpp::Ptr ZYppFactory::getZYpp() const
   {
-    static ZYpp::Ptr _instance;
-
+    ZYpp::Ptr _instance = _theZYppInstance.lock();
     if ( ! _instance )
     {
       if ( geteuid() != 0 )
@@ -339,17 +360,51 @@ namespace zypp
       }
       else if ( globalLock().zyppLocked() )
       {
-       std::string t = str::form(_("System management is locked by the application with pid %d (%s).\n"
-                                     "Close this application before trying again."),
-                                  globalLock().lockerPid(),
-                                  globalLock().lockerName().c_str()
-                                 );
-       ZYPP_THROW(ZYppFactoryException(t, globalLock().lockerPid(), globalLock().lockerName() ));
+       bool failed = true;
+       const long LOCK_TIMEOUT = str::strtonum<long>( getenv( "ZYPP_LOCK_TIMEOUT" ) );
+       if ( LOCK_TIMEOUT > 0 )
+       {
+         MIL << "Waiting whether pid " << globalLock().lockerPid() << " ends within $LOCK_TIMEOUT=" << LOCK_TIMEOUT << " sec." << endl;
+         unsigned delay = 1;
+         Pathname procdir( "/proc"/str::numstring(globalLock().lockerPid()) );
+         for ( long i = 0; i < LOCK_TIMEOUT; i += delay )
+         {
+           if ( PathInfo( procdir ).isDir() )  // wait for /proc/pid to disapear
+             sleep( delay );
+           else
+           {
+             MIL << "Retry after " << i << " sec." << endl;
+             failed = globalLock().zyppLocked();
+             if ( failed )
+             {
+               // another proc locked faster. maybe it ends fast as well....
+               MIL << "Waiting whether pid " << globalLock().lockerPid() << " ends within " << (LOCK_TIMEOUT-i) << " sec." << endl;
+               procdir = Pathname( "/proc"/str::numstring(globalLock().lockerPid()) );
+             }
+             else
+             {
+               MIL << "Finally got the lock!" << endl;
+               break;  // gotcha
+             }
+           }
+         }
+       }
+       if ( failed )
+       {
+         std::string t = str::form(_("System management is locked by the application with pid %d (%s).\n"
+                                     "Close this application before trying again."),
+                                     globalLock().lockerPid(),
+                                     globalLock().lockerName().c_str()
+                                   );
+         ZYPP_THROW(ZYppFactoryException(t, globalLock().lockerPid(), globalLock().lockerName() ));
+       }
       }
       // Here we go...
-      _instance = new ZYpp( ZYpp::Impl_Ptr(new ZYpp::Impl) );
-      if ( _instance )
-        _haveZYpp = true;
+      static ZYpp::Impl_Ptr _theImplInstance;  // for now created once
+      if ( !_theImplInstance )
+       _theImplInstance.reset( new ZYpp::Impl );
+      _instance.reset( new ZYpp( _theImplInstance ) );
+      _theZYppInstance = _instance;
     }
 
     return _instance;
@@ -358,7 +413,7 @@ namespace zypp
   ///////////////////////////////////////////////////////////////////
   //
   bool ZYppFactory::haveZYpp() const
-  { return _haveZYpp; }
+  { return !_theZYppInstance.expired(); }
 
   /******************************************************************
   **