Changeset 92200 in vbox for trunk/src/VBox/VMM/VMMR0/GVMMR0.cpp
- Timestamp:
- Nov 3, 2021 9:46:36 PM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR0/GVMMR0.cpp
r91287 r92200 1592 1592 1593 1593 /** 1594 * Registers the caller as a given worker thread. 1595 * 1596 * This enables the thread to operate critical sections in ring-0. 1597 * 1598 * @returns VBox status code. 1599 * @param pGVM The global (ring-0) VM structure. 1600 * @param enmWorker The worker thread this is supposed to be. 1601 * @param hNativeSelfR3 The ring-3 native self of the caller. 1602 */ 1603 GVMMR0DECL(int) GVMMR0RegisterWorkerThread(PGVM pGVM, GVMMWORKERTHREAD enmWorker, RTNATIVETHREAD hNativeSelfR3) 1604 { 1605 /* 1606 * Validate input. 1607 */ 1608 AssertReturn(enmWorker > GVMMWORKERTHREAD_INVALID && enmWorker < GVMMWORKERTHREAD_END, VERR_INVALID_PARAMETER); 1609 AssertReturn(hNativeSelfR3 != NIL_RTNATIVETHREAD, VERR_INVALID_HANDLE); 1610 RTNATIVETHREAD const hNativeSelf = RTThreadNativeSelf(); 1611 AssertReturn(hNativeSelf != NIL_RTNATIVETHREAD, VERR_INTERNAL_ERROR_3); 1612 PGVMM pGVMM; 1613 int rc = gvmmR0ByGVM(pGVM, &pGVMM, false /*fTakeUsedLock*/); 1614 AssertRCReturn(rc, rc); 1615 AssertReturn(pGVM->enmVMState < VMSTATE_DESTROYING, VERR_VM_INVALID_VM_STATE); 1616 1617 /* 1618 * Grab the big lock and check the VM state again. 1619 */ 1620 uint32_t const hSelf = pGVM->hSelf; 1621 gvmmR0CreateDestroyLock(pGVMM); /** @todo per-VM lock? */ 1622 if ( hSelf < RT_ELEMENTS(pGVMM->aHandles) 1623 && pGVMM->aHandles[hSelf].pvObj != NULL 1624 && pGVMM->aHandles[hSelf].pGVM == pGVM 1625 && pGVMM->aHandles[hSelf].ProcId == RTProcSelf()) 1626 { 1627 if (pGVM->enmVMState < VMSTATE_DESTROYING) 1628 { 1629 /* 1630 * Check that the thread isn't an EMT or serving in some other worker capacity. 1631 */ 1632 for (VMCPUID iCpu = 0; iCpu < pGVM->cCpus; iCpu++) 1633 AssertBreakStmt(pGVM->aCpus[iCpu].hEMT != hNativeSelf, rc = VERR_INVALID_PARAMETER); 1634 for (size_t idx = 0; idx < RT_ELEMENTS(pGVM->gvmm.s.aWorkerThreads); idx++) 1635 AssertBreakStmt(idx != (size_t)enmWorker && pGVM->gvmm.s.aWorkerThreads[enmWorker].hNativeThread != hNativeSelf, 1636 rc = VERR_INVALID_PARAMETER); 1637 if (RT_SUCCESS(rc)) 1638 { 1639 /* 1640 * Do the registration. 1641 */ 1642 if ( pGVM->gvmm.s.aWorkerThreads[enmWorker].hNativeThread == NIL_RTNATIVETHREAD 1643 && pGVM->gvmm.s.aWorkerThreads[enmWorker].hNativeThreadR3 == NIL_RTNATIVETHREAD) 1644 { 1645 pGVM->gvmm.s.aWorkerThreads[enmWorker].hNativeThread = hNativeSelf; 1646 pGVM->gvmm.s.aWorkerThreads[enmWorker].hNativeThreadR3 = hNativeSelfR3; 1647 rc = VINF_SUCCESS; 1648 } 1649 else if ( pGVM->gvmm.s.aWorkerThreads[enmWorker].hNativeThread == hNativeSelf 1650 && pGVM->gvmm.s.aWorkerThreads[enmWorker].hNativeThreadR3 == hNativeSelfR3) 1651 rc = VERR_ALREADY_EXISTS; 1652 else 1653 rc = VERR_RESOURCE_BUSY; 1654 } 1655 } 1656 else 1657 rc = VERR_VM_INVALID_VM_STATE; 1658 } 1659 else 1660 rc = VERR_INVALID_VM_HANDLE; 1661 gvmmR0CreateDestroyUnlock(pGVMM); 1662 return rc; 1663 } 1664 1665 1666 /** 1667 * Deregisters a workinger thread (caller). 1668 * 1669 * The worker thread cannot be re-created and re-registered, instead the given 1670 * @a enmWorker slot becomes invalid. 1671 * 1672 * @returns VBox status code. 1673 * @param pGVM The global (ring-0) VM structure. 1674 * @param enmWorker The worker thread this is supposed to be. 1675 */ 1676 GVMMR0DECL(int) GVMMR0DeregisterWorkerThread(PGVM pGVM, GVMMWORKERTHREAD enmWorker) 1677 { 1678 /* 1679 * Validate input. 1680 */ 1681 AssertReturn(enmWorker > GVMMWORKERTHREAD_INVALID && enmWorker < GVMMWORKERTHREAD_END, VERR_INVALID_PARAMETER); 1682 RTNATIVETHREAD const hNativeThread = RTThreadNativeSelf(); 1683 AssertReturn(hNativeThread != NIL_RTNATIVETHREAD, VERR_INTERNAL_ERROR_3); 1684 PGVMM pGVMM; 1685 int rc = gvmmR0ByGVM(pGVM, &pGVMM, false /*fTakeUsedLock*/); 1686 AssertRCReturn(rc, rc); 1687 1688 /* 1689 * Grab the big lock and check the VM state again. 1690 */ 1691 uint32_t const hSelf = pGVM->hSelf; 1692 gvmmR0CreateDestroyLock(pGVMM); /** @todo per-VM lock? */ 1693 if ( hSelf < RT_ELEMENTS(pGVMM->aHandles) 1694 && pGVMM->aHandles[hSelf].pvObj != NULL 1695 && pGVMM->aHandles[hSelf].pGVM == pGVM 1696 && pGVMM->aHandles[hSelf].ProcId == RTProcSelf()) 1697 { 1698 /* 1699 * Do the deregistration. 1700 * This will prevent any other threads register as the worker later. 1701 */ 1702 if (pGVM->gvmm.s.aWorkerThreads[enmWorker].hNativeThread == hNativeThread) 1703 { 1704 pGVM->gvmm.s.aWorkerThreads[enmWorker].hNativeThread = GVMM_RTNATIVETHREAD_DESTROYED; 1705 pGVM->gvmm.s.aWorkerThreads[enmWorker].hNativeThreadR3 = GVMM_RTNATIVETHREAD_DESTROYED; 1706 rc = VINF_SUCCESS; 1707 } 1708 else if ( pGVM->gvmm.s.aWorkerThreads[enmWorker].hNativeThread == GVMM_RTNATIVETHREAD_DESTROYED 1709 && pGVM->gvmm.s.aWorkerThreads[enmWorker].hNativeThreadR3 == GVMM_RTNATIVETHREAD_DESTROYED) 1710 rc = VINF_SUCCESS; 1711 else 1712 rc = VERR_NOT_OWNER; 1713 } 1714 else 1715 rc = VERR_INVALID_VM_HANDLE; 1716 gvmmR0CreateDestroyUnlock(pGVMM); 1717 return rc; 1718 } 1719 1720 1721 /** 1594 1722 * Lookup a GVM structure by its handle. 1595 1723 * … … 1925 2053 /* 1926 2054 * Find the matching hash table entry. 2055 * See similar code in GVMMR0GetRing3ThreadForSelf. 1927 2056 */ 1928 2057 uint32_t idxHash = GVMM_EMT_HASH_1(hEMT); … … 1963 2092 Assert(pGVCpu->gvmm.s.idxEmtHash == idxHash); 1964 2093 return pGVCpu; 2094 } 2095 2096 2097 /** 2098 * Get the native ring-3 thread handle for the caller. 2099 * 2100 * This works for EMTs and registered workers. 2101 * 2102 * @returns ring-3 native thread handle or NIL_RTNATIVETHREAD. 2103 * @param pGVM The global (ring-0) VM structure. 2104 */ 2105 GVMMR0DECL(RTNATIVETHREAD) GVMMR0GetRing3ThreadForSelf(PGVM pGVM) 2106 { 2107 /* 2108 * Validate input. 2109 */ 2110 AssertPtr(pGVM); 2111 AssertReturn(pGVM->u32Magic == GVM_MAGIC, NIL_RTNATIVETHREAD); 2112 RTNATIVETHREAD const hNativeSelf = RTThreadNativeSelf(); 2113 AssertReturn(hNativeSelf != NIL_RTNATIVETHREAD, NIL_RTNATIVETHREAD); 2114 2115 /* 2116 * Find the matching hash table entry. 2117 * See similar code in GVMMR0GetGVCpuByGVMandEMT. 2118 */ 2119 uint32_t idxHash = GVMM_EMT_HASH_1(hNativeSelf); 2120 if (pGVM->gvmm.s.aEmtHash[idxHash].hNativeEmt == hNativeSelf) 2121 { /* likely */ } 2122 else 2123 { 2124 #ifdef VBOX_STRICT 2125 unsigned cCollisions = 0; 2126 #endif 2127 uint32_t const idxHash2 = GVMM_EMT_HASH_2(hNativeSelf); 2128 for (;;) 2129 { 2130 Assert(cCollisions++ < GVMM_EMT_HASH_SIZE); 2131 idxHash = (idxHash + idxHash2) % GVMM_EMT_HASH_SIZE; 2132 if (pGVM->gvmm.s.aEmtHash[idxHash].hNativeEmt == hNativeSelf) 2133 break; 2134 if (pGVM->gvmm.s.aEmtHash[idxHash].hNativeEmt == NIL_RTNATIVETHREAD) 2135 { 2136 #ifdef VBOX_STRICT 2137 uint32_t idxCpu = pGVM->cCpus; 2138 AssertStmt(idxCpu < VMM_MAX_CPU_COUNT, idxCpu = VMM_MAX_CPU_COUNT); 2139 while (idxCpu-- > 0) 2140 Assert(pGVM->aCpus[idxCpu].hNativeThreadR0 != hNativeSelf); 2141 #endif 2142 2143 /* 2144 * Not an EMT, so see if it's a worker thread. 2145 */ 2146 size_t idx = RT_ELEMENTS(pGVM->gvmm.s.aWorkerThreads); 2147 while (--idx > GVMMWORKERTHREAD_INVALID) 2148 if (pGVM->gvmm.s.aWorkerThreads[idx].hNativeThread == hNativeSelf) 2149 return pGVM->gvmm.s.aWorkerThreads[idx].hNativeThreadR3; 2150 2151 return NIL_RTNATIVETHREAD; 2152 } 2153 } 2154 } 2155 2156 /* 2157 * Validate the VCpu number and translate it into a pointer. 2158 */ 2159 VMCPUID const idCpu = pGVM->gvmm.s.aEmtHash[idxHash].idVCpu; 2160 AssertReturn(idCpu < pGVM->cCpus, NIL_RTNATIVETHREAD); 2161 PGVMCPU pGVCpu = &pGVM->aCpus[idCpu]; 2162 Assert(pGVCpu->hNativeThreadR0 == hNativeSelf); 2163 Assert(pGVCpu->gvmm.s.idxEmtHash == idxHash); 2164 return pGVCpu->hNativeThread; 1965 2165 } 1966 2166
Note:
See TracChangeset
for help on using the changeset viewer.