once.cpp revision 6e59cff536e8de93f15fa1fb6b46d0ee01e06829
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * IPRT - Execute Once.
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * Copyright (C) 2007 Sun Microsystems, Inc.
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * available from http://www.virtualbox.org. This file is free software;
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * you can redistribute it and/or modify it under the terms of the GNU
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * General Public License (GPL) as published by the Free Software
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * The contents of this file may alternatively be used under the terms
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * of the Common Development and Distribution License Version 1.0
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * VirtualBox OSE distribution, in which case the provisions of the
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * CDDL are applicable instead of those of the GPL.
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * You may elect to license modified versions of this file under the
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * terms and conditions of either the GPL or the CDDL or both.
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * additional information or have any questions.
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync/*******************************************************************************
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync* Header Files *
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync*******************************************************************************/
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsyncRTDECL(int) RTOnce(PRTONCE pOnce, PFNRTONCE pfnOnce, void *pvUser1, void *pvUser2)
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * Validate input (strict builds only).
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * Deal with the 'initialized' case first
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync int32_t iState = ASMAtomicUoReadS32(&pOnce->iState);
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync AssertReturn(iState == -1 || iState == 1, VERR_INTERNAL_ERROR);
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * Do we initialize it?
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync ASMAtomicWriteHandle(&pOnce->hEventMulti, hEventMulti);
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync /* do the execute once stuff. */
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync /* set the return code, change the state and signal any waiters. */
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync /* last guy destroys the semaphore. */
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync ASMAtomicWriteSize(&pOnce->hEventMulti, NIL_RTSEMEVENTMULTI);
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * Wait for it to finish initializing.
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * Take care not to increment the counter if it's 0, that indicates
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * that RTONCE::hEventMulti isn't valid either because it's not set
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * yet, or because it's being destroyed.
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync int32_t cEventRefs = ASMAtomicUoReadS32(&pOnce->cEventRefs);
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync && !ASMAtomicCmpXchgS32(&pOnce->cEventRefs, cEventRefs + 1, cEventRefs))
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync cEventRefs = ASMAtomicUoReadS32(&pOnce->cEventRefs);
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * The hEventMulti might be NIL for two reasons, see above in
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * the init code, if it isn't valid just do the yield/sleep thing.
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync ASMAtomicUoReadSize(&pOnce->hEventMulti, &hEventMulti);
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync RTSemEventMultiWait(hEventMulti, RT_INDEFINITE_WAIT);
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * Last thread cleans up.
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync ASMAtomicXchgHandle(&pOnce->hEventMulti, NIL_RTSEMEVENTMULTI, &hEventMulti);
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * If we didn't block, yield or sleep for a bit.
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * The sleep is essential to prevent higher priority threads from spinning wildly
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * and preventing a lower priority thread from completing the pfnOnce operation
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * in a timely manner.
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync if (!(++i % 8) )
33b0e5fd502b10034575ffa7c8a30c6816222ce2vboxsync * Finally, return the status code from the execute once function.
6e59cff536e8de93f15fa1fb6b46d0ee01e06829vboxsync /* Cannot be done while busy! */
6e59cff536e8de93f15fa1fb6b46d0ee01e06829vboxsync /* Do the same as RTONCE_INITIALIZER does. */