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