Index: trunk/src/VBox/Main/webservice/vboxweb.cpp
===================================================================
--- trunk/src/VBox/Main/webservice/vboxweb.cpp	(revision 26374)
+++ trunk/src/VBox/Main/webservice/vboxweb.cpp	(revision 26375)
@@ -32,5 +32,5 @@
 #include <VBox/version.h>
 
-#include <iprt/cpp/lock.h>
+#include <iprt/thread.h>
 #include <iprt/rand.h>
 #include <iprt/initterm.h>
@@ -114,8 +114,9 @@
  ****************************************************************************/
 
-RTLockMtx           g_mutexAuthLib;
+// this mutex protects the auth lib and authentication
+util::RWLockHandle  *g_pAuthLibLockHandle;
 
 // this mutex protects all of the below
-RTLockMtx           g_mutexSessions;
+util::RWLockHandle  *g_pSessionsLockHandle;
 
 SessionsMap         g_mapSessions;
@@ -247,4 +248,70 @@
 }
 
+/**
+ * Called from main(). This implements the loop that takes SOAP calls
+ * from HTTP and serves them, calling the COM method implementations
+ * in the generated methodmaps.cpp code.
+ */
+void beginProcessing()
+{
+    // set up gSOAP
+    struct soap soap;
+    soap_init(&soap);
+
+    soap.bind_flags |= SO_REUSEADDR;
+            // avoid EADDRINUSE on bind()
+
+    int m, s; // master and slave sockets
+    m = soap_bind(&soap,
+                  g_pcszBindToHost,     // host: current machine
+                  g_uBindToPort,     // port
+                  g_uBacklog);     // backlog = max queue size for requests
+    if (m < 0)
+        WebLogSoapError(&soap);
+    else
+    {
+        WebLog("Socket connection successful: host = %s, port = %u, master socket = %d\n",
+               (g_pcszBindToHost) ? g_pcszBindToHost : "default (localhost)",
+               g_uBindToPort,
+               m);
+
+        for (uint64_t i = 1;
+             ;
+             i++)
+        {
+            // call gSOAP to handle incoming SOAP connection
+            s = soap_accept(&soap);
+            if (s < 0)
+            {
+                WebLogSoapError(&soap);
+                break;
+            }
+
+            WebLog("%llu: accepted connection from IP=%lu.%lu.%lu.%lu socket=%d... ",
+                   i,
+                   (soap.ip>>24)&0xFF,
+                   (soap.ip>>16)&0xFF,
+                   (soap.ip>>8)&0xFF,
+                   soap.ip&0xFF,
+                   s);
+
+            // now process the RPC request (this goes into the
+            // generated code in methodmaps.cpp with all the COM calls)
+            if (soap_serve(&soap) != SOAP_OK)
+            {
+                WebLogSoapError(&soap);
+            }
+
+            WebLog("Request served\n");
+
+            soap_destroy(&soap); // clean up class instances
+            soap_end(&soap); // clean up everything and close socket
+
+            // we have to process main event queue
+            int vrc = com::EventQueue::getMainEventQueue()->processEventQueue(0);
+        }
+    }
+    soap_done(&soap); // close master socket and detach environment
+}
 
 /**
@@ -390,4 +457,8 @@
     }
 
+    // create the global mutexes
+    g_pAuthLibLockHandle = new util::RWLockHandle(util::LOCKCLASS_OBJECTSTATE);
+    g_pSessionsLockHandle = new util::RWLockHandle(util::LOCKCLASS_OBJECTSTATE);
+
     if (g_iWatchdogTimeoutSecs > 0)
     {
@@ -407,67 +478,5 @@
     }
 
-    // set up gSOAP
-    struct soap soap;
-    soap_init(&soap);
-
-    soap.bind_flags |= SO_REUSEADDR;
-            // avoid EADDRINUSE on bind()
-
-    int m, s; // master and slave sockets
-    m = soap_bind(&soap,
-                  g_pcszBindToHost,     // host: current machine
-                  g_uBindToPort,     // port
-                  g_uBacklog);     // backlog = max queue size for requests
-    if (m < 0)
-        WebLogSoapError(&soap);
-    else
-    {
-        WebLog("Socket connection successful: host = %s, port = %u, master socket = %d\n",
-               (g_pcszBindToHost) ? g_pcszBindToHost : "default (localhost)",
-               g_uBindToPort,
-               m);
-
-        for (uint64_t i = 1;
-             ;
-             i++)
-        {
-            // call gSOAP to handle incoming SOAP connection
-            s = soap_accept(&soap);
-            if (s < 0)
-            {
-                WebLogSoapError(&soap);
-                break;
-            }
-
-            WebLog("%llu: accepted connection from IP=%lu.%lu.%lu.%lu socket=%d... ",
-                   i,
-                   (soap.ip>>24)&0xFF,
-                   (soap.ip>>16)&0xFF,
-                   (soap.ip>>8)&0xFF,
-                   soap.ip&0xFF,
-                   s);
-
-            // enclose the entire RPC call in the sessions lock
-            // so that the watchdog cannot destroy COM objects
-            // while the RPC is ongoing
-            RTLock lock(g_mutexSessions);
-            // now process the RPC request (this goes into the
-            // generated code in methodmaps.cpp with all the COM calls)
-            if (soap_serve(&soap) != SOAP_OK)
-            {
-                WebLogSoapError(&soap);
-            }
-            lock.release();
-
-            WebLog("Request served\n");
-
-            soap_destroy(&soap); // clean up class instances
-            soap_end(&soap); // clean up everything and close socket
-
-            // we have to process main event queue
-            int vrc = com::EventQueue::getMainEventQueue()->processEventQueue(0);
-        }
-    }
-    soap_done(&soap); // close master socket and detach environment
+    beginProcessing();
 
     com::Shutdown();
@@ -499,10 +508,11 @@
         time(&tNow);
 
-        RTLock lock(g_mutexSessions);
+        // lock the sessions while we're iterating; this blocks
+        // out the COM code from messing with it
+        util::AutoWriteLock lock(g_pSessionsLockHandle COMMA_LOCKVAL_SRC_POS);
         WEBDEBUG(("Watchdog: checking %d sessions\n", g_mapSessions.size()));
 
-        SessionsMap::iterator
-            it = g_mapSessions.begin(),
-            itEnd = g_mapSessions.end();
+        SessionsMap::iterator it = g_mapSessions.begin(),
+                              itEnd = g_mapSessions.end();
         while (it != itEnd)
         {
@@ -520,5 +530,4 @@
                 ++it;
         }
-        lock.release();
     }
 
@@ -617,6 +626,5 @@
 std::string ConvertComString(const com::Guid &uuid)
 {
-    com::Bstr bstr(uuid);
-    com::Utf8Str ustr(bstr);
+    com::Utf8Str ustr(uuid.toString());
     const char *pcsz;
     if ((pcsz = ustr.raw()))
@@ -739,5 +747,5 @@
  * Constructor for the session object.
  *
- * Preconditions: Caller must have locked g_mutexSessions.
+ * Preconditions: Caller must have locked g_pSessionsLockHandle in write mode.
  *
  * @param username
@@ -753,4 +761,5 @@
 
     // register this session globally
+    Assert(g_pSessionsLockHandle->isWriteLockOnCurrentThread());
     g_mapSessions[_uSessionID] = this;
 }
@@ -759,5 +768,5 @@
  * Destructor. Cleans up and destroys all contained managed object references on the way.
  *
- * Preconditions: Caller must have locked g_mutexSessions.
+ * Preconditions: Caller must have locked g_pSessionsLockHandle in write mode.
  */
 WebServiceSession::~WebServiceSession()
@@ -765,4 +774,5 @@
     // delete us from global map first so we can't be found
     // any more while we're cleaning up
+    Assert(g_pSessionsLockHandle->isWriteLockOnCurrentThread());
     g_mapSessions.erase(_uSessionID);
 
@@ -778,7 +788,6 @@
     // }
 
-    ManagedObjectsMapById::iterator
-        it,
-        end = _pp->_mapManagedObjectsById.end();
+    ManagedObjectsMapById::iterator it,
+                                    end = _pp->_mapManagedObjectsById.end();
     for (it = _pp->_mapManagedObjectsById.begin();
          it != end;
@@ -804,5 +813,5 @@
     int rc = VERR_WEB_NOT_AUTHENTICATED;
 
-    RTLock lock(g_mutexAuthLib);
+    util::AutoReadLock lock(g_pAuthLibLockHandle COMMA_LOCKVAL_SRC_POS);
 
     static bool fAuthLibLoaded = false;
@@ -875,4 +884,6 @@
     }
 
+    lock.release();
+
     if (!rc)
     {
@@ -912,5 +923,5 @@
  *  our private hash table, we must search for one too.
  *
- *  Preconditions: Caller must have locked g_mutexSessions.
+ * Preconditions: Caller must have locked g_pSessionsLockHandle in read mode.
  *
  * @param pcu pointer to a COM object.
@@ -919,4 +930,6 @@
 ManagedObjectRef* WebServiceSession::findRefFromPtr(const ComPtr<IUnknown> &pcu)
 {
+    // Assert(g_pSessionsLockHandle->isReadLockOnCurrentThread());      // @todo
+
     IUnknown *p = pcu;
     uintptr_t ulp = (uintptr_t)p;
@@ -940,5 +953,5 @@
  * object IDs and then looking up the session object for that session ID.
  *
- * Preconditions: Caller must have locked g_mutexSessions.
+ * Preconditions: Caller must have locked g_pSessionsLockHandle in read mode.
  *
  * @param id Managed object reference (with combined session and object IDs).
@@ -947,4 +960,6 @@
 WebServiceSession* WebServiceSession::findSessionFromRef(const WSDLT_ID &id)
 {
+    // Assert(g_pSessionsLockHandle->isReadLockOnCurrentThread()); // @todo
+
     WebServiceSession *pSession = NULL;
     uint64_t sessid;
@@ -1010,5 +1025,5 @@
 /**
  *  Constructor, which assigns a unique ID to this managed object
- *  reference and stores it two global hashs:
+ *  reference and stores it two global hashes:
  *
  *   a) G_mapManagedObjectsById, which maps ManagedObjectID's to
@@ -1294,4 +1309,7 @@
 
     do {
+        // WebServiceSession constructor tinkers with global MOR map and requires a write lock
+        util::AutoWriteLock lock(g_pSessionsLockHandle COMMA_LOCKVAL_SRC_POS);
+
         // create new session; the constructor stores the new session
         // in the global map automatically
Index: trunk/src/VBox/Main/webservice/vboxweb.h
===================================================================
--- trunk/src/VBox/Main/webservice/vboxweb.h	(revision 26374)
+++ trunk/src/VBox/Main/webservice/vboxweb.h	(revision 26375)
@@ -3,5 +3,5 @@
  *      header file for "real" web server code.
  *
- * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ * Copyright (C) 2006-2010 Sun Microsystems, Inc.
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -33,4 +33,5 @@
 #include <VBox/com/VirtualBox.h>
 #include <VBox/com/Guid.h>
+#include <VBox/com/AutoLock.h>
 
 #include <VBox/err.h>
@@ -39,5 +40,4 @@
 
 #include <string>
-
 
 /****************************************************************************
@@ -51,4 +51,8 @@
 
 extern PRTSTREAM g_pstrLog;
+
+extern util::RWLockHandle  *g_pAuthLibLockHandle;
+
+extern util::RWLockHandle  *g_pSessionsLockHandle;
 
 /****************************************************************************
@@ -224,4 +228,8 @@
                      bool fNullAllowed)
 {
+    // we're only reading the MOR maps, not modifying them, so a readlock is good enough
+    // (allow concurrency, this code gets called from everywhere in methodmaps.cpp)
+    util::AutoReadLock lock(g_pSessionsLockHandle COMMA_LOCKVAL_SRC_POS);
+
     int rc;
     ManagedObjectRef *pRef;
@@ -270,4 +278,6 @@
     }
 
+    // we might be modifying the MOR maps below, so request write lock now
+    util::AutoWriteLock lock(g_pSessionsLockHandle COMMA_LOCKVAL_SRC_POS);
     WebServiceSession *pSession;
     if ((pSession = WebServiceSession::findSessionFromRef(idParent)))
