Index: /trunk/include/VBox/com/EventQueue.h
===================================================================
--- /trunk/include/VBox/com/EventQueue.h	(revision 22721)
+++ /trunk/include/VBox/com/EventQueue.h	(revision 22722)
@@ -90,4 +90,7 @@
     BOOL waitForEvent (Event **event);
     BOOL handleEvent (Event *event);
+    static int processThreadEventQueue(uint32_t cMsTimeout, bool (*pfnExitCheck)(void *pvUser) = 0,
+                                       void *pvUser = 0, uint32_t cMsPollInterval = 1000,
+                                       bool fReturnOnEvent = true);
 
 private:
Index: /trunk/include/iprt/err.h
===================================================================
--- /trunk/include/iprt/err.h	(revision 22721)
+++ /trunk/include/iprt/err.h	(revision 22722)
@@ -599,4 +599,8 @@
 /** Invalid Base64 encoding. */
 #define VERR_INVALID_BASE64_ENCODING        (-87)
+/** Return instigated by a callback or similar. */
+#define VERR_CALLBACK_RETURN                (-88)
+/** Return instigated by a callback or similar. */
+#define VINF_CALLBACK_RETURN                88
 /** @} */
 
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestProp.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestProp.cpp	(revision 22721)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestProp.cpp	(revision 22722)
@@ -419,4 +419,18 @@
 
 /**
+ * Callback for processThreadEventQueue.
+ *
+ * @param   pvUser  Pointer to the callback object.
+ *
+ * @returns true if it should return or false if it should continue waiting for
+ *          events.
+ */
+static bool eventExitCheck(void *pvUser)
+{
+    GuestPropertyCallback const *pCallbacks = (GuestPropertyCallback const *)pvUser;
+    return pCallbacks->Signalled();
+}
+
+/**
  * Enumerates the properties in the guest property store.
  *
@@ -469,4 +483,5 @@
      * Set up the callback and wait.
      *
+     *
      * The waiting is done is 1 sec at the time since there there are races
      * between the callback and us going to sleep.  This also guards against
@@ -485,83 +500,14 @@
     a->virtualBox->RegisterCallback(callback);
 
-#ifdef USE_XPCOM_QUEUE
-    int const       fdQueue   = a->eventQ->GetEventQueueSelectFD();
-#endif
-    uint64_t const  StartMsTS = RTTimeMilliTS();
-    for (;;)
-    {
-#ifdef VBOX_WITH_XPCOM
-        /* Process pending XPCOM events. */
-        a->eventQ->ProcessPendingEvents();
-#endif
-
-        /* Signalled? */
-        if (cbImpl->Signalled())
-            break;
-
-        /* Figure out how much we have left to wait and if we've timed out already. */
-        uint32_t cMsLeft;
-        if (cMsTimeout == RT_INDEFINITE_WAIT)
-            cMsLeft = RT_INDEFINITE_WAIT;
-        else
-        {
-            uint64_t cMsElapsed = RTTimeMilliTS() - StartMsTS;
-            if (cMsElapsed >= cMsTimeout)
-                break; /* timeout */
-            cMsLeft = cMsTimeout - (uint32_t)cMsElapsed;
-        }
-
-        /* Wait in a platform specific manner. */
-#define POLL_MS_INTERVAL    1000
-#ifdef USE_XPCOM_QUEUE
-        fd_set fdset;
-        FD_ZERO(&fdset);
-        FD_SET(fdQueue, &fdset);
-        struct timeval tv;
-        if (    cMsLeft == RT_INDEFINITE_WAIT
-            ||  cMsLeft >= POLL_MS_INTERVAL)
-        {
-            tv.tv_sec = POLL_MS_INTERVAL / 1000;
-            tv.tv_usec = 0;
-        }
-        else
-        {
-            tv.tv_sec = 0;
-            tv.tv_usec = cMsLeft * 1000;
-        }
-        int prc = select(fdQueue + 1, &fdset, NULL, NULL, &tv);
-        if (prc == -1)
-        {
-            RTPrintf("Error waiting for event: %s (%d)\n", strerror(errno), errno);
-            break;
-        }
-
-#elif defined(RT_OS_DARWIN)
-        CFTimeInterval rdTimeout = (double)RT_MIN(cMsLeft, POLL_MS_INTERVAL) / 1000;
-        OSStatus orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, rdTimeout, true /*returnAfterSourceHandled*/);
-        if (orc == kCFRunLoopRunHandledSource)
-            orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, false /*returnAfterSourceHandled*/);
-        if (   orc != 0
-            && orc != kCFRunLoopRunHandledSource
-            && orc != kCFRunLoopRunTimedOut)
-        {
-            RTPrintf("Error waiting for event: %d\n", orc);
-            break;
-        }
-
-#else  /* !USE_XPCOM_QUEUE */
-        int vrc = cbImpl->wait(RT_MIN(cMsLeft, POLL_MS_INTERVAL));
-        if (    vrc != VERR_TIMEOUT
-            &&  RT_FAILURE(vrc))
-        {
-            RTPrintf("Error waiting for event: %Rrc\n", vrc);
-            break;
-        }
-#endif /* !USE_XPCOM_QUEUE */
-    } /* for (;;) */
-
-    /*
-     * Clean up the callback and report timeout.
-     */
+    int vrc = com::EventQueue::processThreadEventQueue(cMsTimeout, eventExitCheck, (void *)cbImpl,
+                                                       1000 /*cMsPollInterval*/, false /*fReturnOnEvent*/);
+    if (   RT_FAILURE(vrc)
+        && vrc != VERR_CALLBACK_RETURN
+        && vrc != VERR_TIMEOUT)
+    {
+        RTPrintf("Error waiting for event: %Rrc\n", vrc);
+        return 1;
+    }
+
     a->virtualBox->UnregisterCallback(callback);
 
Index: /trunk/src/VBox/Main/glue/EventQueue.cpp
===================================================================
--- /trunk/src/VBox/Main/glue/EventQueue.cpp	(revision 22721)
+++ /trunk/src/VBox/Main/glue/EventQueue.cpp	(revision 22722)
@@ -24,4 +24,19 @@
 
 #include "VBox/com/EventQueue.h"
+
+#ifdef RT_OS_DARWIN
+# include <CoreFoundation/CFRunLoop.h>
+#endif
+
+#if defined(VBOX_WITH_XPCOM) && !defined(RT_OS_DARWIN) && !defined(RT_OS_OS2)
+# define USE_XPCOM_QUEUE
+#endif
+
+#include <iprt/err.h>
+#include <iprt/time.h>
+#include <iprt/thread.h>
+#ifdef USE_XPCOM_QUEUE
+# include <errno.h>
+#endif
 
 namespace com
@@ -246,4 +261,275 @@
 }
 
-} /* namespace com */
-
+
+#ifdef VBOX_WITH_XPCOM
+
+/** Wrapper around nsIEventQueue::PendingEvents. */
+DECLINLINE(bool) hasEventQueuePendingEvents(nsIEventQueue *pQueue)
+{
+    PRBool fHasEvents = PR_FALSE;
+    nsresult rc = pQueue->PendingEvents(&fHasEvents);
+    return NS_SUCCEEDED(rc) && fHasEvents ? true : false;
+}
+
+/** Wrapper around nsIEventQueue::IsQueueNative. */
+DECLINLINE(bool) isEventQueueNative(nsIEventQueue *pQueue)
+{
+    PRBool fIsNative = PR_FALSE;
+    nsresult rc = pQueue->IsQueueNative(&fIsNative);
+    return NS_SUCCEEDED(rc) && fIsNative ? true : false;
+}
+
+/** Wrapper around nsIEventQueue::ProcessPendingEvents. */
+DECLINLINE(void) processPendingEvents(nsIEventQueue *pQueue)
+{
+    pQueue->ProcessPendingEvents();
+}
+
+#else
+
+/** For automatic cleanup.  */
+class MyThreadHandle
+{
+public:
+    HANDLE mh;
+
+    MyThreadHandle(HANDLE hThread)
+    {
+        if (!DuplicateHandle(GetCurrentProcess(), hThread, GetCurrentProcess(),
+                             &mh, 0 /*dwDesiredAccess*/, FALSE /*bInheritHandle*/,
+                             DUPLICATE_SAME_ACCESS))
+            mh = INVALID_HANDLE_VALUE;
+    }
+
+    ~MyThreadHandle()
+    {
+        CloseHandle(mh);
+        mh = INVALID_HANDLE_VALUE;
+    }
+};
+
+/** COM version of nsIEventQueue::PendingEvents. */
+DECLINLINE(bool) hasEventQueuePendingEvents(MyThreadHandle &Handle)
+{
+    DWORD rc = MsgWaitForMultipleObjects(1, &Handle.mh, TRUE /*fWaitAll*/, 0 /*ms*/, QS_ALLINPUT);
+    return rc == WAIT_OBJECT_0;
+}
+
+/** COM version of nsIEventQueue::IsQueueNative, the question doesn't make
+ *  sense and we have to return false for the code below to work. */
+DECLINLINE(bool) isEventQueueNative(MyThreadHandle const &Handle)
+{
+    return false;
+}
+
+/** COM version of nsIEventQueue::ProcessPendingEvents. */
+static void processPendingEvents(MyThreadHandle const &Handle)
+{
+    /*
+     * Process pending thead messages.
+     */
+    MSG Msg;
+    while (PeekMessage(&Msg, NULL /*hWnd*/, 0 /*wMsgFilterMin*/, 0 /*wMsgFilterMax*/, PM_REMOVE))
+    {
+        if (Msg.message == WM_QUIT)
+            return /*VERR_INTERRUPTED*/;
+        DispatchMessage(&Msg);
+    }
+}
+
+#endif /* VBOX_WITH_XPCOM */
+
+/**
+ *  Processes events for the current thread.
+ *
+ *  @param cMsTimeout       The timeout in milliseconds or RT_INDEFINITE_WAIT.
+ *  @param pfnExitCheck     Optional callback for checking for some exit condition
+ *                          while looping.  Note that this may be called
+ *  @param pvUser           User argument for pfnExitCheck.
+ *  @param cMsPollInterval  The interval cMsTimeout should be called at. 0 means
+ *                          never default.
+ *  @param fReturnOnEvent   If true, return immediately after some events has
+ *                          been processed. If false, process events until we
+ *                          time out, pfnExitCheck returns true, interrupted or
+ *                          the queue receives some kind of quit message.
+ *
+ *  @returns VBox status code.
+ *  @retval VINF_SUCCESS if events were processed.
+ *  @retval VERR_TIMEOUT if no events before cMsTimeout elapsed.
+ *  @retval VERR_INTERRUPTED if the wait was interrupted by a signal or other
+ *          async event.
+ *  @retval VERR_NOT_FOUND if the thread has no event queue.
+ *  @retval VERR_CALLBACK_RETURN if the callback indicates return.
+ *
+ *  @todo This is just a quick approximation of what we need. Feel free to
+ *        improve the interface and make it fit better in with the EventQueue
+ *        class.
+ */
+/*static*/ int
+EventQueue::processThreadEventQueue(uint32_t cMsTimeout, bool (*pfnExitCheck)(void *pvUser) /*= 0*/,
+                                    void *pvUser /*= 0*/, uint32_t cMsPollInterval /*= 1000*/,
+                                    bool fReturnOnEvent /*= true*/)
+{
+    uint64_t const StartMsTS = RTTimeMilliTS();
+
+    /* set default. */
+    if (cMsPollInterval == 0)
+        cMsPollInterval = 1000;
+
+    /*
+     * Get the event queue / thread.
+     */
+#ifdef VBOX_WITH_XPCOM
+    nsCOMPtr<nsIEventQueue> q;
+    nsresult rv = NS_GetCurrentEventQ(getter_AddRefs(q));
+    if (NS_FAILED(rv))
+        return VERR_NOT_FOUND;
+#else
+    MyThreadHandle q(GetCurrentThread());
+#endif
+
+    /*
+     * Check for pending before setting up the wait.
+     */
+    if (    !hasEventQueuePendingEvents(q)
+        ||  !fReturnOnEvent)
+    {
+        bool fIsNative = isEventQueueNative(q);
+        if (    fIsNative
+            ||  cMsTimeout != RT_INDEFINITE_WAIT
+            ||  pfnExitCheck
+            ||  !fReturnOnEvent /** @todo !fReturnOnEvent and cMsTimeout RT_INDEFINITE_WAIT can be handled in else */)
+        {
+#ifdef USE_XPCOM_QUEUE
+            int const fdQueue = fIsNative ? q->GetEventQueueSelectFD() : -1;
+            if (fIsNative && fdQueue == -1)
+                return VERR_INTERNAL_ERROR_4;
+#endif
+            for (;;)
+            {
+                /*
+                 * Check for events.
+                 */
+                if (hasEventQueuePendingEvents(q))
+                {
+                    if (fReturnOnEvent)
+                        break;
+                    processPendingEvents(q);
+                }
+
+                /*
+                 * Check the user exit.
+                 */
+                if (   pfnExitCheck
+                    && pfnExitCheck(pvUser))
+                    return VERR_CALLBACK_RETURN;
+
+                /*
+                 * Figure out how much we have left to wait and if we've timed out already.
+                 */
+                uint32_t cMsLeft;
+                if (cMsTimeout == RT_INDEFINITE_WAIT)
+                    cMsLeft = RT_INDEFINITE_WAIT;
+                else
+                {
+                    uint64_t cMsElapsed = RTTimeMilliTS() - StartMsTS;
+                    if (cMsElapsed >= cMsTimeout)
+                        break; /* timeout */
+                    cMsLeft = cMsTimeout - (uint32_t)cMsElapsed;
+                }
+
+                /*
+                 * Wait in a queue & platform specific manner.
+                 */
+#ifdef VBOX_WITH_XPCOM
+                if (!fIsNative)
+                    RTThreadSleep(250 /*ms*/);
+                else
+                {
+# ifdef USE_XPCOM_QUEUE
+                    fd_set fdset;
+                    FD_ZERO(&fdset);
+                    FD_SET(fdQueue, &fdset);
+                    struct timeval tv;
+                    if (    cMsLeft == RT_INDEFINITE_WAIT
+                        ||  cMsLeft >= cMsPollInterval)
+                    {
+                        tv.tv_sec = cMsPollInterval / 1000;
+                        tv.tv_usec = (cMsPollInterval % 1000) * 1000;
+                    }
+                    else
+                    {
+                        tv.tv_sec = cMsLeft / 1000;
+                        tv.tv_usec = (cMsLeft % 1000) * 1000;
+                    }
+                    int prc = select(fdQueue + 1, &fdset, NULL, NULL, &tv);
+                    if (prc == -1)
+                        return RTErrConvertFromErrno(errno);
+
+# elif defined(RT_OS_DARWIN)
+                    CFTimeInterval rdTimeout = (double)RT_MIN(cMsLeft, cMsPollInterval) / 1000;
+                    OSStatus orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, rdTimeout, true /*returnAfterSourceHandled*/);
+                    if (orc == kCFRunLoopRunHandledSource)
+                        orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, false /*returnAfterSourceHandled*/);
+                    if (   orc != 0
+                        && orc != kCFRunLoopRunHandledSource
+                        && orc != kCFRunLoopRunTimedOut)
+                        return orc == kCFRunLoopRunStopped || orc == kCFRunLoopRunFinished
+                             ? VERR_INTERRUPTED
+                             : RTErrConvertFromDarwin(orc);
+# else
+#  warning "PORTME:"
+                    RTThreadSleep(250);
+# endif
+                }
+
+#else  /* !VBOX_WITH_XPCOM */
+                DWORD rc = MsgWaitForMultipleObjects(1, &q.mh, TRUE /*fWaitAll*/, RT_MIN(cMsLeft, cMsPollInterval), QS_ALLINPUT);
+                if (rc == WAIT_OBJECT_0)
+                {
+                    if (fReturnOnEvent)
+                        break;
+                    processPendingEvents(q);
+                }
+                else if (rc == WAIT_FAILED)
+                    return RTErrConvertFromWin32(GetLastError());
+                else if (rc != WAIT_TIMEOUT)
+                    return VERR_INTERNAL_ERROR_4;
+#endif /* !VBOX_WITH_XPCOM */
+            } /* for (;;) */
+        }
+        else
+        {
+            /*
+             * Indefinite wait without any complications.
+             */
+#ifdef VBOX_WITH_XPCOM
+            PLEvent *pEvent = NULL;
+            rv = q->WaitForEvent(&pEvent);
+            if (NS_FAILED(rv))
+                return VERR_INTERRUPTED;
+            q->HandleEvent(pEvent);
+#else
+            DWORD rc = MsgWaitForMultipleObjects(1, &q.mh, TRUE /*fWaitAll*/, INFINITE, QS_ALLINPUT);
+            if (rc != WAIT_OBJECT_0)
+            {
+                if (rc == WAIT_FAILED)
+                    return RTErrConvertFromWin32(GetLastError());
+                return VERR_INTERNAL_ERROR_3;
+            }
+#endif
+        }
+    }
+
+    /*
+     * We have/had events in the queue. Process pending events and
+     * return successfully.
+     */
+    processPendingEvents(q);
+
+    return VINF_SUCCESS;
+}
+
+}
+/* namespace com */
+
Index: /trunk/src/VBox/Main/webservice/vboxweb.cpp
===================================================================
--- /trunk/src/VBox/Main/webservice/vboxweb.cpp	(revision 22721)
+++ /trunk/src/VBox/Main/webservice/vboxweb.cpp	(revision 22722)
@@ -462,4 +462,11 @@
             WebLog("Request served\n");
 
+#if 0 /* Ulrich, try enable this and see if the leak goes away. */
+{
+ int vrc = com::EventQueue::processThreadEventQueue(0);
+ WebLog("processThreadEventQueue -> %Rrc\n", vrc);
+}
+#endif
+
             soap_destroy(&soap); // clean up class instances
             soap_end(&soap); // clean up everything and close socket
