412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/* $Id$ */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/** @file
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * IPRT - Multiprocessor, Ring-0 Driver, Event Notifications.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/*
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2008-2013 Oracle Corporation
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * available from http://www.virtualbox.org. This file is free software;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * you can redistribute it and/or modify it under the terms of the GNU
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * General Public License (GPL) as published by the Free Software
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * The contents of this file may alternatively be used under the terms
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * of the Common Development and Distribution License Version 1.0
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * VirtualBox OSE distribution, in which case the provisions of the
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * CDDL are applicable instead of those of the GPL.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * You may elect to license modified versions of this file under the
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * terms and conditions of either the GPL or the CDDL or both.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/*******************************************************************************
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync* Header Files *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync*******************************************************************************/
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <iprt/mp.h>
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync#include "internal/iprt.h"
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <iprt/asm.h>
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync# include <iprt/asm-amd64-x86.h>
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#endif
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <iprt/assert.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <iprt/err.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <iprt/mem.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <iprt/spinlock.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include <iprt/string.h>
8c99dcd207cf5b7bee01f95fbe19728a94076f94vboxsync#include <iprt/thread.h>
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync#include "r0drv/mp-r0drv.h"
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/*******************************************************************************
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync* Structures and Typedefs *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync*******************************************************************************/
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/**
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Notification registration record tracking
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * RTMpRegisterNotification() calls.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsynctypedef struct RTMPNOTIFYREG
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync{
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /** Pointer to the next record. */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync struct RTMPNOTIFYREG * volatile pNext;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /** The callback. */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync PFNRTMPNOTIFICATION pfnCallback;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /** The user argument. */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync void *pvUser;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /** Bit mask indicating whether we've done this callback or not. */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync uint8_t bmDone[sizeof(void *)];
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync} RTMPNOTIFYREG;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/** Pointer to a registration record. */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsynctypedef RTMPNOTIFYREG *PRTMPNOTIFYREG;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/*******************************************************************************
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync* Global Variables *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync*******************************************************************************/
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/** The spinlock protecting the list. */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic RTSPINLOCK volatile g_hRTMpNotifySpinLock = NIL_RTSPINLOCK;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/** List of callbacks, in registration order. */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic PRTMPNOTIFYREG volatile g_pRTMpCallbackHead = NULL;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/** The current done bit. */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic uint32_t volatile g_iRTMpDoneBit;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/** The list generation.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * This is increased whenever the list has been modified. The callback routine
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * make use of this to avoid having restart at the list head after each callback. */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncstatic uint32_t volatile g_iRTMpGeneration;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync/**
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * This is called by the native code.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param idCpu The CPU id the event applies to.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * @param enmEvent The event.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync */
5eda82e218d35ae0691febd531e1bfc0324cc4a6vboxsyncDECLHIDDEN(void) rtMpNotificationDoCallbacks(RTMPEVENT enmEvent, RTCPUID idCpu)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync{
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync PRTMPNOTIFYREG pCur;
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync RTSPINLOCK hSpinlock;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /*
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * This is a little bit tricky as we cannot be holding the spinlock
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * while calling the callback. This means that the list might change
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * while we're walking it, and that multiple events might be running
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * concurrently (depending on the OS).
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * So, the first measure is to employ a 32-bitmask for each
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * record where we'll use a bit that rotates for each call to
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * this function to indicate which records that has been
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * processed. This will take care of both changes to the list
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * and a reasonable amount of concurrent events.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync *
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * In order to avoid having to restart the list walks for every
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * callback we make, we'll make use a list generation number that is
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * incremented everytime the list is changed. So, if it remains
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * unchanged over a callback we can safely continue the iteration.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync uint32_t iDone = ASMAtomicIncU32(&g_iRTMpDoneBit);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync iDone %= RT_SIZEOFMEMB(RTMPNOTIFYREG, bmDone) * 8;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync hSpinlock = g_hRTMpNotifySpinLock;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (hSpinlock == NIL_RTSPINLOCK)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return;
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockAcquire(hSpinlock);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /* Clear the bit. */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync for (pCur = g_pRTMpCallbackHead; pCur; pCur = pCur->pNext)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync ASMAtomicBitClear(&pCur->bmDone[0], iDone);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /* Iterate the records and perform the callbacks. */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync do
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync uint32_t const iGeneration = ASMAtomicUoReadU32(&g_iRTMpGeneration);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pCur = g_pRTMpCallbackHead;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync while (pCur)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (!ASMAtomicBitTestAndSet(&pCur->bmDone[0], iDone))
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync PFNRTMPNOTIFICATION pfnCallback = pCur->pfnCallback;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync void *pvUser = pCur->pvUser;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pCur = pCur->pNext;
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(g_hRTMpNotifySpinLock);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pfnCallback(enmEvent, idCpu, pvUser);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /* carefully require the lock here, see RTR0MpNotificationTerm(). */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync hSpinlock = g_hRTMpNotifySpinLock;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (hSpinlock == NIL_RTSPINLOCK)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return;
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockAcquire(hSpinlock);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (ASMAtomicUoReadU32(&g_iRTMpGeneration) != iGeneration)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync break;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync else
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pCur = pCur->pNext;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync } while (pCur);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(hSpinlock);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync}
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncRTDECL(int) RTMpNotificationRegister(PFNRTMPNOTIFICATION pfnCallback, void *pvUser)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync{
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync PRTMPNOTIFYREG pCur;
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync PRTMPNOTIFYREG pNew;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /*
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Validation.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync AssertReturn(g_hRTMpNotifySpinLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
8c99dcd207cf5b7bee01f95fbe19728a94076f94vboxsync RT_ASSERT_PREEMPTIBLE();
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockAcquire(g_hRTMpNotifySpinLock);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync for (pCur = g_pRTMpCallbackHead; pCur; pCur = pCur->pNext)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if ( pCur->pvUser == pvUser
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync && pCur->pfnCallback == pfnCallback)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync break;
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(g_hRTMpNotifySpinLock);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync AssertMsgReturn(!pCur, ("pCur=%p pfnCallback=%p pvUser=%p\n", pCur, pfnCallback, pvUser), VERR_ALREADY_EXISTS);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /*
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Allocate a new record and attempt to insert it.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pNew = (PRTMPNOTIFYREG)RTMemAlloc(sizeof(*pNew));
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (!pNew)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return VERR_NO_MEMORY;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pNew->pNext = NULL;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pNew->pfnCallback = pfnCallback;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pNew->pvUser = pvUser;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync memset(&pNew->bmDone[0], 0xff, sizeof(pNew->bmDone));
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockAcquire(g_hRTMpNotifySpinLock);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pCur = g_pRTMpCallbackHead;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (!pCur)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync g_pRTMpCallbackHead = pNew;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync else
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync for (pCur = g_pRTMpCallbackHead; ; pCur = pCur->pNext)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if ( pCur->pvUser == pvUser
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync && pCur->pfnCallback == pfnCallback)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync break;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync else if (!pCur->pNext)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pCur->pNext = pNew;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pCur = NULL;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync break;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync ASMAtomicIncU32(&g_iRTMpGeneration);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(g_hRTMpNotifySpinLock);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /* duplicate? */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (pCur)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync RTMemFree(pCur);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync AssertMsgFailedReturn(("pCur=%p pfnCallback=%p pvUser=%p\n", pCur, pfnCallback, pvUser), VERR_ALREADY_EXISTS);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return VINF_SUCCESS;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTMpNotificationRegister);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsyncRTDECL(int) RTMpNotificationDeregister(PFNRTMPNOTIFICATION pfnCallback, void *pvUser)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync{
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync PRTMPNOTIFYREG pPrev;
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync PRTMPNOTIFYREG pCur;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /*
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Validation.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync AssertReturn(g_hRTMpNotifySpinLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
8c99dcd207cf5b7bee01f95fbe19728a94076f94vboxsync RT_ASSERT_INTS_ON();
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /*
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Find and unlink the record from the list.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync */
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockAcquire(g_hRTMpNotifySpinLock);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pPrev = NULL;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync for (pCur = g_pRTMpCallbackHead; pCur; pCur = pCur->pNext)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if ( pCur->pvUser == pvUser
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync && pCur->pfnCallback == pfnCallback)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync break;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pPrev = pCur;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (pCur)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (pPrev)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pPrev->pNext = pCur->pNext;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync else
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync g_pRTMpCallbackHead = pCur->pNext;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync ASMAtomicIncU32(&g_iRTMpGeneration);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(g_hRTMpNotifySpinLock);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (!pCur)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return VERR_NOT_FOUND;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync /*
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync * Invalidate and free the record.
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync */
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pCur->pNext = NULL;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync pCur->pfnCallback = NULL;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync RTMemFree(pCur);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return VINF_SUCCESS;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTMpNotificationDeregister);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
5eda82e218d35ae0691febd531e1bfc0324cc4a6vboxsyncDECLHIDDEN(int) rtR0MpNotificationInit(void)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync{
4904fa0280dc21e724cf7eaac5c959534b47b9b9vboxsync int rc = RTSpinlockCreate((PRTSPINLOCK)&g_hRTMpNotifySpinLock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "RTR0Mp");
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync if (RT_SUCCESS(rc))
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync {
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync rc = rtR0MpNotificationNativeInit();
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync if (RT_SUCCESS(rc))
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync return rc;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync RTSpinlockDestroy(g_hRTMpNotifySpinLock);
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync g_hRTMpNotifySpinLock = NIL_RTSPINLOCK;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync return rc;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync}
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
5eda82e218d35ae0691febd531e1bfc0324cc4a6vboxsyncDECLHIDDEN(void) rtR0MpNotificationTerm(void)
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync{
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync PRTMPNOTIFYREG pHead;
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync RTSPINLOCK hSpinlock = g_hRTMpNotifySpinLock;
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync AssertReturnVoid(hSpinlock != NIL_RTSPINLOCK);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync rtR0MpNotificationNativeTerm();
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync /* pick up the list and the spinlock. */
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockAcquire(hSpinlock);
81cfcb51c89626fd5d331d92dcec81c94a5e9d2fvboxsync ASMAtomicWriteHandle(&g_hRTMpNotifySpinLock, NIL_RTSPINLOCK);
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync pHead = g_pRTMpCallbackHead;
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync g_pRTMpCallbackHead = NULL;
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync ASMAtomicIncU32(&g_iRTMpGeneration);
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(hSpinlock);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync /* free the list. */
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync while (pHead)
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync {
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync PRTMPNOTIFYREG pFree = pHead;
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync pHead = pHead->pNext;
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync pFree->pNext = NULL;
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync pFree->pfnCallback = NULL;
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync RTMemFree(pFree);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync }
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync
7b6f8773dac1008543c95f9a606db09ebe3c97cavboxsync RTSpinlockDestroy(hSpinlock);
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync}
412ad5bac323727b4073056113e1d8e0faf60db3vboxsync