/** * Lazy initialization of the m_pWorkLoop member. * * @returns m_pWorkLoop. */ IOWorkLoop *org_virtualbox_VBoxGuest::getWorkLoop() { /** @todo r=bird: This is actually a classic RTOnce scenario, except it's * tied to a org_virtualbox_VBoxGuest instance. */ /* * Handle the case when work loop was not created yet. */ if (ASMAtomicCmpXchgU8(&g_fWorkLoopCreated, VBOXGUEST_OBJECT_INITIALIZING, VBOXGUEST_OBJECT_UNINITIALIZED)) { m_pWorkLoop = IOWorkLoop::workLoop(); if (m_pWorkLoop) { /* Notify the rest of threads about the fact that work * loop was successully allocated and can be safely used */ Log(("VBoxGuest: created new work loop\n")); ASMAtomicWriteU8(&g_fWorkLoopCreated, VBOXGUEST_OBJECT_INITIALIZED); } else { /* Notify the rest of threads about the fact that there was * an error during allocation of a work loop */ Log(("VBoxGuest: failed to create new work loop!\n")); ASMAtomicWriteU8(&g_fWorkLoopCreated, VBOXGUEST_OBJECT_UNINITIALIZED); } } /* * Handle the case when work loop is already create or * in the process of being. */ else { uint8_t fWorkLoopCreated = ASMAtomicReadU8(&g_fWorkLoopCreated); while (fWorkLoopCreated == VBOXGUEST_OBJECT_INITIALIZING) { thread_block(0); fWorkLoopCreated = ASMAtomicReadU8(&g_fWorkLoopCreated); } if (fWorkLoopCreated != VBOXGUEST_OBJECT_INITIALIZED) Log(("VBoxGuest: No work loop!\n")); } return m_pWorkLoop; }
IOWorkLoop * org_virtualbox_VBoxGuest::getWorkLoop() { /* Handle the case when work loop was not created yet */ if(ASMAtomicCmpXchgU8(&g_fWorkLoopCreated, VBOXGUEST_OBJECT_INITIALIZING, VBOXGUEST_OBJECT_UNINITIALIZED)) { m_pWorkLoop = IOWorkLoop::workLoop(); if (m_pWorkLoop) { /* Notify the rest of threads about the fact that work * loop was successully allocated and can be safely used */ PDEBUG("created new work loop\n"); ASMAtomicWriteU8(&g_fWorkLoopCreated, VBOXGUEST_OBJECT_INITIALIZED); } else { /* Notify the rest of threads about the fact that there was * an error during allocation of a work loop */ PDEBUG("unable new work loop\n"); ASMAtomicWriteU8(&g_fWorkLoopCreated, VBOXGUEST_OBJECT_UNINITIALIZED); } } else { /* Handle the case when work loop is currently being * created or it was previously failed to create */ uint8_t fWorkLoopCreated = VBOXGUEST_OBJECT_INVALID; while (fWorkLoopCreated != VBOXGUEST_OBJECT_INITIALIZED && fWorkLoopCreated != VBOXGUEST_OBJECT_UNINITIALIZED) { fWorkLoopCreated = ASMAtomicReadU8(&g_fWorkLoopCreated); thread_block(0); } if (fWorkLoopCreated == VBOXGUEST_OBJECT_INITIALIZED) PDEBUG("returned existing work loop"); else PDEBUG("work loop was not allocated correctly"); } return m_pWorkLoop; }
/** * Get VBoxVFS root vnode. * * Handle three cases here: * - vnode does not exist yet: create a new one * - currently creating vnode: wait till the end, increment usage count and return existing one * - vnode already created: increment usage count and return existing one * - vnode was failed to create: give a chance to try to re-create it later * * @param mp Mount data provided by VFS layer. * @param ppVnode vnode to return. * @param pContext kAuth context needed in order to authentificate mount operation. * * @return 0 on success or BSD error code otherwise. */ static int vboxvfs_root(struct mount *mp, struct vnode **ppVnode, vfs_context_t pContext) { NOREF(pContext); vboxvfs_mount_t *pMount; int rc = 0; uint32_t vid; PDEBUG("Getting root vnode..."); AssertReturn(mp, EINVAL); AssertReturn(ppVnode, EINVAL); pMount = (vboxvfs_mount_t *)vfs_fsprivate(mp); AssertReturn(pMount, EINVAL); /* Check case when vnode does not exist yet */ if (ASMAtomicCmpXchgU8(&pMount->fRootVnodeState, VBOXVFS_OBJECT_INITIALIZING, VBOXVFS_OBJECT_UNINITIALIZED)) { PDEBUG("Create new root vnode"); /* Allocate empty SHFLSTRING to indicate path to root vnode within Shared Folder */ char szEmpty[1]; SHFLSTRING *pSFVnodePath; pSFVnodePath = vboxvfs_construct_shflstring((char *)szEmpty, 0); if (pSFVnodePath) { int rc2; rc2 = vboxvfs_create_vnode_internal(mp, VDIR, NULL, TRUE, pSFVnodePath, &pMount->pRootVnode); if (rc2 != 0) { RTMemFree(pSFVnodePath); rc = ENOTSUP; } } else rc = ENOMEM; /* Notify other threads about result */ if (rc == 0) ASMAtomicWriteU8(&pMount->fRootVnodeState, VBOXVFS_OBJECT_INITIALIZED); else ASMAtomicWriteU8(&pMount->fRootVnodeState, VBOXVFS_OBJECT_INVALID); } else { /* Check case if we are currently creating vnode. Wait while other thread to finish allocation. */ uint8_t fRootVnodeState = VBOXVFS_OBJECT_UNINITIALIZED; while (fRootVnodeState != VBOXVFS_OBJECT_INITIALIZED && fRootVnodeState != VBOXVFS_OBJECT_INVALID) { /* @todo: Currently, we are burning CPU cycles while waiting. This is for a short * time but we should relax here! */ fRootVnodeState = ASMAtomicReadU8(&pMount->fRootVnodeState); } /* Check if the other thread initialized root vnode and it is ready to be returned */ if (fRootVnodeState == VBOXVFS_OBJECT_INITIALIZED) { /* Take care about iocount */ vid = vnode_vid(pMount->pRootVnode); rc = vnode_getwithvid(pMount->pRootVnode, vid); } else { /* Other thread reported initialization failure. * Set vnode state VBOXVFS_OBJECT_UNINITIALIZED in order to try recreate root * vnode in other attempt */ ASMAtomicWriteU8(&pMount->fRootVnodeState, VBOXVFS_OBJECT_UNINITIALIZED); } } /* Only return vnode if we got success */ if (rc == 0) { PDEBUG("Root vnode can be returned"); *ppVnode = pMount->pRootVnode; } else PDEBUG("Root vnode cannot be returned: 0x%X", rc); return rc; }