- Timestamp:
- May 20, 2021 9:52:42 PM (4 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/vmm/pdmaudioifs.h
r89184 r89208 231 231 232 232 #include <iprt/assertcompile.h> 233 #include <iprt/critsect.h> 233 234 #include <iprt/circbuf.h> 234 235 #include <iprt/list.h> … … 995 996 typedef struct PDMAUDIOSTREAM 996 997 { 998 /** Critical section protecting the stream. 999 * 1000 * When not otherwise stated, DrvAudio will enter this before calling the 1001 * backend. The backend and device/mixer can normally safely enter it prior to 1002 * a DrvAudio call, however not to pfnStreamDestroy, pfnStreamRelease or 1003 * anything that may access the stream list. 1004 * 1005 * @note Lock ordering: 1006 * - After DRVAUDIO::CritSectGlobals. 1007 * - Before DRVAUDIO::CritSectHotPlug. */ 1008 RTCRITSECT CritSect; 997 1009 /** Magic value (PDMAUDIOSTREAM_MAGIC). */ 998 1010 uint32_t uMagic; … … 1017 1029 1018 1030 /** Magic value for PDMAUDIOSTREAM. */ 1019 #define PDMAUDIOSTREAM_MAGIC PDM_VERSION_MAKE(0xa0d3, 4, 0)1031 #define PDMAUDIOSTREAM_MAGIC PDM_VERSION_MAKE(0xa0d3, 5, 0) 1020 1032 1021 1033 … … 1238 1250 1239 1251 /** PDMIAUDIOCONNECTOR interface ID. */ 1240 #define PDMIAUDIOCONNECTOR_IID " 2c2bdfcd-7a2b-4739-9663-07ee9e8fe079"1252 #define PDMIAUDIOCONNECTOR_IID "04ad443a-d860-443a-afc9-98bbad4b1341" 1241 1253 1242 1254 … … 1420 1432 * 1421 1433 * @param pInterface Pointer to this interface. 1422 * @param pStream Pointer to audio stream .1434 * @param pStream Pointer to audio stream (locked). 1423 1435 * @param pvUser Backend specific parameter from the call to 1424 1436 * PDMIHOSTAUDIOPORT::pfnNotifyDeviceChanged. … … 1516 1528 1517 1529 /** PDMIHOSTAUDIO interface ID. */ 1518 #define PDMIHOSTAUDIO_IID " a5650399-be78-4e82-8115-e34a4450378c"1530 #define PDMIHOSTAUDIO_IID "8c68a5a9-6c46-43c2-9d4e-e1bd13d2b97d" 1519 1531 1520 1532 … … 1601 1613 1602 1614 /** PDMIHOSTAUDIOPORT interface ID. */ 1603 #define PDMIHOSTAUDIOPORT_IID "c 752404b-1ccb-4fc0-aa60-eb76ae130e0f"1615 #define PDMIHOSTAUDIOPORT_IID "cd006383-7be1-4dbe-a69e-21236413cf30" 1604 1616 1605 1617 /** @} */ -
trunk/src/VBox/Devices/Audio/DrvAudio.cpp
r89191 r89208 318 318 typedef struct DRVAUDIO 319 319 { 320 /** Read/Write critical section for guarding changes to pHostDrvAudio and 321 * BackendCfg during deteach/attach. Mostly taken in shared mode. 322 * @note Locking order: Must be entered after CritSectGlobals. 323 * @note Locking order: Must be entered after PDMAUDIOSTREAM::CritSect. */ 324 RTCRITSECTRW CritSectHotPlug; 320 325 /** Critical section for protecting: 321 326 * - LstStreams 327 * - cStreams 322 328 * - In.fEnabled 323 329 * - In.cStreamsFree 324 330 * - Out.fEnabled 325 331 * - Out.cStreamsFree 326 */ 327 RTCRITSECT CritSect; 332 * @note Locking order: Must be entered before PDMAUDIOSTREAM::CritSect. 333 * @note Locking order: Must be entered before CritSectHotPlug. */ 334 RTCRITSECTRW CritSectGlobals; 328 335 /** List of audio streams (DRVAUDIOSTREAM). */ 329 336 RTLISTANCHOR LstStreams; 337 /** Number of streams in the list. */ 338 size_t cStreams; 330 339 struct 331 340 { … … 402 411 static uint32_t drvAudioStreamReleaseInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, bool fMayDestroy); 403 412 static void drvAudioStreamResetInternal(PDRVAUDIOSTREAM pStreamEx); 404 static int drvAudioStreamIterateInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx);405 413 406 414 … … 693 701 static DECLCALLBACK(int) drvAudioDevicesEnumerateInternal(PDRVAUDIO pThis, bool fLog, PPDMAUDIOHOSTENUM pDevEnum) 694 702 { 695 AssertReturn(!RTCritSectIsOwner(&pThis->CritSect), VERR_WRONG_ORDER);703 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 696 704 697 705 int rc; … … 743 751 } 744 752 753 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 745 754 LogFunc(("Returning %Rrc\n", rc)); 746 755 return rc; … … 776 785 * Grab the driver wide lock and check it. Ignore call if no change. 777 786 */ 778 int rc = RTCritSect Enter(&pThis->CritSect);787 int rc = RTCritSectRwEnterExcl(&pThis->CritSectGlobals); 779 788 AssertRCReturn(rc, rc); 780 789 … … 866 875 } 867 876 868 RTCritSect Leave(&pThis->CritSect);877 RTCritSectRwLeaveExcl(&pThis->CritSectGlobals); 869 878 LogFlowFuncLeaveRC(rc); 870 879 return rc; … … 879 888 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector); 880 889 AssertPtr(pThis); 881 int rc = RTCritSect Enter(&pThis->CritSect);890 int rc = RTCritSectRwEnterShared(&pThis->CritSectGlobals); 882 891 AssertRCReturn(rc, false); 883 892 … … 890 899 AssertFailedStmt(fEnabled = false); 891 900 892 RTCritSect Leave(&pThis->CritSect);901 RTCritSectRwLeaveShared(&pThis->CritSectGlobals); 893 902 return fEnabled; 894 903 } … … 903 912 AssertPtr(pThis); 904 913 AssertPtrReturn(pCfg, VERR_INVALID_POINTER); 905 int rc = RTCritSect Enter(&pThis->CritSect);914 int rc = RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 906 915 AssertRCReturn(rc, rc); 907 916 908 917 if (pThis->pHostDrvAudio) 909 { 910 if (pThis->pHostDrvAudio->pfnGetConfig) 911 rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, pCfg); 912 else 913 rc = VERR_NOT_SUPPORTED; 914 } 918 rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, pCfg); 915 919 else 916 920 rc = VERR_PDM_NO_ATTACHED_DRIVER; 917 921 918 RTCritSect Leave(&pThis->CritSect);922 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 919 923 LogFlowFuncLeaveRC(rc); 920 924 return rc; … … 929 933 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector); 930 934 AssertPtr(pThis); 931 int rc = RTCritSect Enter(&pThis->CritSect);935 int rc = RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 932 936 AssertRCReturn(rc, PDMAUDIOBACKENDSTS_UNKNOWN); 933 937 … … 943 947 fBackendStatus = PDMAUDIOBACKENDSTS_NOT_ATTACHED; 944 948 945 RTCritSect Leave(&pThis->CritSect);949 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 946 950 LogFlowFunc(("LEAVE - %#x\n", fBackendStatus)); 947 951 return fBackendStatus; … … 966 970 pStreamEx->pBackend = NULL; 967 971 pStreamEx->uMagic = DRVAUDIOSTREAM_MAGIC_DEAD; 972 973 RTCritSectDelete(&pStreamEx->Core.CritSect); 968 974 969 975 RTMemFree(pStreamEx); … … 1129 1135 * PDMAUDIOBACKEND_F_ASYNC_HINT is in effect. 1130 1136 */ 1131 static DECLCALLBACK(void) drvAudioStreamConfigHintWorker(P PDMIHOSTAUDIO pHostDrvAudio, PPDMAUDIOSTREAMCFG pCfg)1132 { 1133 LogFlowFunc(("p HostDrvAudio=%p pCfg=%p\n", pHostDrvAudio, pCfg));1137 static DECLCALLBACK(void) drvAudioStreamConfigHintWorker(PDRVAUDIO pThis, PPDMAUDIOSTREAMCFG pCfg) 1138 { 1139 LogFlowFunc(("pThis=%p pCfg=%p\n", pThis, pCfg)); 1134 1140 AssertPtrReturnVoid(pCfg); 1135 AssertPtrReturnVoid(pHostDrvAudio); 1136 AssertPtrReturnVoid(pHostDrvAudio->pfnStreamConfigHint); 1137 1138 pHostDrvAudio->pfnStreamConfigHint(pHostDrvAudio, pCfg); 1141 int rc = RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 1142 AssertRCReturnVoid(rc); 1143 1144 PPDMIHOSTAUDIO const pHostDrvAudio = pThis->pHostDrvAudio; 1145 if (pHostDrvAudio) 1146 { 1147 AssertPtr(pHostDrvAudio->pfnStreamConfigHint); 1148 if (pHostDrvAudio->pfnStreamConfigHint) 1149 pHostDrvAudio->pfnStreamConfigHint(pHostDrvAudio, pCfg); 1150 } 1139 1151 PDMAudioStrmCfgFree(pCfg); 1152 1153 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 1140 1154 LogFlowFunc(("returns\n")); 1141 1155 } … … 1150 1164 AssertReturnVoid(pCfg->enmDir == PDMAUDIODIR_IN || pCfg->enmDir == PDMAUDIODIR_OUT); 1151 1165 1152 int rc = RTCritSect Enter(&pThis->CritSect); /** @todo Reconsider the locking for DrvAudio */1166 int rc = RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 1153 1167 AssertRCReturnVoid(rc); 1154 1168 … … 1175 1189 if (pDupCfg) 1176 1190 { 1177 rc = RTReqPoolCallVoidNoWait(pThis->hReqPool, (PFNRT)drvAudioStreamConfigHintWorker, 1178 2, pThis->pHostDrvAudio, pDupCfg); 1191 rc = RTReqPoolCallVoidNoWait(pThis->hReqPool, (PFNRT)drvAudioStreamConfigHintWorker, 2, pThis, pDupCfg); 1179 1192 if (RT_SUCCESS(rc)) 1180 1193 LogFlowFunc(("Asynchronous call running on worker thread.\n")); … … 1196 1209 LogFlowFunc(("Ignoring hint because backend has no pfnStreamConfigHint method.\n")); 1197 1210 1198 RTCritSect Leave(&pThis->CritSect);1211 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 1199 1212 } 1200 1213 … … 1205 1218 * 1206 1219 * Used by async init and re-init. 1220 * 1221 * @note Is sometimes called w/o having entered DRVAUDIO::CritSectHotPlug. 1222 * Caller must however own the stream critsect. 1207 1223 */ 1208 1224 static int drvAudioStreamUpdateBackendOnStatus(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, const char *pszWhen) … … 1238 1254 LogFlow(("pThis=%p pStreamEx=%p (%s)\n", pThis, pStreamEx, pStreamEx->Core.szName)); 1239 1255 1256 int rc = RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 1257 AssertRCReturnVoid(rc); 1258 1240 1259 /* 1241 1260 * Do the init job. 1242 * 1243 * This critsect entering and leaving here isn't really necessary, 1244 * but well, I'm a bit paranoid, so sue me. 1245 */ 1246 RTCritSectEnter(&pThis->CritSect); 1261 */ 1262 bool fDestroyed; 1247 1263 PPDMIHOSTAUDIO pIHostDrvAudio = pThis->pHostDrvAudio; 1248 RTCritSectLeave(&pThis->CritSect);1249 1264 AssertPtr(pIHostDrvAudio); 1250 int rc;1251 bool fDestroyed;1252 1265 if (pIHostDrvAudio && pIHostDrvAudio->pfnStreamInitAsync) 1253 1266 { … … 1262 1275 } 1263 1276 1277 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 1278 RTCritSectEnter(&pStreamEx->Core.CritSect); 1279 1264 1280 /* 1265 1281 * On success, update the backend on the stream status and mark it ready for business. 1266 1282 */ 1267 RTCritSectEnter(&pThis->CritSect);1268 1283 if (RT_SUCCESS(rc) && !fDestroyed) 1269 1284 { 1285 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 1270 1286 1271 1287 /* … … 1310 1326 */ 1311 1327 pStreamEx->enmLastBackendState = drvAudioStreamGetBackendState(pThis, pStreamEx); 1328 1329 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 1312 1330 } 1313 1331 /* … … 1329 1347 } 1330 1348 1331 RTCritSectLeave(&p This->CritSect);1349 RTCritSectLeave(&pStreamEx->Core.CritSect); 1332 1350 1333 1351 /* … … 1386 1404 * Call the host driver to create the stream. 1387 1405 */ 1388 AssertLogRelMsgReturn(RT_VALID_PTR(pThis->pHostDrvAudio), ("Audio: %p\n", pThis->pHostDrvAudio), VERR_PDM_NO_ATTACHED_DRIVER); 1389 rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pStreamEx->pBackend, pCfgReq, pCfgAcq); 1406 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 1407 1408 AssertLogRelMsgStmt(RT_VALID_PTR(pThis->pHostDrvAudio), 1409 ("Audio: %p\n", pThis->pHostDrvAudio), rc = VERR_PDM_NO_ATTACHED_DRIVER); 1390 1410 if (RT_SUCCESS(rc)) 1411 AssertLogRelMsgStmt(pStreamEx->Core.cbBackend == pThis->BackendCfg.cbStream, 1412 ("Audio: Backend changed? cbBackend changed from %#x to %#x\n", 1413 pStreamEx->Core.cbBackend, pThis->BackendCfg.cbStream), 1414 rc = VERR_STATE_CHANGED); 1415 if (RT_SUCCESS(rc)) 1416 rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pStreamEx->pBackend, pCfgReq, pCfgAcq); 1417 if (RT_SUCCESS(rc)) 1391 1418 { 1392 1419 pStreamEx->enmLastBackendState = drvAudioStreamGetBackendState(pThis, pStreamEx); 1420 1421 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 1393 1422 1394 1423 AssertLogRelReturn(pStreamEx->pBackend->uMagic == PDMAUDIOBACKENDSTREAM_MAGIC, VERR_INTERNAL_ERROR_3); … … 1402 1431 else 1403 1432 { 1433 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 1404 1434 if (rc == VERR_NOT_SUPPORTED) 1405 1435 LogRel2(("Audio: Creating stream '%s' in backend not supported\n", pStreamEx->Core.szName)); … … 1731 1761 1732 1762 /* 1733 * Lock the whole driver instance.1734 */ 1735 int rc = RTCritSect Enter(&pThis->CritSect);1763 * Grab a free stream count now. 1764 */ 1765 int rc = RTCritSectRwEnterExcl(&pThis->CritSectGlobals); 1736 1766 AssertRCReturn(rc, rc); 1737 1767 1738 /* 1739 * Check that we have free streams in the backend and get the 1740 * size of the backend specific stream data. 1741 */ 1742 uint32_t *pcFreeStreams; 1743 if (pCfgHost->enmDir == PDMAUDIODIR_IN) 1744 { 1745 if (!pThis->In.cStreamsFree) 1746 { 1747 LogFlowFunc(("Maximum number of host input streams reached\n")); 1748 rc = VERR_AUDIO_NO_FREE_INPUT_STREAMS; 1749 } 1750 pcFreeStreams = &pThis->In.cStreamsFree; 1751 } 1752 else /* Out */ 1753 { 1754 if (!pThis->Out.cStreamsFree) 1755 { 1756 LogFlowFunc(("Maximum number of host output streams reached\n")); 1757 rc = VERR_AUDIO_NO_FREE_OUTPUT_STREAMS; 1758 } 1759 pcFreeStreams = &pThis->Out.cStreamsFree; 1760 } 1768 uint32_t * const pcFreeStreams = pCfgHost->enmDir == PDMAUDIODIR_IN ? &pThis->In.cStreamsFree : &pThis->Out.cStreamsFree; 1769 if (*pcFreeStreams > 0) 1770 *pcFreeStreams -= 1; 1771 else 1772 { 1773 RTCritSectRwLeaveExcl(&pThis->CritSectGlobals); 1774 LogFlowFunc(("Maximum number of host %s streams reached\n", PDMAudioDirGetName(pCfgHost->enmDir) )); 1775 return pCfgHost->enmDir == PDMAUDIODIR_IN ? VERR_AUDIO_NO_FREE_INPUT_STREAMS : VERR_AUDIO_NO_FREE_OUTPUT_STREAMS; 1776 } 1777 1778 RTCritSectRwLeaveExcl(&pThis->CritSectGlobals); 1779 1780 /* 1781 * Get and check the backend size. 1782 * 1783 * Since we'll have to leave the hot-plug lock before we call the backend, 1784 * we'll have revalidate the size at that time. 1785 */ 1786 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 1787 1761 1788 size_t const cbHstStrm = pThis->BackendCfg.cbStream; 1762 1789 AssertStmt(cbHstStrm >= sizeof(PDMAUDIOBACKENDSTREAM), rc = VERR_OUT_OF_RANGE); 1763 1790 AssertStmt(cbHstStrm < _16M, rc = VERR_OUT_OF_RANGE); 1791 1792 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 1764 1793 if (RT_SUCCESS(rc)) 1765 1794 { … … 1770 1799 if (pStreamEx) 1771 1800 { 1772 /* Make a unqiue stream name including the host (backend) driver name. */ 1773 AssertPtr(pThis->pHostDrvAudio); 1774 size_t cchName = RTStrPrintf(pStreamEx->Core.szName, RT_ELEMENTS(pStreamEx->Core.szName), "[%s] %s:0", 1775 pThis->BackendCfg.szName, pCfgHost->szName[0] != '\0' ? pCfgHost->szName : "<Untitled>"); 1776 if (cchName < sizeof(pStreamEx->Core.szName)) 1801 rc = RTCritSectInit(&pStreamEx->Core.CritSect); /* (drvAudioStreamFree assumes it's initailized) */ 1802 if (RT_SUCCESS(rc)) 1777 1803 { 1778 for (uint32_t i = 0; i < 256; i++) 1804 PPDMAUDIOBACKENDSTREAM pBackend = (PPDMAUDIOBACKENDSTREAM)(pStreamEx + 1); 1805 pBackend->uMagic = PDMAUDIOBACKENDSTREAM_MAGIC; 1806 pBackend->pStream = &pStreamEx->Core; 1807 1808 pStreamEx->pBackend = pBackend; 1809 pStreamEx->Core.enmDir = pCfgHost->enmDir; 1810 pStreamEx->Core.cbBackend = (uint32_t)cbHstStrm; 1811 pStreamEx->fNoMixBufs = RT_BOOL(fFlags & PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF); 1812 pStreamEx->hReqInitAsync = NIL_RTREQ; 1813 pStreamEx->uMagic = DRVAUDIOSTREAM_MAGIC; 1814 1815 /* Make a unqiue stream name including the host (backend) driver name. */ 1816 AssertPtr(pThis->pHostDrvAudio); 1817 size_t cchName = RTStrPrintf(pStreamEx->Core.szName, RT_ELEMENTS(pStreamEx->Core.szName), "[%s] %s:0", 1818 pThis->BackendCfg.szName, pCfgHost->szName[0] != '\0' ? pCfgHost->szName : "<NoName>"); 1819 if (cchName < sizeof(pStreamEx->Core.szName)) 1779 1820 { 1780 bool fDone = true; 1781 PDRVAUDIOSTREAM pIt; 1782 RTListForEach(&pThis->LstStreams, pIt, DRVAUDIOSTREAM, ListEntry) 1821 RTCritSectRwEnterShared(&pThis->CritSectGlobals); 1822 for (uint32_t i = 0; i < 256; i++) 1783 1823 { 1784 if (strcmp(pIt->Core.szName, pStreamEx->Core.szName) == 0) 1824 bool fDone = true; 1825 PDRVAUDIOSTREAM pIt; 1826 RTListForEach(&pThis->LstStreams, pIt, DRVAUDIOSTREAM, ListEntry) 1785 1827 { 1786 RTStrPrintf(pStreamEx->Core.szName, RT_ELEMENTS(pStreamEx->Core.szName), "[%s] %s:%u", 1787 pThis->BackendCfg.szName, pCfgHost->szName[0] != '\0' ? pCfgHost->szName : "<Untitled>", 1788 i); 1789 fDone = false; 1828 if (strcmp(pIt->Core.szName, pStreamEx->Core.szName) == 0) 1829 { 1830 RTStrPrintf(pStreamEx->Core.szName, RT_ELEMENTS(pStreamEx->Core.szName), "[%s] %s:%u", 1831 pThis->BackendCfg.szName, pCfgHost->szName[0] != '\0' ? pCfgHost->szName : "<NoName>", 1832 i); 1833 fDone = false; 1834 break; 1835 } 1836 } 1837 if (fDone) 1790 1838 break; 1839 } 1840 RTCritSectRwLeaveShared(&pThis->CritSectGlobals); 1841 } 1842 1843 /* 1844 * Try to init the rest. 1845 */ 1846 rc = drvAudioStreamInitInternal(pThis, pStreamEx, fFlags, pCfgHost, pCfgGuest); 1847 if (RT_SUCCESS(rc)) 1848 { 1849 /* Set initial reference counts. */ 1850 pStreamEx->cRefs = pStreamEx->fNeedAsyncInit ? 2 : 1; 1851 1852 /* Add it to the list. */ 1853 RTCritSectRwEnterExcl(&pThis->CritSectGlobals); 1854 1855 RTListAppend(&pThis->LstStreams, &pStreamEx->ListEntry); 1856 pThis->cStreams++; 1857 STAM_COUNTER_INC(&pThis->Stats.TotalStreamsCreated); 1858 1859 RTCritSectRwLeaveExcl(&pThis->CritSectGlobals); 1860 1861 /* 1862 * Init debug stuff if enabled (ignore failures). 1863 */ 1864 if (pCfgHost->enmDir == PDMAUDIODIR_IN) 1865 { 1866 if (pThis->CfgIn.Dbg.fEnabled) 1867 { 1868 AudioHlpFileCreateAndOpen(&pStreamEx->In.Dbg.pFileCaptureNonInterleaved, pThis->CfgIn.Dbg.szPathOut, 1869 "DrvAudioCapNonInt", pThis->pDrvIns->iInstance, &pStreamEx->Host.Cfg.Props); 1870 AudioHlpFileCreateAndOpen(&pStreamEx->In.Dbg.pFileStreamRead, pThis->CfgIn.Dbg.szPathOut, 1871 "DrvAudioRead", pThis->pDrvIns->iInstance, &pStreamEx->Host.Cfg.Props); 1791 1872 } 1792 1873 } 1793 if (fDone) 1794 break; 1874 else /* Out */ 1875 { 1876 if (pThis->CfgOut.Dbg.fEnabled) 1877 { 1878 AudioHlpFileCreateAndOpen(&pStreamEx->Out.Dbg.pFilePlayNonInterleaved, pThis->CfgOut.Dbg.szPathOut, 1879 "DrvAudioPlayNonInt", pThis->pDrvIns->iInstance, &pStreamEx->Host.Cfg.Props); 1880 AudioHlpFileCreateAndOpen(&pStreamEx->Out.Dbg.pFileStreamWrite, pThis->CfgOut.Dbg.szPathOut, 1881 "DrvAudioWrite", pThis->pDrvIns->iInstance, &pStreamEx->Host.Cfg.Props); 1882 } 1883 } 1884 1885 /* 1886 * Kick off the asynchronous init. 1887 */ 1888 if (!pStreamEx->fNeedAsyncInit) 1889 { 1890 pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_BACKEND_READY; 1891 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus); 1892 } 1893 else 1894 { 1895 int rc2 = RTReqPoolCallEx(pThis->hReqPool, 0 /*cMillies*/, &pStreamEx->hReqInitAsync, 1896 RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, 1897 (PFNRT)drvAudioStreamInitAsync, 2, pThis, pStreamEx); 1898 LogFlowFunc(("hReqInitAsync=%p rc2=%Rrc\n", pStreamEx->hReqInitAsync, rc2)); 1899 AssertRCStmt(rc2, drvAudioStreamInitAsync(pThis, pStreamEx)); 1900 } 1901 1902 #ifdef VBOX_STRICT 1903 /* 1904 * Assert lock order to make sure the lock validator picks up on it. 1905 */ 1906 RTCritSectRwEnterShared(&pThis->CritSectGlobals); 1907 RTCritSectEnter(&pStreamEx->Core.CritSect); 1908 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 1909 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 1910 RTCritSectLeave(&pStreamEx->Core.CritSect); 1911 RTCritSectRwLeaveShared(&pThis->CritSectGlobals); 1912 #endif 1913 1914 *ppStream = &pStreamEx->Core; 1915 LogFlowFunc(("returns VINF_SUCCESS (pStreamEx=%p)\n", pStreamEx)); 1916 return VINF_SUCCESS; 1795 1917 } 1796 } 1797 1798 PPDMAUDIOBACKENDSTREAM pBackend = (PPDMAUDIOBACKENDSTREAM)(pStreamEx + 1); 1799 pBackend->uMagic = PDMAUDIOBACKENDSTREAM_MAGIC; 1800 pBackend->pStream = &pStreamEx->Core; 1801 pStreamEx->pBackend = pBackend; 1802 pStreamEx->Core.enmDir = pCfgHost->enmDir; 1803 pStreamEx->Core.cbBackend = (uint32_t)cbHstStrm; 1804 pStreamEx->fNoMixBufs = RT_BOOL(fFlags & PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF); 1805 pStreamEx->hReqInitAsync = NIL_RTREQ; 1806 pStreamEx->uMagic = DRVAUDIOSTREAM_MAGIC; 1807 1808 /* 1809 * Try to init the rest. 1810 */ 1811 rc = drvAudioStreamInitInternal(pThis, pStreamEx, fFlags, pCfgHost, pCfgGuest); 1812 if (RT_SUCCESS(rc)) 1813 { 1814 /* Set initial reference counts. */ 1815 pStreamEx->cRefs = pStreamEx->fNeedAsyncInit ? 2 : 1; 1816 1817 /* Decrement the free stream counter. */ 1818 Assert(*pcFreeStreams > 0); 1819 *pcFreeStreams -= 1; 1820 1821 /* 1822 * We're good. 1823 */ 1824 RTListAppend(&pThis->LstStreams, &pStreamEx->ListEntry); 1825 STAM_COUNTER_INC(&pThis->Stats.TotalStreamsCreated); 1826 *ppStream = &pStreamEx->Core; 1827 1828 /* 1829 * Init debug stuff if enabled (ignore failures). 1830 */ 1831 if (pCfgHost->enmDir == PDMAUDIODIR_IN) 1832 { 1833 if (pThis->CfgIn.Dbg.fEnabled) 1834 { 1835 AudioHlpFileCreateAndOpen(&pStreamEx->In.Dbg.pFileCaptureNonInterleaved, pThis->CfgIn.Dbg.szPathOut, 1836 "DrvAudioCapNonInt", pThis->pDrvIns->iInstance, &pStreamEx->Host.Cfg.Props); 1837 AudioHlpFileCreateAndOpen(&pStreamEx->In.Dbg.pFileStreamRead, pThis->CfgIn.Dbg.szPathOut, 1838 "DrvAudioRead", pThis->pDrvIns->iInstance, &pStreamEx->Host.Cfg.Props); 1839 } 1840 } 1841 else /* Out */ 1842 { 1843 if (pThis->CfgOut.Dbg.fEnabled) 1844 { 1845 AudioHlpFileCreateAndOpen(&pStreamEx->Out.Dbg.pFilePlayNonInterleaved, pThis->CfgOut.Dbg.szPathOut, 1846 "DrvAudioPlayNonInt", pThis->pDrvIns->iInstance, &pStreamEx->Host.Cfg.Props); 1847 AudioHlpFileCreateAndOpen(&pStreamEx->Out.Dbg.pFileStreamWrite, pThis->CfgOut.Dbg.szPathOut, 1848 "DrvAudioWrite", pThis->pDrvIns->iInstance, &pStreamEx->Host.Cfg.Props); 1849 } 1850 } 1851 1852 /* 1853 * Kick off the asynchronous init. 1854 */ 1855 if (!pStreamEx->fNeedAsyncInit) 1856 { 1857 pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_BACKEND_READY; 1858 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus); 1859 } 1860 else 1861 { 1862 int rc2 = RTReqPoolCallEx(pThis->hReqPool, 0 /*cMillies*/, &pStreamEx->hReqInitAsync, 1863 RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, 1864 (PFNRT)drvAudioStreamInitAsync, 2, pThis, pStreamEx); 1865 LogFlowFunc(("hReqInitAsync=%p rc2=%Rrc\n", pStreamEx->hReqInitAsync, rc2)); 1866 AssertRCStmt(rc2, drvAudioStreamInitAsync(pThis, pStreamEx)); 1867 } 1868 } 1869 else 1870 { 1918 1871 1919 LogFunc(("drvAudioStreamInitInternal failed: %Rrc\n", rc)); 1872 1920 int rc2 = drvAudioStreamUninitInternal(pThis, pStreamEx); … … 1874 1922 drvAudioStreamFree(pStreamEx); 1875 1923 } 1924 else 1925 RTMemFree(pStreamEx); 1876 1926 } 1877 1927 else … … 1879 1929 } 1880 1930 1881 RTCritSectLeave(&pThis->CritSect); 1931 /* 1932 * Give back the stream count, we couldn't use it after all. 1933 */ 1934 RTCritSectRwEnterExcl(&pThis->CritSectGlobals); 1935 Assert(*pcFreeStreams >= 0); 1936 *pcFreeStreams += 1; 1937 RTCritSectRwLeaveExcl(&pThis->CritSectGlobals); 1938 1882 1939 LogFlowFuncLeaveRC(rc); 1883 1940 return rc; … … 1913 1970 /* Check if the pointer to the host audio driver is still valid. 1914 1971 * It can be NULL if we were called in drvAudioDestruct, for example. */ 1972 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); /** @todo needed? */ 1915 1973 if (pThis->pHostDrvAudio) 1916 1974 rc = pThis->pHostDrvAudio->pfnStreamDestroy(pThis->pHostDrvAudio, pStreamEx->pBackend); 1975 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 1917 1976 1918 1977 pStreamEx->fStatus &= ~(PDMAUDIOSTREAM_STS_BACKEND_CREATED | PDMAUDIOSTREAM_STS_BACKEND_READY); … … 1932 1991 * @param pThis Pointer to driver instance. 1933 1992 * @param pStreamEx Pointer to audio stream to uninitialize. 1934 *1935 * @note Caller owns the critical section.1936 1993 */ 1937 1994 static int drvAudioStreamUninitInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx) … … 1942 1999 VERR_WRONG_ORDER); 1943 2000 LogFlowFunc(("[%s] cRefs=%RU32\n", pStreamEx->Core.szName, pStreamEx->cRefs)); 2001 2002 RTCritSectEnter(&pStreamEx->Core.CritSect); 1944 2003 1945 2004 /* … … 2004 2063 } 2005 2064 } 2065 2066 RTCritSectLeave(&pStreamEx->Core.CritSect); 2006 2067 LogFlowFunc(("Returning %Rrc\n", rc)); 2007 2068 return rc; … … 2023 2084 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, UINT32_MAX); 2024 2085 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, UINT32_MAX); 2086 Assert(!RTCritSectIsOwner(&pStreamEx->Core.CritSect)); 2025 2087 2026 2088 uint32_t cRefs = ASMAtomicDecU32(&pStreamEx->cRefs); … … 2035 2097 * doesn't) and backend implementation. Ofc, the backend probably needs an 2036 2098 * opt-out here. */ 2037 int rc = RTCritSectEnter(&pThis->CritSect); 2038 AssertRC(rc); 2039 2040 rc = drvAudioStreamUninitInternal(pThis, pStreamEx); 2099 int rc = drvAudioStreamUninitInternal(pThis, pStreamEx); 2041 2100 if (RT_SUCCESS(rc)) 2042 2101 { 2102 RTCritSectRwEnterExcl(&pThis->CritSectGlobals); 2103 2043 2104 if (pStreamEx->Core.enmDir == PDMAUDIODIR_IN) 2044 2105 pThis->In.cStreamsFree++; 2045 2106 else /* Out */ 2046 2107 pThis->Out.cStreamsFree++; 2108 pThis->cStreams--; 2047 2109 2048 2110 RTListNodeRemove(&pStreamEx->ListEntry); 2111 2112 RTCritSectRwLeaveExcl(&pThis->CritSectGlobals); 2049 2113 2050 2114 drvAudioStreamFree(pStreamEx); … … 2055 2119 /** @todo r=bird: What's the plan now? */ 2056 2120 } 2057 2058 RTCritSectLeave(&pThis->CritSect);2059 2121 } 2060 2122 else … … 2079 2141 static DECLCALLBACK(void) drvAudioStreamDestroyAsync(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx) 2080 2142 { 2081 LogFlow(("pThis=%p pStreamEx=%p (%s)\n", pThis, pStreamEx, pStreamEx->Core.szName)); 2082 2083 /** @todo r=bird: This isn't doing the trick for core audio, as the big 2084 * simple-minded critsect is held while the often very slow 2085 * AudioQueueDestroy call is made, blocking creation and manipulation 2086 * of new streams. Sigh^3. */ 2087 2088 /** @todo can we somehow drain it instead? */ 2143 LogFlowFunc(("pThis=%p pStreamEx=%p (%s)\n", pThis, pStreamEx, pStreamEx->Core.szName)); 2144 #ifdef LOG_ENABLED 2145 uint64_t const nsStart = RTTimeNanoTS(); 2146 #endif 2147 2148 RTCritSectEnter(&pStreamEx->Core.CritSect); 2149 2150 /** @todo can we somehow drain it instead? 2151 * Would need to know if the destroying is happening at runtime or when powering 2152 * off the VM, as we don't care for draining the latter case. */ 2089 2153 int rc2 = drvAudioStreamControlInternal(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE); 2090 LogFlow (("DISABLE done: %Rrc\n", rc2));2154 LogFlowFunc(("DISABLE done: %Rrc\n", rc2)); 2091 2155 AssertRC(rc2); 2092 2156 2157 RTCritSectLeave(&pStreamEx->Core.CritSect); 2158 2093 2159 drvAudioStreamReleaseInternal(pThis, pStreamEx, true /*fMayDestroy*/); 2094 LogFlow(("returning\n")); 2160 2161 LogFlowFunc(("returning (after %'RU64 ns)\n", RTTimeNanoTS() - nsStart)); 2095 2162 } 2096 2163 … … 2120 2187 * pfnStreamInitAsync call. 2121 2188 */ 2122 int rc = RTCritSectEnter(&p This->CritSect);2189 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect); 2123 2190 AssertRCReturn(rc, rc); 2124 2191 … … 2154 2221 pStreamEx->hReqInitAsync = NIL_RTREQ; 2155 2222 } 2223 2224 RTCritSectLeave(&pStreamEx->Core.CritSect); 2156 2225 2157 2226 /* … … 2176 2245 } 2177 2246 else 2247 { 2178 2248 AssertLogRelMsgFailedStmt(("%p cRefs=%#x\n", pStreamEx, pStreamEx->cRefs), rc = VERR_CALLER_NO_REFERENCE); 2249 RTCritSectLeave(&pStreamEx->Core.CritSect); /*??*/ 2250 } 2179 2251 } 2180 2252 else 2253 { 2181 2254 AssertLogRelMsgFailedStmt(("%p uMagic=%#x\n", pStreamEx, pStreamEx->uMagic), rc = VERR_INVALID_MAGIC); 2182 2183 RTCritSectLeave(&pThis->CritSect); 2255 RTCritSectLeave(&pStreamEx->Core.CritSect); /*??*/ 2256 } 2257 2184 2258 LogFlowFuncLeaveRC(rc); 2185 2259 return rc; … … 2198 2272 { 2199 2273 LogFunc(("[%s]\n", pStreamEx->Core.szName)); 2274 Assert(RTCritSectIsOwner(&pStreamEx->Core.CritSect)); 2200 2275 2201 2276 if (pStreamEx->fNoMixBufs) … … 2235 2310 char szTmp[RT_MAX(PDMAUDIOSTRMCFGTOSTRING_MAX, DRVAUDIO_STATUS_STR_MAX)]; 2236 2311 LogFlowFunc(("[%s] status: %s\n", pStreamEx->Core.szName, drvAudioStreamStatusToStr(szTmp, pStreamEx->fStatus) )); 2312 Assert(RTCritSectIsOwner(&pStreamEx->Core.CritSect)); 2313 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 2237 2314 2238 2315 /* … … 2323 2400 } 2324 2401 2402 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 2325 2403 LogFunc(("[%s] Returning %Rrc\n", pStreamEx->Core.szName, rc)); 2326 2404 return rc; … … 2341 2419 LogFlowFunc(("\n")); 2342 2420 2343 int rc = RTCritSectEnter(&p This->CritSect);2421 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect); 2344 2422 AssertRCReturn(rc, rc); 2345 2423 … … 2398 2476 } 2399 2477 2400 RTCritSectLeave(&p This->CritSect);2478 RTCritSectLeave(&pStreamEx->Core.CritSect); 2401 2479 2402 2480 LogFlowFuncLeaveRC(rc); … … 2455 2533 * @param enmStreamCmd Control command. 2456 2534 * 2457 * @note Caller has entered the critical section. 2535 * @note Caller has entered the critical section of the stream. 2536 * @note Can be called w/o having entered DRVAUDIO::CritSectHotPlug. 2458 2537 */ 2459 2538 static int drvAudioStreamControlInternalBackend(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, PDMAUDIOSTREAMCMD enmStreamCmd) … … 2461 2540 AssertPtr(pThis); 2462 2541 AssertPtr(pStreamEx); 2542 Assert(RTCritSectIsOwner(&pStreamEx->Core.CritSect)); 2543 2544 int rc = RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 2545 AssertRCReturn(rc, rc); 2463 2546 2464 2547 /* … … 2475 2558 * finish initializing the stream, we'll update it about the stream state. 2476 2559 */ 2477 int rc = VINF_SUCCESS;2478 2560 bool const fDirEnabled = pStreamEx->Core.enmDir == PDMAUDIODIR_IN 2479 2561 ? pThis->In.fEnabled : pThis->Out.fEnabled; … … 2523 2605 2524 2606 default: 2525 AssertMsgFailed Return(("Command %RU32 not implemented\n", enmStreamCmd),VERR_INTERNAL_ERROR_2);2607 AssertMsgFailedBreakStmt(("Command %RU32 not implemented\n", enmStreamCmd), rc = VERR_INTERNAL_ERROR_2); 2526 2608 } 2527 2609 if (RT_SUCCESS(rc)) … … 2542 2624 else 2543 2625 LogFlowFunc(("fDirEnabled=false\n")); 2626 2627 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 2544 2628 return rc; 2545 2629 } … … 2591 2675 AssertPtr(pThis); 2592 2676 AssertPtr(pStreamEx); 2677 Assert(RTCritSectIsOwner(&pStreamEx->Core.CritSect)); 2593 2678 2594 2679 #ifdef LOG_ENABLED … … 2800 2885 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); 2801 2886 2802 int rc = RTCritSectEnter(&p This->CritSect);2887 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect); 2803 2888 AssertRCReturn(rc, rc); 2804 2889 … … 2807 2892 rc = drvAudioStreamControlInternal(pThis, pStreamEx, enmStreamCmd); 2808 2893 2809 RTCritSectLeave(&p This->CritSect);2894 RTCritSectLeave(&pStreamEx->Core.CritSect); 2810 2895 return rc; 2811 2896 } … … 2965 3050 * @param cbBuf Number of new bytes. Can be zero. 2966 3051 * @param pcbWritten Where to return the number of bytes written. 3052 * 3053 * @note Locking: Stream critsect and hot-plug in shared mode. 2967 3054 */ 2968 3055 static int drvAudioStreamPreBufComitting(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, … … 2984 3071 } 2985 3072 } 3073 3074 AssertReturn(pThis->pHostDrvAudio, VERR_AUDIO_BACKEND_NOT_ATTACHED); 2986 3075 2987 3076 /* … … 3085 3174 { 3086 3175 AssertReturn(pStreamEx->Core.enmDir == PDMAUDIODIR_OUT, VINF_SUCCESS); 3176 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 3087 3177 3088 3178 /* … … 3131 3221 drvAudioStreamResetOnDisable(pStreamEx); 3132 3222 } 3223 3224 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 3133 3225 } 3134 3226 … … 3152 3244 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); 3153 3245 3154 int rc = RTCritSectEnter(&p This->CritSect);3246 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect); 3155 3247 AssertRCReturn(rc, rc); 3156 3248 3157 3249 rc = drvAudioStreamIterateInternal(pThis, pStreamEx); 3158 3250 3159 RTCritSectLeave(&p This->CritSect);3251 RTCritSectLeave(&pStreamEx->Core.CritSect); 3160 3252 3161 3253 if (RT_FAILURE(rc)) … … 3177 3269 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, 0); 3178 3270 AssertMsg(pStreamEx->Core.enmDir == PDMAUDIODIR_IN, ("Can't read from a non-input stream\n")); 3179 int rc = RTCritSectEnter(&pThis->CritSect); 3271 3272 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect); 3180 3273 AssertRCReturn(rc, 0); 3274 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 3181 3275 3182 3276 /* … … 3239 3333 } 3240 3334 3241 RTCritSectLeave(&pThis->CritSect); 3335 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 3336 RTCritSectLeave(&pStreamEx->Core.CritSect); 3242 3337 Log3Func(("[%s] cbReadable=%#RX32 (%RU64ms)\n", 3243 3338 pStreamEx->Core.szName, cbReadable, PDMAudioPropsBytesToMilli(&pStreamEx->Host.Cfg.Props, cbReadable))); … … 3258 3353 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, 0); 3259 3354 AssertMsgReturn(pStreamEx->Core.enmDir == PDMAUDIODIR_OUT, ("Can't write to a non-output stream\n"), 0); 3260 int rc = RTCritSectEnter(&pThis->CritSect); 3355 3356 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect); 3261 3357 AssertRCReturn(rc, 0); 3358 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 3262 3359 3263 3360 /* … … 3343 3440 } 3344 3441 3345 RTCritSectLeave(&pThis->CritSect); 3442 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 3443 RTCritSectLeave(&pStreamEx->Core.CritSect); 3346 3444 Log3Func(("[%s] cbWritable=%#RX32 (%RU64ms) enmPlayMode=%s enmBackendState=%s\n", 3347 3445 pStreamEx->Core.szName, cbWritable, PDMAudioPropsBytesToMilli(&pStreamEx->Host.Cfg.Props, cbWritable), … … 3365 3463 * Get the status mask. 3366 3464 */ 3367 int rc = RTCritSectEnter(&p This->CritSect);3465 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect); 3368 3466 AssertRCReturn(rc, PDMAUDIOSTREAMSTATE_INVALID); 3467 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 3369 3468 3370 3469 PDMHOSTAUDIOSTREAMSTATE const enmBackendState = drvAudioStreamGetBackendStateAndProcessChanges(pThis, pStreamEx); … … 3373 3472 Assert(enmDir == PDMAUDIODIR_IN || enmDir == PDMAUDIODIR_OUT); 3374 3473 3375 RTCritSectLeave(&pThis->CritSect); 3474 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 3475 RTCritSectLeave(&pStreamEx->Core.CritSect); 3376 3476 3377 3477 /* … … 3422 3522 LogFlowFunc(("[%s] volL=%RU32, volR=%RU32, fMute=%RTbool\n", pStreamEx->Core.szName, pVol->uLeft, pVol->uRight, pVol->fMuted)); 3423 3523 3524 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect); 3525 AssertRCReturn(rc, rc); 3526 3424 3527 AudioMixBufSetVolume(&pStreamEx->Guest.MixBuf, pVol); 3425 3528 AudioMixBufSetVolume(&pStreamEx->Host.MixBuf, pVol); 3426 3529 3530 RTCritSectLeave(&pStreamEx->Core.CritSect); 3427 3531 return VINF_SUCCESS; 3428 3532 } … … 3461 3565 ("Stream '%s' got a non-frame-aligned write (%#RX32 bytes)\n", pStreamEx->Core.szName, cbBuf)); 3462 3566 3463 int rc = RTCritSectEnter(&p This->CritSect);3567 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect); 3464 3568 AssertRCReturn(rc, rc); 3465 3569 … … 3470 3574 if (PDMAudioStrmStatusIsReady(pStreamEx->fStatus)) 3471 3575 { 3576 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 3472 3577 if ( pThis->Out.fEnabled /* (see @bugref{9882}) */ 3473 3578 && pThis->pHostDrvAudio != NULL) … … 3555 3660 !pThis->Out.fEnabled ? "disabled" : !pThis->pHostDrvAudio ? "not attached" : "not ready yet")); 3556 3661 } 3662 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 3557 3663 } 3558 3664 else 3559 3665 rc = VERR_AUDIO_STREAM_NOT_READY; 3560 3666 3561 RTCritSectLeave(&p This->CritSect);3667 RTCritSectLeave(&pStreamEx->Core.CritSect); 3562 3668 return rc; 3563 3669 } … … 3583 3689 pStreamEx->Core.szName, pStreamEx->Core.enmDir)); 3584 3690 3585 int rc = RTCritSectEnter(&p This->CritSect);3691 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect); 3586 3692 AssertRCReturn(rc, rc); 3587 3693 … … 3669 3775 } while (0); 3670 3776 3671 RTCritSectLeave(&p This->CritSect);3777 RTCritSectLeave(&pStreamEx->Core.CritSect); 3672 3778 3673 3779 if (RT_SUCCESS(rc) && pcbRead) … … 3864 3970 ("Stream '%s' is not an input stream and therefore cannot be captured (direction is 0x%x)\n", 3865 3971 pStreamEx->Core.szName, pStreamEx->Core.enmDir)); 3866 int rc = RTCritSectEnter(&p This->CritSect);3972 int rc = RTCritSectEnter(&pStreamEx->Core.CritSect); 3867 3973 AssertRCReturn(rc, rc); 3974 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 3868 3975 3869 3976 #ifdef LOG_ENABLED … … 3919 4026 } while (0); 3920 4027 3921 RTCritSectLeave(&pThis->CritSect); 4028 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 4029 RTCritSectLeave(&pStreamEx->Core.CritSect); 3922 4030 3923 4031 if (pcFramesCaptured) … … 3945 4053 AssertPtrReturnVoid(pStreamEx); 3946 4054 AssertReturnVoid(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC); 4055 4056 /* 4057 * The CritSectHotPlug lock should not be needed here as detach will destroy 4058 * the thread pool. So, we'll leave taking the stream lock to the worker we're 4059 * calling as there are no lock order concerns. 4060 */ 3947 4061 PPDMIHOSTAUDIO const pIHostDrvAudio = pThis->pHostDrvAudio; 3948 4062 AssertPtrReturnVoid(pIHostDrvAudio); 3949 4063 AssertPtrReturnVoid(pIHostDrvAudio->pfnDoOnWorkerThread); 3950 3951 4064 pIHostDrvAudio->pfnDoOnWorkerThread(pIHostDrvAudio, pStreamEx->pBackend, uUser, pvUser); 3952 4065 … … 3967 4080 LogFlowFunc(("pThis=%p uUser=%#zx pvUser=%p\n", pThis, uUser, pvUser)); 3968 4081 AssertPtrReturnVoid(pThis); 4082 4083 /* 4084 * The CritSectHotPlug lock should not be needed here as detach will destroy 4085 * the thread pool. 4086 */ 3969 4087 PPDMIHOSTAUDIO const pIHostDrvAudio = pThis->pHostDrvAudio; 3970 4088 AssertPtrReturnVoid(pIHostDrvAudio); … … 3987 4105 3988 4106 /* 3989 * Assert some sanity and do the work. 3990 */ 3991 AssertReturn(pThis->pHostDrvAudio, VERR_INTERNAL_ERROR_3); 3992 AssertReturn(pThis->pHostDrvAudio->pfnDoOnWorkerThread, VERR_INVALID_FUNCTION); 3993 AssertReturn(pThis->hReqPool != NIL_RTREQPOOL, VERR_INVALID_FUNCTION); 3994 int rc; 4107 * Assert some sanity. 4108 */ 4109 PDRVAUDIOSTREAM pStreamEx; 3995 4110 if (!pStream) 3996 { 3997 rc = RTReqPoolCallEx(pThis->hReqPool, 0 /*cMillies*/, NULL /*phReq*/, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, 3998 (PFNRT)drvAudioHostPort_DoOnWorkerThreadWorker, 3, pThis, uUser, pvUser); 3999 AssertRC(rc); 4000 } 4111 pStreamEx = NULL; 4001 4112 else 4002 4113 { 4003 4114 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 4004 4115 AssertReturn(pStream->uMagic == PDMAUDIOBACKENDSTREAM_MAGIC, VERR_INVALID_MAGIC); 4005 PDRVAUDIOSTREAMpStreamEx = (PDRVAUDIOSTREAM)pStream->pStream;4116 pStreamEx = (PDRVAUDIOSTREAM)pStream->pStream; 4006 4117 AssertPtrReturn(pStreamEx, VERR_INVALID_POINTER); 4007 4118 AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); 4008 4119 AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC); 4009 4010 uint32_t cRefs = drvAudioStreamRetainInternal(pStreamEx); 4011 if (cRefs != UINT32_MAX) 4012 { 4013 rc = RTReqPoolCallEx(pThis->hReqPool, 0 /*cMillies*/, NULL, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, 4014 (PFNRT)drvAudioHostPort_DoOnWorkerThreadStreamWorker, 4015 4, pThis, pStreamEx, uUser, pvUser); 4016 AssertRC(rc); 4017 if (RT_FAILURE(rc)) 4018 drvAudioStreamReleaseInternal(pThis, pStreamEx, true /*fMayDestroy*/); 4120 } 4121 4122 int rc = RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 4123 AssertRCReturn(rc, rc); 4124 4125 AssertPtr(pThis->hReqPool != NIL_RTREQPOOL); 4126 AssertPtr(pThis->pHostDrvAudio); 4127 if ( pThis->hReqPool != NIL_RTREQPOOL 4128 && pThis->pHostDrvAudio != NULL) 4129 { 4130 Assert(pThis->pHostDrvAudio->pfnDoOnWorkerThread); 4131 if (pThis->pHostDrvAudio->pfnDoOnWorkerThread) 4132 { 4133 /* 4134 * Try do the work. 4135 */ 4136 if (!pStreamEx) 4137 { 4138 rc = RTReqPoolCallEx(pThis->hReqPool, 0 /*cMillies*/, NULL /*phReq*/, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, 4139 (PFNRT)drvAudioHostPort_DoOnWorkerThreadWorker, 3, pThis, uUser, pvUser); 4140 AssertRC(rc); 4141 } 4142 else 4143 { 4144 4145 uint32_t cRefs = drvAudioStreamRetainInternal(pStreamEx); 4146 if (cRefs != UINT32_MAX) 4147 { 4148 rc = RTReqPoolCallEx(pThis->hReqPool, 0 /*cMillies*/, NULL, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, 4149 (PFNRT)drvAudioHostPort_DoOnWorkerThreadStreamWorker, 4150 4, pThis, pStreamEx, uUser, pvUser); 4151 AssertRC(rc); 4152 if (RT_FAILURE(rc)) 4153 { 4154 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 4155 drvAudioStreamReleaseInternal(pThis, pStreamEx, true /*fMayDestroy*/); 4156 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 4157 } 4158 } 4159 else 4160 rc = VERR_INVALID_PARAMETER; 4161 } 4019 4162 } 4020 4163 else 4021 rc = VERR_INVALID_PARAMETER; 4022 } 4164 rc = VERR_INVALID_FUNCTION; 4165 } 4166 else 4167 rc = VERR_INVALID_STATE; 4168 4169 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 4023 4170 LogFlowFunc(("returns %Rrc\n", rc)); 4024 4171 return rc; … … 4032 4179 { 4033 4180 LogFlow((LOG_FN_FMT ": Flagging %s for re-init.\n", pszCaller, pStreamEx->Core.szName)); RT_NOREF(pszCaller); 4181 Assert(RTCritSectIsOwner(&pStreamEx->Core.CritSect)); 4182 4034 4183 pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_NEED_REINIT; 4035 4184 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus); … … 4048 4197 LogRel(("Audio: The %s device for %s is changing.\n", enmDir == PDMAUDIODIR_IN ? "input" : "output", pThis->BackendCfg.szName)); 4049 4198 4050 RTCritSectEnter(&pThis->CritSect); 4199 /* 4200 * Grab the list lock in shared mode and do the work. 4201 */ 4202 int rc = RTCritSectRwEnterShared(&pThis->CritSectGlobals); 4203 AssertRCReturnVoid(rc); 4204 4051 4205 PDRVAUDIOSTREAM pStreamEx; 4052 4206 RTListForEach(&pThis->LstStreams, pStreamEx, DRVAUDIOSTREAM, ListEntry) … … 4054 4208 if (pStreamEx->Core.enmDir == enmDir) 4055 4209 { 4210 RTCritSectEnter(&pStreamEx->Core.CritSect); 4211 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 4212 4056 4213 if (pThis->pHostDrvAudio->pfnStreamNotifyDeviceChanged) 4057 4214 { … … 4064 4221 else 4065 4222 drvAudioStreamMarkNeedReInit(pStreamEx, __PRETTY_FUNCTION__); 4223 4224 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 4225 RTCritSectLeave(&pStreamEx->Core.CritSect); 4066 4226 } 4067 4227 } 4068 RTCritSectLeave(&pThis->CritSect); 4228 4229 RTCritSectRwLeaveShared(&pThis->CritSectGlobals); 4069 4230 } 4070 4231 … … 4076 4237 PPDMAUDIOBACKENDSTREAM pStream) 4077 4238 { 4078 PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IHostAudioPort);4239 RT_NOREF(pInterface); 4079 4240 4080 4241 /* … … 4092 4253 * Grab the lock and do switch the state (only needed for output streams for now). 4093 4254 */ 4094 RTCritSectEnter(&p This->CritSect);4095 AssertReturnVoidStmt(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, RTCritSectLeave(&p This->CritSect)); /* paranoia */4255 RTCritSectEnter(&pStreamEx->Core.CritSect); 4256 AssertReturnVoidStmt(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, RTCritSectLeave(&pStreamEx->Core.CritSect)); /* paranoia */ 4096 4257 4097 4258 if (pStreamEx->Core.enmDir == PDMAUDIODIR_OUT) … … 4127 4288 LogFunc(("input stream, nothing to do.\n")); 4128 4289 4129 RTCritSectLeave(&p This->CritSect);4290 RTCritSectLeave(&pStreamEx->Core.CritSect); 4130 4291 } 4131 4292 … … 4152 4313 * Grab the lock and do the requested work. 4153 4314 */ 4154 RTCritSectEnter(&p This->CritSect);4155 AssertReturnVoidStmt(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, RTCritSectLeave(&p This->CritSect)); /* paranoia */4315 RTCritSectEnter(&pStreamEx->Core.CritSect); 4316 AssertReturnVoidStmt(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, RTCritSectLeave(&pStreamEx->Core.CritSect)); /* paranoia */ 4156 4317 4157 4318 if (fReInit) … … 4187 4348 } 4188 4349 4189 RTCritSectLeave(&p This->CritSect);4350 RTCritSectLeave(&pStreamEx->Core.CritSect); 4190 4351 } 4191 4352 … … 4205 4366 4206 4367 /* Try push the work over to the thread-pool if we've got one. */ 4368 RTCritSectRwEnterShared(&pThis->CritSectHotPlug); 4207 4369 if (pThis->hReqPool != NIL_RTREQPOOL) 4208 4370 { … … 4211 4373 3, pThis, true /*fLog*/, (PPDMAUDIOHOSTENUM)NULL /*pDevEnum*/); 4212 4374 LogFunc(("RTReqPoolCallEx: %Rrc\n", rc)); 4375 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 4213 4376 if (RT_SUCCESS(rc)) 4214 4377 return; 4215 4378 } 4379 else 4380 RTCritSectRwLeaveShared(&pThis->CritSectHotPlug); 4381 4216 4382 LogFunc(("Calling drvAudioDevicesEnumerateInternal...\n")); 4217 4383 drvAudioDevicesEnumerateInternal(pThis, true /* fLog */, NULL /* pDevEnum */); … … 4229 4395 4230 4396 #ifdef RT_OS_DARWIN /** @todo Remove legacy behaviour: */ 4231 /** @todo r=bird: Locking? */4232 4397 /* Mark all host streams to re-initialize. */ 4398 int rc2 = RTCritSectRwEnterShared(&pThis->CritSectGlobals); 4399 AssertRCReturnVoid(rc2); 4233 4400 PDRVAUDIOSTREAM pStreamEx; 4234 4401 RTListForEach(&pThis->LstStreams, pStreamEx, DRVAUDIOSTREAM, ListEntry) 4235 4402 { 4403 RTCritSectEnter(&pStreamEx->Core.CritSect); 4236 4404 drvAudioStreamMarkNeedReInit(pStreamEx, __PRETTY_FUNCTION__); 4237 } 4405 RTCritSectLeave(&pStreamEx->Core.CritSect); 4406 } 4407 RTCritSectRwLeaveShared(&pThis->CritSectGlobals); 4238 4408 #endif 4239 4409 … … 4295 4465 * in drvAudioDestruct(). 4296 4466 */ 4467 int rc = RTCritSectRwEnterShared(&pThis->CritSectGlobals); 4468 AssertRCReturnVoid(rc); 4469 4297 4470 PDRVAUDIOSTREAM pStreamEx; 4298 4471 RTListForEach(&pThis->LstStreams, pStreamEx, DRVAUDIOSTREAM, ListEntry) 4299 4472 { 4473 RTCritSectEnter(&pStreamEx->Core.CritSect); 4300 4474 drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE); 4301 #if 0 /* This leads to double destruction. Also in the backend when we don't set pHostDrvAudio to NULL below. */ 4302 drvAudioStreamDestroyInternalBackend(pThis, pStreamEx); 4303 #endif 4475 RTCritSectLeave(&pStreamEx->Core.CritSect); 4304 4476 } 4305 4477 4306 #if 0 /* Messes up using drvAudioHostPort_DoOnWorkerThread from the backend drivers' power off callback. */ 4307 pThis->pHostDrvAudio = NULL; 4308 #endif 4478 RTCritSectRwLeaveShared(&pThis->CritSectGlobals); 4309 4479 } 4310 4480 … … 4325 4495 RT_NOREF(fFlags); 4326 4496 4327 int rc = RTCritSect Enter(&pThis->CritSect);4328 Assert RC(rc);4497 int rc = RTCritSectRwEnterExcl(&pThis->CritSectHotPlug); 4498 AssertLogRelRCReturnVoid(rc); 4329 4499 4330 4500 LogFunc(("%s (detached %p, hReqPool=%p)\n", pThis->BackendCfg.szName, pThis->pHostDrvAudio, pThis->hReqPool)); … … 4339 4509 RTREQPOOL hReqPool = pThis->hReqPool; 4340 4510 pThis->hReqPool = NIL_RTREQPOOL; 4341 RTCritSectLeave(&pThis->CritSect); 4511 4512 RTCritSectRwLeaveExcl(&pThis->CritSectHotPlug); 4342 4513 4343 4514 RTReqPoolRelease(hReqPool); 4344 4515 4345 RTCritSect Enter(&pThis->CritSect);4516 RTCritSectRwEnterExcl(&pThis->CritSectHotPlug); 4346 4517 } 4347 4518 … … 4351 4522 pThis->pHostDrvAudio = NULL; 4352 4523 4353 RTCritSect Leave(&pThis->CritSect);4524 RTCritSectRwLeaveExcl(&pThis->CritSectHotPlug); 4354 4525 } 4355 4526 … … 4390 4561 /* 4391 4562 * Get the backend configuration. 4563 * 4564 * Note! Limit the number of streams to max 128 in each direction to 4565 * prevent wasting resources. 4392 4566 * Note! Take care not to wipe the DriverName config value on failure. 4393 4567 */ … … 4400 4574 LogFunc(("BackendCfg.szName: '%s' -> '%s'\n", pThis->BackendCfg.szName, BackendCfg.szName)); 4401 4575 pThis->BackendCfg = BackendCfg; 4402 pThis->In.cStreamsFree = BackendCfg.cMaxStreamsIn;4403 pThis->Out.cStreamsFree = BackendCfg.cMaxStreamsOut;4576 pThis->In.cStreamsFree = RT_MIN(BackendCfg.cMaxStreamsIn, 128); 4577 pThis->Out.cStreamsFree = RT_MIN(BackendCfg.cMaxStreamsOut, 128); 4404 4578 4405 4579 LogFlowFunc(("cStreamsFreeIn=%RU8, cStreamsFreeOut=%RU8\n", pThis->In.cStreamsFree, pThis->Out.cStreamsFree)); … … 4550 4724 LogFunc(("%s\n", pThis->BackendCfg.szName)); 4551 4725 4552 int rc = RTCritSect Enter(&pThis->CritSect);4726 int rc = RTCritSectRwEnterExcl(&pThis->CritSectHotPlug); 4553 4727 AssertRCReturn(rc, rc); 4554 4728 4555 4729 rc = drvAudioDoAttachInternal(pDrvIns, pThis, fFlags); 4556 4730 4557 RTCritSect Leave(&pThis->CritSect);4731 RTCritSectRwLeaveExcl(&pThis->CritSectHotPlug); 4558 4732 return rc; 4559 4733 } … … 4572 4746 LogFlowFunc(("enmCmd=%s\n", PDMAudioStrmCmdGetName(enmCmd))); 4573 4747 4574 int rc2 = RTCritSect Enter(&pThis->CritSect);4748 int rc2 = RTCritSectRwEnterShared(&pThis->CritSectGlobals); 4575 4749 AssertRCReturnVoid(rc2); 4576 4750 4577 if (pThis->pHostDrvAudio) 4578 { 4579 PDRVAUDIOSTREAM pStreamEx; 4580 RTListForEach(&pThis->LstStreams, pStreamEx, DRVAUDIOSTREAM, ListEntry) 4581 { 4582 drvAudioStreamControlInternal(pThis, pStreamEx, enmCmd); 4583 } 4584 } 4585 4586 rc2 = RTCritSectLeave(&pThis->CritSect); 4587 AssertRC(rc2); 4751 PDRVAUDIOSTREAM pStreamEx; 4752 RTListForEach(&pThis->LstStreams, pStreamEx, DRVAUDIOSTREAM, ListEntry) 4753 { 4754 RTCritSectEnter(&pStreamEx->Core.CritSect); 4755 drvAudioStreamControlInternal(pThis, pStreamEx, enmCmd); 4756 RTCritSectLeave(&pStreamEx->Core.CritSect); 4757 } 4758 4759 RTCritSectRwLeaveShared(&pThis->CritSectGlobals); 4588 4760 } 4589 4761 … … 4622 4794 4623 4795 LogFlowFuncEnter(); 4624 4625 if (RTCritSectIsInitialized(&pThis->CritSect))4626 {4627 int rc = RTCritSectEnter(&pThis->CritSect);4628 AssertRC(rc);4629 }4630 4796 4631 4797 /* … … 4638 4804 /* Thus, NULL the pointer to the host audio driver first, 4639 4805 * so that routines like drvAudioStreamDestroyInternal() don't call the driver(s) below us anymore. */ 4640 pThis->pHostDrvAudio = NULL; 4641 4642 PDRVAUDIOSTREAM pStreamEx, pStreamExNext; 4643 RTListForEachSafe(&pThis->LstStreams, pStreamEx, pStreamExNext, DRVAUDIOSTREAM, ListEntry) 4644 { 4645 int rc = drvAudioStreamUninitInternal(pThis, pStreamEx); 4646 if (RT_SUCCESS(rc)) 4647 { 4648 RTListNodeRemove(&pStreamEx->ListEntry); 4649 drvAudioStreamFree(pStreamEx); 4806 if (RTCritSectRwIsInitialized(&pThis->CritSectHotPlug)) 4807 { 4808 RTCritSectRwEnterExcl(&pThis->CritSectHotPlug); 4809 pThis->pHostDrvAudio = NULL; 4810 RTCritSectRwLeaveExcl(&pThis->CritSectHotPlug); 4811 } 4812 else 4813 { 4814 Assert(pThis->pHostDrvAudio == NULL); 4815 pThis->pHostDrvAudio = NULL; 4816 } 4817 4818 if (RTCritSectRwIsInitialized(&pThis->CritSectGlobals)) 4819 { 4820 RTCritSectRwEnterExcl(&pThis->CritSectGlobals); 4821 4822 PDRVAUDIOSTREAM pStreamEx, pStreamExNext; 4823 RTListForEachSafe(&pThis->LstStreams, pStreamEx, pStreamExNext, DRVAUDIOSTREAM, ListEntry) 4824 { 4825 int rc = drvAudioStreamUninitInternal(pThis, pStreamEx); 4826 if (RT_SUCCESS(rc)) 4827 { 4828 RTListNodeRemove(&pStreamEx->ListEntry); 4829 drvAudioStreamFree(pStreamEx); 4830 } 4650 4831 } 4651 } 4832 4833 RTCritSectRwLeaveExcl(&pThis->CritSectGlobals); 4834 RTCritSectRwDelete(&pThis->CritSectGlobals); 4835 } 4836 4652 4837 4653 4838 /* Sanity. */ 4654 4839 Assert(RTListIsEmpty(&pThis->LstStreams)); 4655 4840 4656 if (RTCritSectIsInitialized(&pThis->CritSect)) 4657 { 4658 int rc = RTCritSectLeave(&pThis->CritSect); 4659 AssertRC(rc); 4660 4661 rc = RTCritSectDelete(&pThis->CritSect); 4662 AssertRC(rc); 4663 } 4841 if (RTCritSectRwIsInitialized(&pThis->CritSectHotPlug)) 4842 RTCritSectRwDelete(&pThis->CritSectHotPlug); 4664 4843 4665 4844 #ifdef VBOX_WITH_STATISTICS … … 4852 5031 * Init the rest of the driver instance data. 4853 5032 */ 4854 rc = RTCritSect Init(&pThis->CritSect);5033 rc = RTCritSectRwInit(&pThis->CritSectHotPlug); 4855 5034 AssertRCReturn(rc, rc); 5035 rc = RTCritSectRwInit(&pThis->CritSectGlobals); 5036 AssertRCReturn(rc, rc); 5037 #ifdef VBOX_STRICT 5038 /* Define locking order: */ 5039 RTCritSectRwEnterExcl(&pThis->CritSectGlobals); 5040 RTCritSectRwEnterExcl(&pThis->CritSectHotPlug); 5041 RTCritSectRwLeaveExcl(&pThis->CritSectHotPlug); 5042 RTCritSectRwLeaveExcl(&pThis->CritSectGlobals); 5043 #endif 4856 5044 4857 5045 pThis->pDrvIns = pDrvIns;
Note:
See TracChangeset
for help on using the changeset viewer.