Index: /trunk/src/VBox/HostDrivers/Support/SUPDrv-dtrace.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPDrv-dtrace.cpp	(revision 40674)
+++ /trunk/src/VBox/HostDrivers/Support/SUPDrv-dtrace.cpp	(revision 40675)
@@ -81,4 +81,6 @@
     /** The number of probes we've provided to DTrace. */
     uint32_t            cProvidedProbes;
+    /** Set when the module is unloaded or the driver deregisters its probes. */
+    bool                fZombie;
 } SUPDRVDTPROVIDER;
 /** Pointer to the data for a provider. */
@@ -374,4 +376,18 @@
 
 /**
+ * Frees the provider structure and associated resources. 
+ *  
+ * @param   pProv               The provider to free.
+ */
+static void supdrvVtgFreeProvider(PSUPDRVDTPROVIDER pProv)
+{
+    pProv->fZombie = true;
+    pProv->pDesc   = NULL;
+    pProv->pHdr    = NULL;
+    RTMemFree(pProv);
+}
+
+
+/**
  * Registers the VTG tracepoint providers of a driver.
  *
@@ -444,4 +460,5 @@
             pProv->idDtProv         = 0;
             pProv->cProvidedProbes  = 0;
+            pProv->fZombie          = false;
             supdrvVtgConvAttr(&pProv->DtAttrs.dtpa_provider, &pDesc->AttrSelf);
             supdrvVtgConvAttr(&pProv->DtAttrs.dtpa_mod,      &pDesc->AttrModules);
@@ -477,5 +494,5 @@
         {
             PSUPDRVDTPROVIDER   pProvNext;
-            RTMemFree(pProv);
+            supdrvVtgFreeProvider(pProv);
 
             RTSemFastMutexRequest(pDevExt->mtxDTrace);
@@ -503,4 +520,54 @@
 
 /**
+ * Deregisters a provider. 
+ *  
+ * If the provider is still busy, it will be put in the zombie list.
+ *  
+ * @param   pDevExt             The device extension.
+ * @param   pProv               The provider. 
+ *  
+ * @remarks The caller owns mtxDTrace. 
+ */
+static void supdrvVtgDeregister(PSUPDRVDEVEXT pDevExt, PSUPDRVDTPROVIDER pProv)
+{
+    int rc;
+
+    dtrace_invalidate(pProv->idDtProv);
+    rc = dtrace_unregister(pProv->idDtProv);
+    if (!rc)
+    {
+        supdrvVtgFreeProvider(pProv);
+        return;
+    }
+
+    pProv->fZombie = true;
+    RTListAppend(&pDevExt->DtProviderZombieList, &pProv->ListEntry);
+}
+
+
+/**
+ * Processes the zombie list. 
+ *  
+ * @param   pDevExt             The device extension.
+ */
+static void supdrvVtgProcessZombies(PSUPDRVDEVEXT pDevExt)
+{
+    PSUPDRVDTPROVIDER pProv, pProvNext;
+
+    RTSemFastMutexRequest(pDevExt->mtxDTrace);
+    RTListForEachSafe(&pDevExt->DtProviderList, pProv, pProvNext, SUPDRVDTPROVIDER, ListEntry)
+    {
+        int rc = dtrace_unregister(pProv->idDtProv);
+        if (!rc)
+        {
+            RTListNodeRemove(&pProv->ListEntry);
+            supdrvVtgFreeProvider(pProv);
+        }
+    }
+    RTSemFastMutexRelease(pDevExt->mtxDTrace);
+}
+
+
+/**
  * Registers the VTG tracepoint providers of a driver.
  *
@@ -512,9 +579,19 @@
 SUPR0DECL(int) SUPR0VtgRegisterDrv(PSUPDRVSESSION pSession, PVTGOBJHDR pVtgHdr, const char *pszName)
 {
+    int rc;
+
     AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
     AssertPtrReturn(pszName, VERR_INVALID_POINTER);
     AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
-
-    return supdrvVtgRegister(pSession->pDevExt, pVtgHdr, _1M, NULL /*pImage*/, pSession, pszName);
+    AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
+
+    rc = supdrvVtgRegister(pSession->pDevExt, pVtgHdr, _1M, NULL /*pImage*/, pSession, pszName);
+
+    /*
+     * Try unregister zombies while we have a chance.
+     */
+    supdrvVtgProcessZombies(pSession->pDevExt);
+
+    return rc;
 }
 
@@ -531,6 +608,11 @@
     PSUPDRVDEVEXT     pDevExt;
     AssertReturnVoid(SUP_IS_SESSION_VALID(pSession));
+    AssertReturnVoid(pSession->R0Process == NIL_RTR0PROCESS);
 
     pDevExt = pSession->pDevExt;
+
+    /*
+     * Search for providers belonging to this driver session.
+     */
     RTSemFastMutexRequest(pDevExt->mtxDTrace);
     RTListForEachSafe(&pDevExt->DtProviderList, pProv, pProvNext, SUPDRVDTPROVIDER, ListEntry)
@@ -539,13 +621,13 @@
         {
             RTListNodeRemove(&pProv->ListEntry);
-            RTSemFastMutexRelease(pDevExt->mtxDTrace);
-
-            dtrace_unregister(pProv->idDtProv);
-            RTMemFree(pProv);
-
-            RTSemFastMutexRequest(pDevExt->mtxDTrace);
+            supdrvVtgDeregister(pDevExt, pProv);
         }
     }
     RTSemFastMutexRelease(pDevExt->mtxDTrace);
+
+    /*
+     * Try unregister zombies while we have a chance.
+     */
+    supdrvVtgProcessZombies(pDevExt);
 }
 
@@ -566,4 +648,5 @@
     PSUPDRVDEVEXT   pDevExt;
     uintptr_t       cbVtgObj;
+    int             rc;
 
     /* 
@@ -587,5 +670,12 @@
     cbVtgObj = pImage->cbImageBits - cbVtgObj;
 
-    return supdrvVtgRegister(pDevExt, pVtgHdr, cbVtgObj, pImage, NULL, pImage->szName);
+    rc = supdrvVtgRegister(pDevExt, pVtgHdr, cbVtgObj, pImage, NULL, pImage->szName);
+
+    /*
+     * Try unregister zombies while we have a chance.
+     */
+    supdrvVtgProcessZombies(pDevExt);
+
+    return rc;
 }
 
@@ -610,13 +700,13 @@
         {
             RTListNodeRemove(&pProv->ListEntry);
-            RTSemFastMutexRelease(pDevExt->mtxDTrace);
-
-            dtrace_unregister(pProv->idDtProv);
-            RTMemFree(pProv);
-
-            RTSemFastMutexRequest(pDevExt->mtxDTrace);
+            supdrvVtgDeregister(pDevExt, pProv);
         }
     }
     RTSemFastMutexRelease(pDevExt->mtxDTrace);
+
+    /*
+     * Try unregister zombies while we have a chance.
+     */
+    supdrvVtgProcessZombies(pDevExt);
 }
 
@@ -643,4 +733,5 @@
 #endif
         RTListInit(&pDevExt->DtProviderList);
+        RTListInit(&pDevExt->DtProviderZombieList);
         rc = supdrvVtgRegister(pDevExt, &g_VTGObjHeader, _1M, NULL /*pImage*/, NULL /*pSession*/, "vboxdrv");
         if (RT_SUCCESS(rc))
@@ -659,7 +750,8 @@
  * @param   pDevExt             The device extension structure.
  */
-int VBOXCALL supdrvVtgTerm(PSUPDRVDEVEXT pDevExt)
+void VBOXCALL supdrvVtgTerm(PSUPDRVDEVEXT pDevExt)
 {
     PSUPDRVDTPROVIDER pProv, pProvNext;
+    uint32_t i;
 
     /*
@@ -670,15 +762,39 @@
     {
         RTListNodeRemove(&pProv->ListEntry);
+        supdrvVtgDeregister(pDevExt, pProv);
+    }
+    RTSemFastMutexRelease(pDevExt->mtxDTrace);
+
+    /*
+     * Try unregister zombies now, sleep on busy ones.
+     */
+    for (i = 0; ; i++)
+    {
+        bool fEmpty;
+
+        RTSemFastMutexRequest(pDevExt->mtxDTrace);
+        RTListForEachSafe(&pDevExt->DtProviderList, pProv, pProvNext, SUPDRVDTPROVIDER, ListEntry)
+        {
+            int rc = dtrace_unregister(pProv->idDtProv);
+            if (!rc)
+            {
+                RTListNodeRemove(&pProv->ListEntry);
+                supdrvVtgFreeProvider(pProv);
+            }
+            else if (!(i & 0xf))
+                SUPR0Printf("supdrvVtgTerm: Waiting on busy provider %p\n", pProv->idDtProv);
+        }
+
+        fEmpty = RTListIsEmpty(&pDevExt->DtProviderZombieList);
         RTSemFastMutexRelease(pDevExt->mtxDTrace);
-
-        dtrace_unregister(pProv->idDtProv);
-        RTMemFree(pProv);
-
-        RTSemFastMutexRequest(pDevExt->mtxDTrace);
-    }
-    RTSemFastMutexRelease(pDevExt->mtxDTrace);
+        if (fEmpty)
+            break;
+
+        /* Delay...*/
+        RTThreadSleep(1000);
+    }
+
     RTSemFastMutexDestroy(pDevExt->mtxDTrace);
     pDevExt->mtxDTrace = NIL_RTSEMFASTMUTEX;
-    return VINF_SUCCESS;
 }
 
@@ -690,5 +806,5 @@
 {
     PSUPDRVDTPROVIDER   pProv      = (PSUPDRVDTPROVIDER)pvProv;
-    uint16_t const      idxProv    = (uint16_t)(&pProv->pHdr->paProviders[0] - pProv->pDesc);
+    uint16_t            idxProv;
     PVTGPROBELOC        pProbeLoc;
     PVTGPROBELOC        pProbeLocEnd;
@@ -698,4 +814,7 @@
     if (pDtProbeDesc)
         return;  /* We don't generate probes, so never mind these requests. */
+
+    if (pProv->fZombie)
+        return;
 
     if (pProv->cProvidedProbes >= pProv->pDesc->cProbes)
@@ -712,4 +831,5 @@
       * this provider.
       */
+     idxProv      = (uint16_t)(&pProv->pHdr->paProviders[0] - pProv->pDesc);
      pProbeLoc    = pProv->pHdr->paProbLocs;
      pProbeLocEnd = pProv->pHdr->paProbLocsEnd;
@@ -796,15 +916,17 @@
 {
     PSUPDRVDTPROVIDER   pProv      = (PSUPDRVDTPROVIDER)pvProv;
-    PVTGPROBELOC        pProbeLoc  = (PVTGPROBELOC)pvProbe;
-    PVTGDESCPROBE       pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
-
-    if (!pProbeLoc->fEnabled)
-    {
-        pProbeLoc->fEnabled = 1;
-        if (ASMAtomicIncU32(&pProbeDesc->u32User) == 1)
-            pProv->pHdr->pafProbeEnabled[pProbeDesc->idxEnabled] = 1;
-    }
-
-    NOREF(pvProv);
+    if (!pProv->fZombie)
+    {
+        PVTGPROBELOC    pProbeLoc  = (PVTGPROBELOC)pvProbe;
+        PVTGDESCPROBE   pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
+
+        if (!pProbeLoc->fEnabled)
+        {
+            pProbeLoc->fEnabled = 1;
+            if (ASMAtomicIncU32(&pProbeDesc->u32User) == 1)
+                pProv->pHdr->pafProbeEnabled[pProbeDesc->idxEnabled] = 1;
+        }
+    }
+
     return 0;
 }
@@ -817,15 +939,16 @@
 {
     PSUPDRVDTPROVIDER   pProv      = (PSUPDRVDTPROVIDER)pvProv;
-    PVTGPROBELOC        pProbeLoc  = (PVTGPROBELOC)pvProbe;
-    PVTGDESCPROBE       pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
-
-    if (pProbeLoc->fEnabled)
-    {
-        pProbeLoc->fEnabled = 0;
-        if (ASMAtomicDecU32(&pProbeDesc->u32User) == 0)
-            pProv->pHdr->pafProbeEnabled[pProbeDesc->idxEnabled] = 1;
-    }
-
-    NOREF(pvProv);
+    if (!pProv->fZombie)
+    {
+        PVTGPROBELOC    pProbeLoc  = (PVTGPROBELOC)pvProbe;
+        PVTGDESCPROBE   pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
+
+        if (pProbeLoc->fEnabled)
+        {
+            pProbeLoc->fEnabled = 0;
+            if (ASMAtomicDecU32(&pProbeDesc->u32User) == 0)
+                pProv->pHdr->pafProbeEnabled[pProbeDesc->idxEnabled] = 1;
+        }
+    }
 }
 
@@ -838,23 +961,27 @@
 {
     PSUPDRVDTPROVIDER   pProv      = (PSUPDRVDTPROVIDER)pvProv;
-    PVTGPROBELOC        pProbeLoc  = (PVTGPROBELOC)pvProbe;
-    PVTGDESCPROBE       pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
-    PVTGDESCARGLIST     pArgList   = (PVTGDESCARGLIST)((uintptr_t)pProv->pHdr->paArgLists + pProbeDesc->offArgList);
-
-    Assert(pProbeDesc->offArgList < pProv->pHdr->cbArgLists);
-    if (pArgList->cArgs > pArgDesc->dtargd_ndx)
-    {
-        const char *pszType = supdrvVtgGetString(pProv->pHdr, pArgList->aArgs[pArgDesc->dtargd_ndx].offType);
-        size_t      cchType = strlen(pszType);
-        if (cchType < sizeof(pArgDesc->dtargd_native))
-        {
-            memcpy(pArgDesc->dtargd_native, pszType, cchType + 1);
-            /** @todo mapping */
-        }
-        else
-            pArgDesc->dtargd_ndx = DTRACE_ARGNONE;
-    }
-    else
-        pArgDesc->dtargd_ndx = DTRACE_ARGNONE;
+    unsigned            uArg       = pArgDesc->dtargd_ndx; 
+
+    if (!pProv->fZombie)
+    {
+        PVTGPROBELOC    pProbeLoc  = (PVTGPROBELOC)pvProbe;
+        PVTGDESCPROBE   pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
+        PVTGDESCARGLIST pArgList   = (PVTGDESCARGLIST)((uintptr_t)pProv->pHdr->paArgLists + pProbeDesc->offArgList);
+
+        Assert(pProbeDesc->offArgList < pProv->pHdr->cbArgLists);
+        if (pArgList->cArgs > uArg)
+        {
+            const char *pszType = supdrvVtgGetString(pProv->pHdr, pArgList->aArgs[uArg].offType);
+            size_t      cchType = strlen(pszType);
+            if (cchType < sizeof(pArgDesc->dtargd_native))
+            {
+                memcpy(pArgDesc->dtargd_native, pszType, cchType + 1);
+                /** @todo mapping */
+                return;
+            }
+        }
+    }
+
+    pArgDesc->dtargd_ndx = DTRACE_ARGNONE;
 }
 
@@ -878,9 +1005,11 @@
 {
     PSUPDRVDTPROVIDER   pProv      = (PSUPDRVDTPROVIDER)pvProv;
-    PVTGPROBELOC        pProbeLoc  = (PVTGPROBELOC)pvProbe;
-
-    Assert(!pProbeLoc->fEnabled);
-    Assert(pProbeLoc->idProbe == idProbe); NOREF(idProbe);
-    pProbeLoc->idProbe = UINT32_MAX;
+    if (!pProv->fZombie)
+    {
+        PVTGPROBELOC    pProbeLoc  = (PVTGPROBELOC)pvProbe;
+        Assert(!pProbeLoc->fEnabled);
+        Assert(pProbeLoc->idProbe == idProbe); NOREF(idProbe);
+        pProbeLoc->idProbe = UINT32_MAX;
+    }
     pProv->cProvidedProbes--;
 }
Index: /trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h	(revision 40674)
+++ /trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h	(revision 40675)
@@ -542,4 +542,6 @@
     /** List of DTrace providers (SUPDRVDTPROVIDER). */
     RTLISTANCHOR                    DtProviderList;
+    /** List of zombie DTrace providers (SUPDRVDTPROVIDER). */
+    RTLISTANCHOR                    DtProviderZombieList;
 #endif
 
@@ -635,5 +637,5 @@
 #ifdef VBOX_WITH_DTRACE_R0DRV
 int  VBOXCALL   supdrvVtgInit(PSUPDRVDEVEXT pDevExt, PSUPFUNC pVtgFireProbe);
-int  VBOXCALL   supdrvVtgTerm(PSUPDRVDEVEXT pDevExt);
+void VBOXCALL   supdrvVtgTerm(PSUPDRVDEVEXT pDevExt);
 void VBOXCALL   supdrvVtgModuleUnloading(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage);
 #endif
