semeventmulti-r0drv-linux.c revision e6c7f0916ea395e9211fe5a004cebe5934521694
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync/* $Id$ */
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync/** @file
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, Linux.
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync */
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync/*
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * Copyright (C) 2006-2007 Oracle Corporation
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync *
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * available from http://www.virtualbox.org. This file is free software;
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * you can redistribute it and/or modify it under the terms of the GNU
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * General Public License (GPL) as published by the Free Software
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync *
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * The contents of this file may alternatively be used under the terms
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * of the Common Development and Distribution License Version 1.0
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * VirtualBox OSE distribution, in which case the provisions of the
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * CDDL are applicable instead of those of the GPL.
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync *
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * You may elect to license modified versions of this file under the
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * terms and conditions of either the GPL or the CDDL or both.
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync */
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync/*******************************************************************************
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync* Header Files *
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync*******************************************************************************/
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync#include "the-linux-kernel.h"
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync#include "internal/iprt.h"
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync#include <iprt/semaphore.h>
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync#include <iprt/alloc.h>
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync#include <iprt/assert.h>
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync#include <iprt/asm.h>
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync#include <iprt/err.h>
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync#include "internal/magics.h"
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync/*******************************************************************************
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync* Structures and Typedefs *
8a7af14e45ca3f1aadcad537ddf79f68a830748cvboxsync*******************************************************************************/
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync/**
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync * Linux event semaphore.
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync */
9d508d63ddd8cbaa227c3e3176bb376ba98ffa53vboxsynctypedef struct RTSEMEVENTMULTIINTERNAL
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync{
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync /** Magic value (RTSEMEVENTMULTI_MAGIC). */
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync uint32_t volatile u32Magic;
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync /** The object status - !0 when signaled and 0 when reset. */
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync uint32_t volatile fState;
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync /** The wait queue. */
9d508d63ddd8cbaa227c3e3176bb376ba98ffa53vboxsync wait_queue_head_t Head;
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync
218c5abcfe14c89d04353015e755a02447960018vboxsync
218c5abcfe14c89d04353015e755a02447960018vboxsync
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsyncRTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
9d508d63ddd8cbaa227c3e3176bb376ba98ffa53vboxsync{
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync}
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsyncRTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync const char *pszNameFmt, ...)
e7e589ca404045e288030a4151e57b63976cb39dvboxsync{
e7e589ca404045e288030a4151e57b63976cb39dvboxsync PRTSEMEVENTMULTIINTERNAL pThis;
e7e589ca404045e288030a4151e57b63976cb39dvboxsync
9d508d63ddd8cbaa227c3e3176bb376ba98ffa53vboxsync AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
9d508d63ddd8cbaa227c3e3176bb376ba98ffa53vboxsync if (pThis)
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync {
7255e1c7174fd3b892a74dede74e72557f6cced9vboxsync pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
7255e1c7174fd3b892a74dede74e72557f6cced9vboxsync pThis->fState = 0;
7255e1c7174fd3b892a74dede74e72557f6cced9vboxsync init_waitqueue_head(&pThis->Head);
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync *phEventMultiSem = pThis;
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync return VINF_SUCCESS;
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync }
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync return VERR_NO_MEMORY;
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync}
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsyncRT_EXPORT_SYMBOL(RTSemEventMultiCreate);
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsyncRTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync{
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync /*
7255e1c7174fd3b892a74dede74e72557f6cced9vboxsync * Validate input.
7255e1c7174fd3b892a74dede74e72557f6cced9vboxsync */
7255e1c7174fd3b892a74dede74e72557f6cced9vboxsync PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
7255e1c7174fd3b892a74dede74e72557f6cced9vboxsync if (pThis == NIL_RTSEMEVENTMULTI)
7255e1c7174fd3b892a74dede74e72557f6cced9vboxsync return VINF_SUCCESS;
9d508d63ddd8cbaa227c3e3176bb376ba98ffa53vboxsync AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
9d508d63ddd8cbaa227c3e3176bb376ba98ffa53vboxsync AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
9d508d63ddd8cbaa227c3e3176bb376ba98ffa53vboxsync
7255e1c7174fd3b892a74dede74e72557f6cced9vboxsync /*
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync * Invalidate it and signal the object just in case.
e45e3ae4a834169539e689759ba6b3ac71bfe40fvboxsync */
b4514c911ccdb647c9c0f503f3cee0660f41104avboxsync ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC);
218c5abcfe14c89d04353015e755a02447960018vboxsync ASMAtomicXchgU32(&pThis->fState, 0);
Assert(!waitqueue_active(&pThis->Head));
wake_up_all(&pThis->Head);
RTMemFree(pThis);
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTSemEventMultiDestroy);
RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
{
/*
* Validate input.
*/
PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
if (!pThis)
return VERR_INVALID_PARAMETER;
AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
/*
* Signal the event object.
*/
ASMAtomicXchgU32(&pThis->fState, 1);
wake_up_all(&pThis->Head);
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTSemEventMultiSignal);
RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
{
/*
* Validate input.
*/
PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
if (!pThis)
return VERR_INVALID_PARAMETER;
AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
/*
* Reset it.
*/
ASMAtomicXchgU32(&pThis->fState, 0);
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTSemEventMultiReset);
/**
* Worker for RTSemEventMulti and RTSemEventMultiNoResume.
*
* @returns VBox status code.
* @param pThis The event semaphore.
* @param cMillies The number of milliseconds to wait.
* @param fInterruptible Whether it's an interruptible wait or not.
*/
static int rtSemEventMultiWait(PRTSEMEVENTMULTIINTERNAL pThis, RTMSINTERVAL cMillies, bool fInterruptible)
{
/*
* Ok wait for it.
*/
DEFINE_WAIT(Wait);
int rc = VINF_SUCCESS;
long lTimeout = cMillies == RT_INDEFINITE_WAIT ? MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(cMillies);
#ifdef IPRT_DEBUG_SEMS
snprintf(current->comm, sizeof(current->comm), "E%lx", IPRT_DEBUG_SEMS_ADDRESS(pThis));
#endif
for (;;)
{
/* make everything thru schedule() atomic scheduling wise. */
prepare_to_wait(&pThis->Head, &Wait, fInterruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
/* check the condition. */
if (pThis->fState)
break;
/* check for pending signals. */
if (fInterruptible && signal_pending(current))
{
rc = VERR_INTERRUPTED;
break;
}
/* wait */
lTimeout = schedule_timeout(lTimeout);
after_wait(&Wait);
/* Check if someone destroyed the semaphore while we were waiting. */
if (pThis->u32Magic != RTSEMEVENTMULTI_MAGIC)
{
rc = VERR_SEM_DESTROYED;
break;
}
/* check for timeout. */
if (!lTimeout)
{
rc = VERR_TIMEOUT;
break;
}
}
finish_wait(&pThis->Head, &Wait);
#ifdef IPRT_DEBUG_SEMS
snprintf(current->comm, sizeof(current->comm), "E%lx:%d", IPRT_DEBUG_SEMS_ADDRESS(pThis), rc);
#endif
return rc;
}
RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
{
PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
if (!pThis)
return VERR_INVALID_PARAMETER;
AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
if (pThis->fState)
return VINF_SUCCESS;
return rtSemEventMultiWait(pThis, cMillies, false /* fInterruptible */);
}
RT_EXPORT_SYMBOL(RTSemEventMultiWait);
RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
{
PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
if (!pThis)
return VERR_INVALID_PARAMETER;
AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
if (pThis->fState)
return VINF_SUCCESS;
return rtSemEventMultiWait(pThis, cMillies, true /* fInterruptible */);
}
RT_EXPORT_SYMBOL(RTSemEventMultiWaitNoResume);