1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync/* $Id$ */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync/** @file
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * IPRT - Thread-Context Hook, Ring-0 Driver, Linux.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync/*
9a0e6916879b853871c27de021935fd6a53a863bvboxsync * Copyright (C) 2013-2015 Oracle Corporation
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync *
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * available from http://www.virtualbox.org. This file is free software;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * you can redistribute it and/or modify it under the terms of the GNU
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * General Public License (GPL) as published by the Free Software
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync *
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * The contents of this file may alternatively be used under the terms
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * of the Common Development and Distribution License Version 1.0
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * VirtualBox OSE distribution, in which case the provisions of the
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * CDDL are applicable instead of those of the GPL.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync *
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * You may elect to license modified versions of this file under the
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * terms and conditions of either the GPL or the CDDL or both.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync/*******************************************************************************
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync* Header Files *
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync*******************************************************************************/
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync#include "the-linux-kernel.h"
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync#include "internal/iprt.h"
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync#include <iprt/mem.h>
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync#include <iprt/assert.h>
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync#include <iprt/thread.h>
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync#include <iprt/err.h>
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync#include <iprt/asm.h>
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync# include <iprt/asm-amd64-x86.h>
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync#endif
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync#include "internal/thread.h"
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
182a3087d3263266f37fc8c86377a1cc177c4b80vboxsync/*
1cd55a40a30997c1baf5b231a5bb88b6f8f047e5vboxsync * Linux kernel 2.6.23 introduced thread-context hooks but RedHat 2.6.18 kernels
1cd55a40a30997c1baf5b231a5bb88b6f8f047e5vboxsync * got it backported.
182a3087d3263266f37fc8c86377a1cc177c4b80vboxsync */
1cd55a40a30997c1baf5b231a5bb88b6f8f047e5vboxsync#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) && defined(CONFIG_PREEMPT_NOTIFIERS)
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync/*******************************************************************************
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync* Structures and Typedefs *
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync*******************************************************************************/
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync/**
2a7c2c6cf74b4bf69770343650059641a1c00a6avboxsync * The internal thread-context object.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsynctypedef struct RTTHREADCTXINT
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync{
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync /** Magic value (RTTHREADCTXINT_MAGIC). */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync uint32_t volatile u32Magic;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync /** The thread handle (owner) for which the context-hooks are registered. */
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync RTNATIVETHREAD hOwner;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync /** The preemption notifier object. */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync struct preempt_notifier hPreemptNotifier;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync /** Whether this handle has any hooks registered or not. */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync bool fRegistered;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync /** Pointer to the registered thread-context hook. */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync PFNRTTHREADCTXHOOK pfnThreadCtxHook;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync /** User argument passed to the thread-context hook. */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync void *pvUser;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync /** The thread-context operations. */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync struct preempt_ops hPreemptOps;
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync /** The reference count for this object. */
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync uint32_t volatile cRefs;
9a0e6916879b853871c27de021935fd6a53a863bvboxsync#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 19) && defined(RT_ARCH_AMD64)
9a0e6916879b853871c27de021935fd6a53a863bvboxsync /** Starting with 3.1.19, the linux kernel doesn't restore kernel RFLAGS during
9a0e6916879b853871c27de021935fd6a53a863bvboxsync * task switch, so we have to do that ourselves. (x86 code is not affected.) */
9a0e6916879b853871c27de021935fd6a53a863bvboxsync RTCCUINTREG fSavedRFlags;
9a0e6916879b853871c27de021935fd6a53a863bvboxsync#endif
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync} RTTHREADCTXINT, *PRTTHREADCTXINT;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync/**
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * Hook function for the thread-preempting event.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync *
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * @param pPreemptNotifier Pointer to the preempt_notifier struct.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * @param pNext Pointer to the task that is preempting the
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * current thread.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync *
81fc67afdb6f5cfe155abe26e8a9b0a3a87a316dvboxsync * @remarks Called with the rq (runqueue) lock held and with preemption and
81fc67afdb6f5cfe155abe26e8a9b0a3a87a316dvboxsync * interrupts disabled!
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsyncstatic void rtThreadCtxHooksLnxSchedOut(struct preempt_notifier *pPreemptNotifier, struct task_struct *pNext)
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync{
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync PRTTHREADCTXINT pThis = RT_FROM_MEMBER(pPreemptNotifier, RTTHREADCTXINT, hPreemptNotifier);
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync RTCCUINTREG fSavedEFlags = ASMGetFlags();
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync stac();
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync#endif
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync AssertPtr(pThis);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync AssertPtr(pThis->pfnThreadCtxHook);
c3d815a42d27fd8f006bade5dba5d5f4b364655evboxsync Assert(pThis->fRegistered);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync pThis->pfnThreadCtxHook(RTTHREADCTXEVENT_PREEMPTING, pThis->pvUser);
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync ASMSetFlags(fSavedEFlags);
9a0e6916879b853871c27de021935fd6a53a863bvboxsync# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 19) && defined(RT_ARCH_AMD64)
9a0e6916879b853871c27de021935fd6a53a863bvboxsync pThis->fSavedRFlags = fSavedEFlags;
9a0e6916879b853871c27de021935fd6a53a863bvboxsync# endif
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync#endif
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync}
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync/**
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * Hook function for the thread-resumed event.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync *
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * @param pPreemptNotifier Pointer to the preempt_notifier struct.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * @param iCpu The CPU this thread is scheduled on.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync *
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * @remarks Called without holding the rq (runqueue) lock and with preemption
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * enabled!
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsyncstatic void rtThreadCtxHooksLnxSchedIn(struct preempt_notifier *pPreemptNotifier, int iCpu)
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync{
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync PRTTHREADCTXINT pThis = RT_FROM_MEMBER(pPreemptNotifier, RTTHREADCTXINT, hPreemptNotifier);
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync RTCCUINTREG fSavedEFlags = ASMGetFlags();
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync stac();
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync#endif
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync AssertPtr(pThis);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync AssertPtr(pThis->pfnThreadCtxHook);
8d89dea452618bdc9ca59b93bdc15d3e746a416evboxsync Assert(pThis->fRegistered);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync pThis->pfnThreadCtxHook(RTTHREADCTXEVENT_RESUMED, pThis->pvUser);
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
9a0e6916879b853871c27de021935fd6a53a863bvboxsync# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 19) && defined(RT_ARCH_AMD64)
9a0e6916879b853871c27de021935fd6a53a863bvboxsync fSavedEFlags &= ~RT_BIT_64(18) /*X86_EFL_AC*/;
9a0e6916879b853871c27de021935fd6a53a863bvboxsync fSavedEFlags |= pThis->fSavedRFlags & RT_BIT_64(18) /*X86_EFL_AC*/;
9a0e6916879b853871c27de021935fd6a53a863bvboxsync# endif
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync ASMSetFlags(fSavedEFlags);
e82dbec0ddc5bd92d0501af680082176f0fb0930vboxsync#endif
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync}
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync/**
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync * Worker function for RTThreadCtxHooks(Deregister|Release)().
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync *
2a7c2c6cf74b4bf69770343650059641a1c00a6avboxsync * @param pThis Pointer to the internal thread-context object.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsyncDECLINLINE(void) rtThreadCtxHooksDeregister(PRTTHREADCTXINT pThis)
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync{
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync preempt_notifier_unregister(&pThis->hPreemptNotifier);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync pThis->hPreemptOps.sched_out = NULL;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync pThis->hPreemptOps.sched_in = NULL;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync pThis->fRegistered = false;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync}
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsyncRTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx)
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync{
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync PRTTHREADCTXINT pThis;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync pThis = (PRTTHREADCTXINT)RTMemAllocZ(sizeof(*pThis));
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync if (RT_UNLIKELY(!pThis))
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync return VERR_NO_MEMORY;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync pThis->u32Magic = RTTHREADCTXINT_MAGIC;
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync pThis->hOwner = RTThreadNativeSelf();
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync pThis->fRegistered = false;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync preempt_notifier_init(&pThis->hPreemptNotifier, &pThis->hPreemptOps);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync pThis->cRefs = 1;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync *phThreadCtx = pThis;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync return VINF_SUCCESS;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync}
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsyncRT_EXPORT_SYMBOL(RTThreadCtxHooksCreate);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
094bd1aaada16d47495d62f7c3324f9df84c999avboxsyncRTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync{
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync /*
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * Validate input.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync */
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync uint32_t cRefs;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync PRTTHREADCTXINT pThis = hThreadCtx;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync AssertPtr(pThis);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync UINT32_MAX);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync cRefs = ASMAtomicIncU32(&pThis->cRefs);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync Assert(cRefs < UINT32_MAX / 2);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync return cRefs;
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync}
094bd1aaada16d47495d62f7c3324f9df84c999avboxsyncRT_EXPORT_SYMBOL(RTThreadCtxHooksRetain);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
094bd1aaada16d47495d62f7c3324f9df84c999avboxsyncRTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync{
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync /*
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync * Validate input.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync */
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync uint32_t cRefs;
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync PRTTHREADCTXINT pThis = hThreadCtx;
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync if (pThis == NIL_RTTHREADCTX)
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync return 0;
27f4d2f49f23fdb722ed0e3d78045d58756497bfvboxsync
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync AssertPtr(pThis);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync UINT32_MAX);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync cRefs = ASMAtomicDecU32(&pThis->cRefs);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync if (!cRefs)
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync {
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync /*
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync * If there's still a registered thread-context hook, deregister it now before destroying the object.
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync */
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync if (pThis->fRegistered)
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync rtThreadCtxHooksDeregister(pThis);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync /*
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync * Paranoia... but since these are ring-0 threads we can't be too careful.
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync */
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync Assert(!pThis->fRegistered);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync Assert(!pThis->hPreemptOps.sched_out);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync Assert(!pThis->hPreemptOps.sched_in);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXINT_MAGIC);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync RTMemFree(pThis);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync }
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync else
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync Assert(cRefs < UINT32_MAX / 2);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync return cRefs;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync}
094bd1aaada16d47495d62f7c3324f9df84c999avboxsyncRT_EXPORT_SYMBOL(RTThreadCtxHooksRelease);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsyncRTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnThreadCtxHook, void *pvUser)
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync{
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync /*
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * Validate input.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync PRTTHREADCTXINT pThis = hThreadCtx;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync if (pThis == NIL_RTTHREADCTX)
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync return VERR_INVALID_HANDLE;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync AssertPtr(pThis);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync VERR_INVALID_HANDLE);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync Assert(pThis->hOwner == RTThreadNativeSelf());
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync Assert(!pThis->hPreemptOps.sched_out);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync Assert(!pThis->hPreemptOps.sched_in);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync /*
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * Register the callback.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync pThis->hPreemptOps.sched_out = rtThreadCtxHooksLnxSchedOut;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync pThis->hPreemptOps.sched_in = rtThreadCtxHooksLnxSchedIn;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync pThis->pvUser = pvUser;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync pThis->pfnThreadCtxHook = pfnThreadCtxHook;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync pThis->fRegistered = true;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync preempt_notifier_register(&pThis->hPreemptNotifier);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync return VINF_SUCCESS;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync}
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsyncRT_EXPORT_SYMBOL(RTThreadCtxHooksRegister);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsyncRTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx)
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync{
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync /*
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * Validate input.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync PRTTHREADCTXINT pThis = hThreadCtx;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync if (pThis == NIL_RTTHREADCTX)
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync return VERR_INVALID_HANDLE;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync AssertPtr(pThis);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync VERR_INVALID_HANDLE);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync Assert(pThis->hOwner == RTThreadNativeSelf());
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync Assert(pThis->fRegistered);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync /*
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync * Deregister the callback.
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync rtThreadCtxHooksDeregister(pThis);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync return VINF_SUCCESS;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync}
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsyncRT_EXPORT_SYMBOL(RTThreadCtxHooksDeregister);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync
decf6daa697ed0e43daab9dc84769165b23f5abavboxsyncRTDECL(bool) RTThreadCtxHooksAreRegistered(RTTHREADCTX hThreadCtx)
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync{
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync /*
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync * Validate input.
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync */
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync PRTTHREADCTXINT pThis = hThreadCtx;
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync if (pThis == NIL_RTTHREADCTX)
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync return false;
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync AssertPtr(pThis);
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync AssertMsg(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis));
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync return pThis->fRegistered;
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync}
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync#else /* Not supported / Not needed */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsyncRTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx)
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync{
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync NOREF(phThreadCtx);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync return VERR_NOT_SUPPORTED;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync}
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsyncRT_EXPORT_SYMBOL(RTThreadCtxHooksCreate);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
094bd1aaada16d47495d62f7c3324f9df84c999avboxsyncRTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync{
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync NOREF(hThreadCtx);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync return UINT32_MAX;
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync}
094bd1aaada16d47495d62f7c3324f9df84c999avboxsyncRT_EXPORT_SYMBOL(RTThreadCtxHooksRetain);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync
094bd1aaada16d47495d62f7c3324f9df84c999avboxsyncRTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync{
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync NOREF(hThreadCtx);
094bd1aaada16d47495d62f7c3324f9df84c999avboxsync return UINT32_MAX;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync}
094bd1aaada16d47495d62f7c3324f9df84c999avboxsyncRT_EXPORT_SYMBOL(RTThreadCtxHooksRelease);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsyncRTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnThreadCtxHook, void *pvUser)
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync{
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync NOREF(hThreadCtx);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync NOREF(pfnThreadCtxHook);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync NOREF(pvUser);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync return VERR_NOT_SUPPORTED;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync}
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsyncRT_EXPORT_SYMBOL(RTThreadCtxHooksRegister);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsyncRTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx)
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync{
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync NOREF(hThreadCtx);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync return VERR_NOT_SUPPORTED;
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync}
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsyncRT_EXPORT_SYMBOL(RTThreadCtxHooksDeregister);
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync
decf6daa697ed0e43daab9dc84769165b23f5abavboxsyncRTDECL(bool) RTThreadCtxHooksAreRegistered(RTTHREADCTX hThreadCtx)
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync{
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync NOREF(hThreadCtx);
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync return false;
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync}
decf6daa697ed0e43daab9dc84769165b23f5abavboxsyncRT_EXPORT_SYMBOL(RTThreadCtxHooksAreRegistered);
decf6daa697ed0e43daab9dc84769165b23f5abavboxsync
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync#endif /* Not supported / Not needed */
1d42c7799e7c35c5b36a2494cde9a47e5651ceadvboxsync