threadctxhooks-r0drv-linux.c revision e82dbec0ddc5bd92d0501af680082176f0fb0930
248c89033c87fed7229aa29bbbc4f4698fb13687vboxsync * IPRT - Thread-Context Hook, Ring-0 Driver, Linux.
248c89033c87fed7229aa29bbbc4f4698fb13687vboxsync * Copyright (C) 2013 Oracle Corporation
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * available from http://www.virtualbox.org. This file is free software;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * General Public License (GPL) as published by the Free Software
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * The contents of this file may alternatively be used under the terms
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * of the Common Development and Distribution License Version 1.0
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * VirtualBox OSE distribution, in which case the provisions of the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * CDDL are applicable instead of those of the GPL.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * You may elect to license modified versions of this file under the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * terms and conditions of either the GPL or the CDDL or both.
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync/*******************************************************************************
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync* Header Files *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync*******************************************************************************/
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * Linux kernel 2.6.23 introduced thread-context hooks but RedHat 2.6.18 kernels
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * got it backported.
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) && defined(CONFIG_PREEMPT_NOTIFIERS)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/*******************************************************************************
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync* Structures and Typedefs *
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync*******************************************************************************/
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * The internal thread-context object.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync /** Magic value (RTTHREADCTXINT_MAGIC). */
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync /** The thread handle (owner) for which the context-hooks are registered. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The preemption notifier object. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Whether this handle has any hooks registered or not. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Pointer to the registered thread-context hook. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** User argument passed to the thread-context hook. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The thread-context operations. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The reference count for this object. */
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * Hook function for the thread-preempting event.
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * @param pPreemptNotifier Pointer to the preempt_notifier struct.
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * @param pNext Pointer to the task that is preempting the
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * current thread.
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * @remarks Called with the rq (runqueue) lock held and with preemption and
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync * interrupts disabled!
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsyncstatic void rtThreadCtxHooksLnxSchedOut(struct preempt_notifier *pPreemptNotifier, struct task_struct *pNext)
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync PRTTHREADCTXINT pThis = RT_FROM_MEMBER(pPreemptNotifier, RTTHREADCTXINT, hPreemptNotifier);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pThis->pfnThreadCtxHook(RTTHREADCTXEVENT_PREEMPTING, pThis->pvUser);
ffb50166c9adb4ae583b914d405197035cf890advboxsync * Hook function for the thread-resumed event.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pPreemptNotifier Pointer to the preempt_notifier struct.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param iCpu The CPU this thread is scheduled on.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @remarks Called without holding the rq (runqueue) lock and with preemption
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic void rtThreadCtxHooksLnxSchedIn(struct preempt_notifier *pPreemptNotifier, int iCpu)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PRTTHREADCTXINT pThis = RT_FROM_MEMBER(pPreemptNotifier, RTTHREADCTXINT, hPreemptNotifier);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pThis->pfnThreadCtxHook(RTTHREADCTXEVENT_RESUMED, pThis->pvUser);
248c89033c87fed7229aa29bbbc4f4698fb13687vboxsync * Worker function for RTThreadCtxHooks(Deregister|Release)().
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pThis Pointer to the internal thread-context object.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncDECLINLINE(void) rtThreadCtxHooksDeregister(PRTTHREADCTXINT pThis)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync preempt_notifier_unregister(&pThis->hPreemptNotifier);
b4d7b4dbcc45b8bde7502aa129440d92d7ffd038vboxsyncRTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pThis = (PRTTHREADCTXINT)RTMemAllocZ(sizeof(*pThis));
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync preempt_notifier_init(&pThis->hPreemptNotifier, &pThis->hPreemptOps);
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsyncRTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync * Validate input.
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsyncRTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync * Validate input.
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync * If there's still a registered thread-context hook, deregister it now before destroying the object.
462e60a19d02a99b2b1a5c08dff74bb0808d707cvboxsync * Paranoia... but since these are ring-0 threads we can't be too careful.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXINT_MAGIC);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncRTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnThreadCtxHook, void *pvUser)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Validate input.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Register the callback.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pThis->hPreemptOps.sched_out = rtThreadCtxHooksLnxSchedOut;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pThis->hPreemptOps.sched_in = rtThreadCtxHooksLnxSchedIn;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync preempt_notifier_register(&pThis->hPreemptNotifier);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncRTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Validate input.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Deregister the callback.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncRTDECL(bool) RTThreadCtxHooksAreRegistered(RTTHREADCTX hThreadCtx)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Validate input.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return false;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync AssertMsg(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#else /* Not supported / Not needed */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncRTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncRTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncRTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
5c9a5681751a936cd9fe7e98d9f30de34bc99372vboxsyncRTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnThreadCtxHook, void *pvUser)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsyncRTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx)
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsyncRTDECL(bool) RTThreadCtxHooksAreRegistered(RTTHREADCTX hThreadCtx)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return false;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#endif /* Not supported / Not needed */