/** * performs the "base" globals initialization * we separate the globals initialization to globals "base" initialization which is actually * "general" globals initialization except for Idc not being initialized, and idc initialization. * This is needed for windows filter driver, which gets loaded prior to VBoxDrv, * thus it's not possible to make idc initialization from the driver startup routine for it. * * @returns VBox status code. * @param pGlobals Pointer to the globals. */ DECLHIDDEN(int) vboxNetAdpInitGlobalsBase(PVBOXNETADPGLOBALS pGlobals) { /* * Initialize the common portions of the structure. */ int i; int rc = RTSemFastMutexCreate(&pGlobals->hFastMtx); if (RT_SUCCESS(rc)) { memset(pGlobals->aAdapters, 0, sizeof(pGlobals->aAdapters)); for (i = 0; i < (int)RT_ELEMENTS(pGlobals->aAdapters); i++) { rc = vboxNetAdpSlotCreate(pGlobals, i, &pGlobals->aAdapters[i]); if (RT_FAILURE(rc)) { /* Clean up. */ while (--i >= 0) vboxNetAdpSlotDestroy(&pGlobals->aAdapters[i]); Log(("vboxNetAdpInitGlobalsBase: Failed to create fast mutex (rc=%Rrc).\n", rc)); RTSemFastMutexDestroy(pGlobals->hFastMtx); return rc; } } pGlobals->TrunkFactory.pfnRelease = vboxNetAdpFactoryRelease; pGlobals->TrunkFactory.pfnCreateAndConnect = vboxNetAdpFactoryCreateAndConnect; strcpy(pGlobals->SupDrvFactory.szName, "VBoxNetAdp"); pGlobals->SupDrvFactory.pfnQueryFactoryInterface = vboxNetAdpQueryFactoryInterface; } return rc; }
/** * Creates a new empty I/O logger. * * @returns VBox status code. * @param ppIoLogger Where to store the new I/O logger handle. */ static int vddbgIoLoggerCreate(PVDIOLOGGERINT *ppIoLogger) { int rc = VINF_SUCCESS; PVDIOLOGGERINT pIoLogger = NULL; pIoLogger = (PVDIOLOGGERINT)RTMemAllocZ(sizeof(VDIOLOGGERINT)); if (pIoLogger) { rc = RTSemFastMutexCreate(&pIoLogger->hMtx); if (RT_SUCCESS(rc)) { rc = RTMemCacheCreate(&pIoLogger->hMemCacheIoLogEntries, sizeof(VDIOLOGENTINT), 0, UINT32_MAX, NULL, NULL, NULL, 0); if (RT_SUCCESS(rc)) { *ppIoLogger = pIoLogger; return rc; } } RTMemFree(pIoLogger); } else rc = VERR_NO_MEMORY; return rc; }
/** * @copydoc RAWPCIFACTORY::pfnInitVm */ static DECLCALLBACK(int) vboxPciFactoryInitVm(PRAWPCIFACTORY pFactory, PVM pVM, PRAWPCIPERVM pVmData) { PVBOXRAWPCIDRVVM pThis = (PVBOXRAWPCIDRVVM)RTMemAllocZ(sizeof(VBOXRAWPCIDRVVM)); int rc; if (!pThis) return VERR_NO_MEMORY; rc = RTSemFastMutexCreate(&pThis->hFastMtx); if (RT_SUCCESS(rc)) { rc = vboxPciOsInitVm(pThis, pVM, pVmData); if (RT_SUCCESS(rc)) { #ifdef VBOX_WITH_IOMMU /* If IOMMU notification routine in pVmData->pfnContigMemInfo is set - we have functional IOMMU hardware. */ if (pVmData->pfnContigMemInfo) pVmData->fVmCaps |= PCIRAW_VMFLAGS_HAS_IOMMU; #endif pThis->pPerVmData = pVmData; pVmData->pDriverData = pThis; return VINF_SUCCESS; } RTSemFastMutexDestroy(pThis->hFastMtx); pThis->hFastMtx = NIL_RTSEMFASTMUTEX; RTMemFree(pThis); } return rc; }
/** * Initializes the object (called right after construction). * * @returns S_OK on success and non-fatal failures, some COM error otherwise. */ int USBProxyBackendUsbIp::init(void) { int rc = VINF_SUCCESS; m = new Data; /** @todo: Pass in some config like host and port to connect to. */ /* Setup wakeup pipe and poll set first. */ rc = RTSemFastMutexCreate(&m->hMtxDevices); if (RT_SUCCESS(rc)) { rc = RTPipeCreate(&m->hWakeupPipeR, &m->hWakeupPipeW, 0); if (RT_SUCCESS(rc)) { rc = RTPollSetCreate(&m->hPollSet); if (RT_SUCCESS(rc)) { rc = RTPollSetAddPipe(m->hPollSet, m->hWakeupPipeR, RTPOLL_EVT_READ, USBIP_POLL_ID_PIPE); if (RT_SUCCESS(rc)) { /* Connect to the USB/IP host. */ rc = reconnect(); if (RT_SUCCESS(rc)) rc = start(); /* Start service thread. */ } if (RT_FAILURE(rc)) { RTPollSetRemove(m->hPollSet, USBIP_POLL_ID_PIPE); int rc2 = RTPollSetDestroy(m->hPollSet); AssertRC(rc2); } } if (RT_FAILURE(rc)) { int rc2 = RTPipeClose(m->hWakeupPipeR); AssertRC(rc2); rc2 = RTPipeClose(m->hWakeupPipeW); AssertRC(rc2); } } if (RT_FAILURE(rc)) RTSemFastMutexDestroy(m->hMtxDevices); } return rc; }
/** * Initializes the VBoxUSB filter manager. * * @returns IPRT status code. */ int VBoxUSBFilterInit(void) { #ifdef VBOXUSBFILTERMGR_USB_SPINLOCK int rc = RTSpinlockCreate(&g_Spinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxUSBFilter"); #else int rc = RTSemFastMutexCreate(&g_Mtx); #endif if (RT_SUCCESS(rc)) { /* not really required, but anyway... */ for (unsigned i = USBFILTERTYPE_FIRST; i < RT_ELEMENTS(g_aLists); i++) g_aLists[i].pHead = g_aLists[i].pTail = NULL; } return rc; }
/** * Initializes the globals. * * @returns VBox status code. * @param pGlobals Pointer to the globals. */ DECLHIDDEN(int) vboxPciInitGlobals(PVBOXRAWPCIGLOBALS pGlobals) { /* * Initialize the common portions of the structure. */ int rc = RTSemFastMutexCreate(&pGlobals->hFastMtx); if (RT_SUCCESS(rc)) { pGlobals->pInstanceHead = NULL; pGlobals->RawPciFactory.pfnRelease = vboxPciFactoryRelease; pGlobals->RawPciFactory.pfnCreateAndConnect = vboxPciFactoryCreateAndConnect; pGlobals->RawPciFactory.pfnInitVm = vboxPciFactoryInitVm; pGlobals->RawPciFactory.pfnDeinitVm = vboxPciFactoryDeinitVm; memcpy(pGlobals->SupDrvFactory.szName, "VBoxRawPci", sizeof("VBoxRawPci")); pGlobals->SupDrvFactory.pfnQueryFactoryInterface = vboxPciQueryFactoryInterface; pGlobals->fIDCOpen = false; } return rc; }
/** * Initializes the HGCM VBGL bits. * * @return VBox status code. */ int vbglR0HGCMInit (void) { return RTSemFastMutexCreate(&g_vbgldata.mutexHGCMHandle); }
static SPUFunctions * renderSPUInit( int id, SPU *child, SPU *self, unsigned int context_id, unsigned int num_contexts ) { int numFuncs, numSpecial; GLint defaultWin, defaultCtx; WindowInfo *windowInfo; const char * pcpwSetting; int rc; (void) child; (void) context_id; (void) num_contexts; self->privatePtr = (void *) &render_spu; #ifdef CHROMIUM_THREADSAFE crDebug("Render SPU: thread-safe"); #endif crMemZero(&render_spu, sizeof(render_spu)); render_spu.id = id; renderspuSetVBoxConfiguration(&render_spu); if (render_spu.swap_master_url) swapsyncConnect(); /* Get our special functions. */ numSpecial = renderspuCreateFunctions( _cr_render_table ); #ifdef RT_OS_WINDOWS /* Start thread to create windows and process window messages */ crDebug("RenderSPU: Starting windows serving thread"); render_spu.hWinThreadReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (!render_spu.hWinThreadReadyEvent) { crError("RenderSPU: Failed to create WinThreadReadyEvent! (%x)", GetLastError()); return NULL; } if (!CreateThread(NULL, 0, renderSPUWindowThreadProc, 0, 0, &render_spu.dwWinThreadId)) { crError("RenderSPU: Failed to start windows thread! (%x)", GetLastError()); return NULL; } WaitForSingleObject(render_spu.hWinThreadReadyEvent, INFINITE); #endif /* Get the OpenGL functions. */ numFuncs = crLoadOpenGL( &render_spu.ws, _cr_render_table + numSpecial ); if (numFuncs == 0) { crError("The render SPU was unable to load the native OpenGL library"); return NULL; } numFuncs += numSpecial; render_spu.contextTable = crAllocHashtableEx(1, INT32_MAX); render_spu.windowTable = crAllocHashtableEx(1, INT32_MAX); render_spu.dummyWindowTable = crAllocHashtable(); pcpwSetting = crGetenv("CR_RENDER_ENABLE_SINGLE_PRESENT_CONTEXT"); if (pcpwSetting) { if (pcpwSetting[0] == '0') pcpwSetting = NULL; } if (pcpwSetting) { /* TODO: need proper blitter synchronization, do not use so far! * the problem is that rendering can be done in multiple thread: the main command (hgcm) thread and the redraw thread * we currently use per-window synchronization, while we'll need a per-blitter synchronization if one blitter is used for multiple windows * this is not done currently */ crWarning("TODO: need proper blitter synchronization, do not use so far!"); render_spu.blitterTable = crAllocHashtable(); CRASSERT(render_spu.blitterTable); } else render_spu.blitterTable = NULL; CRASSERT(render_spu.default_visual & CR_RGB_BIT); rc = renderspu_SystemInit(); if (!RT_SUCCESS(rc)) { crError("renderspu_SystemInit failed rc %d", rc); return NULL; } #ifdef USE_OSMESA if (render_spu.use_osmesa) { if (!crLoadOSMesa(&render_spu.OSMesaCreateContext, &render_spu.OSMesaMakeCurrent, &render_spu.OSMesaDestroyContext)) { crError("Unable to load OSMesa library"); } } #endif #ifdef DARWIN # ifdef VBOX_WITH_COCOA_QT # else /* VBOX_WITH_COCOA_QT */ render_spu.hRootVisibleRegion = 0; render_spu.currentBufferName = 1; render_spu.uiDockUpdateTS = 0; /* Create a mutex for synchronizing events from the main Qt thread & this thread */ RTSemFastMutexCreate(&render_spu.syncMutex); /* Create our window groups */ CreateWindowGroup(kWindowGroupAttrMoveTogether | kWindowGroupAttrLayerTogether | kWindowGroupAttrSharedActivation | kWindowGroupAttrHideOnCollapse | kWindowGroupAttrFixedLevel, &render_spu.pMasterGroup); CreateWindowGroup(kWindowGroupAttrMoveTogether | kWindowGroupAttrLayerTogether | kWindowGroupAttrSharedActivation | kWindowGroupAttrHideOnCollapse | kWindowGroupAttrFixedLevel, &render_spu.pParentGroup); /* Make the correct z-layering */ SendWindowGroupBehind (render_spu.pParentGroup, render_spu.pMasterGroup); /* and set the gParentGroup as parent for gMasterGroup. */ SetWindowGroupParent (render_spu.pMasterGroup, render_spu.pParentGroup); /* Install the event handlers */ EventTypeSpec eventList[] = { {kEventClassVBox, kEventVBoxUpdateContext}, /* Update the context after show/size/move events */ {kEventClassVBox, kEventVBoxBoundsChanged} /* Clip/Pos the OpenGL windows when the main window is changed in pos/size */ }; /* We need to process events from our main window */ render_spu.hParentEventHandler = NewEventHandlerUPP(windowEvtHndlr); InstallApplicationEventHandler (render_spu.hParentEventHandler, GetEventTypeCount(eventList), eventList, NULL, NULL); render_spu.fInit = true; # endif /* VBOX_WITH_COCOA_QT */ #endif /* DARWIN */ /* * Create the default window and context. Their indexes are zero and * a client can use them without calling CreateContext or WindowCreate. */ crDebug("Render SPU: Creating default window (visBits=0x%x, id=0)", render_spu.default_visual); defaultWin = renderspuWindowCreateEx( NULL, render_spu.default_visual, CR_RENDER_DEFAULT_WINDOW_ID ); if (defaultWin != CR_RENDER_DEFAULT_WINDOW_ID) { crError("Render SPU: Couldn't get a double-buffered, RGB visual with Z!"); return NULL; } crDebug( "Render SPU: WindowCreate returned %d (0=normal)", defaultWin ); crDebug("Render SPU: Creating default context, visBits=0x%x", render_spu.default_visual ); defaultCtx = renderspuCreateContextEx( NULL, render_spu.default_visual, CR_RENDER_DEFAULT_CONTEXT_ID, 0 ); if (defaultCtx != CR_RENDER_DEFAULT_CONTEXT_ID) { crError("Render SPU: failed to create default context!"); return NULL; } renderspuMakeCurrent( defaultWin, 0, defaultCtx ); /* Get windowInfo for the default window */ windowInfo = (WindowInfo *) crHashtableSearch(render_spu.windowTable, CR_RENDER_DEFAULT_WINDOW_ID); CRASSERT(windowInfo); windowInfo->mapPending = GL_TRUE; /* * Get the OpenGL extension functions. * SIGH -- we have to wait until the very bitter end to load the * extensions, because the context has to be bound before * wglGetProcAddress will work correctly. No such issue with GLX though. */ numFuncs += crLoadOpenGLExtensions( &render_spu.ws, _cr_render_table + numFuncs ); CRASSERT(numFuncs < 1000); #ifdef WINDOWS /* * Same problem as above, these are extensions so we need to * load them after a context has been bound. As they're WGL * extensions too, we can't simply tag them into the spu_loader. * So we do them here for now. * Grrr, NVIDIA driver uses EXT for GetExtensionsStringEXT, * but ARB for others. Need further testing here.... */ render_spu.ws.wglGetExtensionsStringEXT = (wglGetExtensionsStringEXTFunc_t) render_spu.ws.wglGetProcAddress( "wglGetExtensionsStringEXT" ); render_spu.ws.wglChoosePixelFormatEXT = (wglChoosePixelFormatEXTFunc_t) render_spu.ws.wglGetProcAddress( "wglChoosePixelFormatARB" ); render_spu.ws.wglGetPixelFormatAttribivEXT = (wglGetPixelFormatAttribivEXTFunc_t) render_spu.ws.wglGetProcAddress( "wglGetPixelFormatAttribivARB" ); render_spu.ws.wglGetPixelFormatAttribfvEXT = (wglGetPixelFormatAttribfvEXTFunc_t) render_spu.ws.wglGetProcAddress( "wglGetPixelFormatAttribfvARB" ); if (render_spu.ws.wglGetProcAddress("glCopyTexSubImage3D")) { _cr_render_table[numFuncs].name = crStrdup("CopyTexSubImage3D"); _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glCopyTexSubImage3D"); ++numFuncs; crDebug("Render SPU: Found glCopyTexSubImage3D function"); } if (render_spu.ws.wglGetProcAddress("glDrawRangeElements")) { _cr_render_table[numFuncs].name = crStrdup("DrawRangeElements"); _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glDrawRangeElements"); ++numFuncs; crDebug("Render SPU: Found glDrawRangeElements function"); } if (render_spu.ws.wglGetProcAddress("glTexSubImage3D")) { _cr_render_table[numFuncs].name = crStrdup("TexSubImage3D"); _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glTexSubImage3D"); ++numFuncs; crDebug("Render SPU: Found glTexSubImage3D function"); } if (render_spu.ws.wglGetProcAddress("glTexImage3D")) { _cr_render_table[numFuncs].name = crStrdup("TexImage3D"); _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glTexImage3D"); ++numFuncs; crDebug("Render SPU: Found glTexImage3D function"); } if (render_spu.ws.wglGetExtensionsStringEXT) { crDebug("WGL - found wglGetExtensionsStringEXT\n"); } if (render_spu.ws.wglChoosePixelFormatEXT) { crDebug("WGL - found wglChoosePixelFormatEXT\n"); } #endif render_spu.barrierHash = crAllocHashtable(); render_spu.cursorX = 0; render_spu.cursorY = 0; render_spu.use_L2 = 0; render_spu.gather_conns = NULL; numFuncs = renderspu_SystemPostprocessFunctions(_cr_render_table, numFuncs, RT_ELEMENTS(_cr_render_table)); crDebug("Render SPU: ---------- End of Init -------------"); return &render_functions; }
/** * Creates a new instance. * * @returns VBox status code. * @param pGlobals The globals. * @param pszName The instance name. * @param ppDevPort Where to store the pointer to our port interface. */ static int vboxPciNewInstance(PVBOXRAWPCIGLOBALS pGlobals, uint32_t u32HostAddress, uint32_t fFlags, PRAWPCIPERVM pVmCtx, PRAWPCIDEVPORT *ppDevPort, uint32_t *pfDevFlags) { int rc; PVBOXRAWPCIINS pNew = (PVBOXRAWPCIINS)RTMemAllocZ(sizeof(*pNew)); if (!pNew) return VERR_NO_MEMORY; pNew->pGlobals = pGlobals; pNew->hSpinlock = NIL_RTSPINLOCK; pNew->cRefs = 1; pNew->pNext = NULL; pNew->HostPciAddress = u32HostAddress; pNew->pVmCtx = pVmCtx; pNew->DevPort.u32Version = RAWPCIDEVPORT_VERSION; pNew->DevPort.pfnInit = vboxPciDevInit; pNew->DevPort.pfnDeinit = vboxPciDevDeinit; pNew->DevPort.pfnDestroy = vboxPciDevDestroy; pNew->DevPort.pfnGetRegionInfo = vboxPciDevGetRegionInfo; pNew->DevPort.pfnMapRegion = vboxPciDevMapRegion; pNew->DevPort.pfnUnmapRegion = vboxPciDevUnmapRegion; pNew->DevPort.pfnPciCfgRead = vboxPciDevPciCfgRead; pNew->DevPort.pfnPciCfgWrite = vboxPciDevPciCfgWrite; pNew->DevPort.pfnPciCfgRead = vboxPciDevPciCfgRead; pNew->DevPort.pfnPciCfgWrite = vboxPciDevPciCfgWrite; pNew->DevPort.pfnRegisterIrqHandler = vboxPciDevRegisterIrqHandler; pNew->DevPort.pfnUnregisterIrqHandler = vboxPciDevUnregisterIrqHandler; pNew->DevPort.pfnPowerStateChange = vboxPciDevPowerStateChange; pNew->DevPort.u32VersionEnd = RAWPCIDEVPORT_VERSION; rc = RTSpinlockCreate(&pNew->hSpinlock); if (RT_SUCCESS(rc)) { rc = RTSemFastMutexCreate(&pNew->hFastMtx); if (RT_SUCCESS(rc)) { rc = pNew->DevPort.pfnInit(&pNew->DevPort, fFlags); if (RT_SUCCESS(rc)) { *ppDevPort = &pNew->DevPort; pNew->pNext = pGlobals->pInstanceHead; pGlobals->pInstanceHead = pNew; } else { RTSemFastMutexDestroy(pNew->hFastMtx); RTSpinlockDestroy(pNew->hSpinlock); RTMemFree(pNew); } } } return rc; }
DECLHIDDEN(int) VUSBSnifferCreate(PVUSBSNIFFER phSniffer, uint32_t fFlags, const char *pszCaptureFilename, const char *pszDesc) { int rc = VINF_SUCCESS; PVUSBSNIFFERINT pThis = NULL; pThis = (PVUSBSNIFFERINT)RTMemAllocZ(sizeof(VUSBSNIFFERINT)); if (pThis) { pThis->hFile = NIL_RTFILE; pThis->cbBlockCur = 0; pThis->cbBlockMax = 0; pThis->pbBlockData = NULL; pThis->hMtx = NIL_RTSEMFASTMUTEX; rc = RTSemFastMutexCreate(&pThis->hMtx); if (RT_SUCCESS(rc)) { rc = RTFileOpen(&pThis->hFile, pszCaptureFilename, RTFILE_O_DENY_NONE | RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_READ); if (RT_SUCCESS(rc)) { /* Write header and link type blocks. */ DumpFileShb Shb; Shb.Hdr.u32BlockType = DUMPFILE_SHB_BLOCK_TYPE; Shb.Hdr.u32BlockTotalLength = 0; /* Filled out by lower layer. */ Shb.u32ByteOrderMagic = DUMPFILE_SHB_BYTE_ORDER_MAGIC; Shb.u16VersionMajor = DUMPFILE_SHB_VERSION_MAJOR; Shb.u16VersionMinor = DUMPFILE_SHB_VERSION_MINOR; Shb.u64SectionLength = UINT64_C(0xffffffffffffffff); /* -1 */ /* Write the blocks. */ rc = vusbSnifferBlockNew(pThis, &Shb.Hdr, sizeof(Shb)); if (RT_SUCCESS(rc)) { const char *pszOpt = RTBldCfgTargetDotArch(); rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_HARDWARE, pszOpt, strlen(pszOpt) + 1); } if (RT_SUCCESS(rc)) { char szTmp[512]; size_t cbTmp = sizeof(szTmp); RT_ZERO(szTmp); /* Build the OS code. */ rc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, cbTmp); if (RT_SUCCESS(rc)) { size_t cb = strlen(szTmp); szTmp[cb] = ' '; rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, &szTmp[cb + 1], cbTmp - (cb + 1)); if (RT_SUCCESS(rc)) { cb = strlen(szTmp); szTmp[cb] = ' '; rc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, &szTmp[cb + 1], cbTmp - (cb + 1)); } } if (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW) rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_OS, szTmp, strlen(szTmp) + 1); else rc = VINF_SUCCESS; /* Skip OS code if building the string failed. */ } if (RT_SUCCESS(rc)) { /** @todo: Add product info. */ } if (RT_SUCCESS(rc)) rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_END, NULL, 0); if (RT_SUCCESS(rc)) rc = vusbSnifferBlockCommit(pThis); /* Write Interface descriptor block. */ if (RT_SUCCESS(rc)) { DumpFileIdb Idb; Idb.Hdr.u32BlockType = DUMPFILE_IDB_BLOCK_TYPE; Idb.Hdr.u32BlockTotalLength = 0; /* Filled out by lower layer. */ Idb.u16LinkType = DUMPFILE_IDB_LINK_TYPE_USB_LINUX_MMAPED; Idb.u16Reserved = 0; Idb.u32SnapLen = UINT32_C(0xffffffff); rc = vusbSnifferBlockNew(pThis, &Idb.Hdr, sizeof(Idb)); if (RT_SUCCESS(rc)) { uint8_t u8TsResolution = 9; /* Nano second resolution. */ /* Add timestamp resolution option. */ rc = vusbSnifferAddOption(pThis, DUMPFILE_IDB_OPTION_TS_RESOLUTION, &u8TsResolution, sizeof(u8TsResolution)); } if (RT_SUCCESS(rc)) rc = vusbSnifferAddOption(pThis, DUMPFILE_OPTION_CODE_END, NULL, 0); if (RT_SUCCESS(rc)) rc = vusbSnifferBlockCommit(pThis); } if (RT_SUCCESS(rc)) { *phSniffer = pThis; return VINF_SUCCESS; } RTFileClose(pThis->hFile); pThis->hFile = NIL_RTFILE; RTFileDelete(pszCaptureFilename); } RTSemFastMutexDestroy(pThis->hMtx); pThis->hMtx = NIL_RTSEMFASTMUTEX; } RTMemFree(pThis); } else rc = VERR_NO_MEMORY; return rc; }