mpnotification-r0drv.c revision 81cfcb51c89626fd5d331d92dcec81c94a5e9d2f
77b1a2d8b5dbe2c0b5200794914239fee3c8ee5dvboxsync * IPRT - Multiprocessor, Ring-0 Driver, Event Notifications.
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2008-2010 Oracle Corporation
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 * 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.
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.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*******************************************************************************
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync* Header Files *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync*******************************************************************************/
efff36b306e370346025647a158689021df2e1d1vboxsync/*******************************************************************************
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync* Structures and Typedefs *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync*******************************************************************************/
efff36b306e370346025647a158689021df2e1d1vboxsync * Notification registration record tracking
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * RTMpRegisterNotification() calls.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /** Pointer to the next record. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /** The callback. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /** The user argument. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /** Bit mask indicating whether we've done this callback or not. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** Pointer to a registration record. */
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. */
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. */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * This is called by the native code.
c0a370e600bb60153a269fb32b5f709347c35768vboxsync * @param idCpu The CPU id the event applies to.
c0a370e600bb60153a269fb32b5f709347c35768vboxsync * @param enmEvent The event.
c0a370e600bb60153a269fb32b5f709347c35768vboxsyncDECLHIDDEN(void) rtMpNotificationDoCallbacks(RTMPEVENT enmEvent, RTCPUID idCpu)
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 * 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.
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 /* Clear the bit. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync for (pCur = g_pRTMpCallbackHead; pCur; pCur = pCur->pNext)
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* Iterate the records and perform the callbacks. */
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync uint32_t const iGeneration = ASMAtomicUoReadU32(&g_iRTMpGeneration);
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (!ASMAtomicBitTestAndSet(&pCur->bmDone[0], iDone))
21029597fc4b76d0db0c9542daee201447281781vboxsync PFNRTMPNOTIFICATION pfnCallback = pCur->pfnCallback;
16a9adc14900ca18e6909679a579f6833425e030vboxsync /* carefully require the lock here, see RTR0MpNotificationTerm(). */
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync if (ASMAtomicUoReadU32(&g_iRTMpGeneration) != iGeneration)
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsyncRTDECL(int) RTMpNotificationRegister(PFNRTMPNOTIFICATION pfnCallback, void *pvUser)
16a9adc14900ca18e6909679a579f6833425e030vboxsync * Validation.
16a9adc14900ca18e6909679a579f6833425e030vboxsync AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
16a9adc14900ca18e6909679a579f6833425e030vboxsync AssertReturn(g_hRTMpNotifySpinLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync for (pCur = g_pRTMpCallbackHead; pCur; pCur = pCur->pNext)
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync AssertMsgReturn(!pCur, ("pCur=%p pfnCallback=%p pvUser=%p\n", pCur, pfnCallback, pvUser), VERR_ALREADY_EXISTS);
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync * Allocate a new record and attempt to insert it.
681fd85cc7cd49e9cf66a917d6ae9ff36eb7d9e9vboxsync memset(&pNew->bmDone[0], 0xff, sizeof(pNew->bmDone));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync for (pCur = g_pRTMpCallbackHead; ; pCur = pCur->pNext)
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync /* duplicate? */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync AssertMsgFailedReturn(("pCur=%p pfnCallback=%p pvUser=%p\n", pCur, pfnCallback, pvUser), VERR_ALREADY_EXISTS);
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsyncRTDECL(int) RTMpNotificationDeregister(PFNRTMPNOTIFICATION pfnCallback, void *pvUser)
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * Validation.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync AssertReturn(g_hRTMpNotifySpinLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
16a9adc14900ca18e6909679a579f6833425e030vboxsync * Find and unlink the record from the list.
16a9adc14900ca18e6909679a579f6833425e030vboxsync for (pCur = g_pRTMpCallbackHead; pCur; pCur = pCur->pNext)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * Invalidate and free the record.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync int rc = RTSpinlockCreate((PRTSPINLOCK)&g_hRTMpNotifySpinLock);
a9d49c8f2b28a72e6a4db86eee91e4569290157bvboxsync /* pick up the list and the spinlock. */
a9d49c8f2b28a72e6a4db86eee91e4569290157bvboxsync ASMAtomicWriteHandle(&g_hRTMpNotifySpinLock, NIL_RTSPINLOCK);
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* free the list. */