VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/linux/threadctxhooks-r0drv-linux.c@ 47733

Last change on this file since 47733 was 47733, checked in by vboxsync, 11 years ago

Runtime/threadctxhooks/linux: Assert() not AssertPtr() for booleans.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.9 KB
Line 
1/* $Id: threadctxhooks-r0drv-linux.c 47733 2013-08-14 15:17:52Z vboxsync $ */
2/** @file
3 * IPRT - Thread-Context Hook, Ring-0 Driver, Linux.
4 */
5
6/*
7 * Copyright (C) 2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include "the-linux-kernel.h"
32#include "internal/iprt.h"
33
34#include <iprt/mem.h>
35#include <iprt/assert.h>
36#include <iprt/thread.h>
37#include <iprt/err.h>
38#include <iprt/asm.h>
39#include "internal/thread.h"
40
41#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_PREEMPT_NOTIFIERS)
42
43/*******************************************************************************
44* Structures and Typedefs *
45*******************************************************************************/
46/**
47 * The internal thread-context object.
48 */
49typedef struct RTTHREADCTXINT
50{
51 /** Magic value (RTTHREADCTXINT_MAGIC). */
52 uint32_t volatile u32Magic;
53 /** The thread handle (owner) for which the context-hooks are registered. */
54 RTNATIVETHREAD hOwner;
55 /** The preemption notifier object. */
56 struct preempt_notifier hPreemptNotifier;
57 /** Whether this handle has any hooks registered or not. */
58 bool fRegistered;
59 /** Pointer to the registered thread-context hook. */
60 PFNRTTHREADCTXHOOK pfnThreadCtxHook;
61 /** User argument passed to the thread-context hook. */
62 void *pvUser;
63 /** The thread-context operations. */
64 struct preempt_ops hPreemptOps;
65 /** The reference count for this object. */
66 uint32_t volatile cRefs;
67} RTTHREADCTXINT, *PRTTHREADCTXINT;
68
69
70/**
71 * Hook function for the thread-preempting event.
72 *
73 * @param pPreemptNotifier Pointer to the preempt_notifier struct.
74 * @param pNext Pointer to the task that is preempting the
75 * current thread.
76 *
77 * @remarks Called with the rq (runqueue) lock held and with preemption
78 * disabled!
79 */
80static void rtThreadCtxHooksLnxSchedOut(struct preempt_notifier *pPreemptNotifier, struct task_struct *pNext)
81{
82 PRTTHREADCTXINT pThis = RT_FROM_MEMBER(pPreemptNotifier, RTTHREADCTXINT, hPreemptNotifier);
83 AssertPtr(pThis);
84 AssertPtr(pThis->pfnThreadCtxHook);
85 Assert(pThis->fRegistered);
86 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
87
88 pThis->pfnThreadCtxHook(RTTHREADCTXEVENT_PREEMPTING, pThis->pvUser);
89}
90
91
92/**
93 * Hook function for the thread-resumed event.
94 *
95 * @param pPreemptNotifier Pointer to the preempt_notifier struct.
96 * @param iCpu The CPU this thread is scheduled on.
97 *
98 * @remarks Called without holding the rq (runqueue) lock and with preemption
99 * enabled!
100 */
101static void rtThreadCtxHooksLnxSchedIn(struct preempt_notifier *pPreemptNotifier, int iCpu)
102{
103 PRTTHREADCTXINT pThis = RT_FROM_MEMBER(pPreemptNotifier, RTTHREADCTXINT, hPreemptNotifier);
104 AssertPtr(pThis);
105 AssertPtr(pThis->pfnThreadCtxHook);
106 AssertPtr(pThis->fRegistered);
107
108 pThis->pfnThreadCtxHook(RTTHREADCTXEVENT_RESUMED, pThis->pvUser);
109}
110
111
112/**
113 * Worker function for RTThreadCtxHooks(Deregister|Release)().
114 *
115 * @param pThis Pointer to the internal thread-context object.
116 */
117DECLINLINE(void) rtThreadCtxHooksDeregister(PRTTHREADCTXINT pThis)
118{
119 preempt_notifier_unregister(&pThis->hPreemptNotifier);
120 pThis->hPreemptOps.sched_out = NULL;
121 pThis->hPreemptOps.sched_in = NULL;
122 pThis->fRegistered = false;
123}
124
125
126RTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx)
127{
128 PRTTHREADCTXINT pThis;
129 Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
130
131 pThis = (PRTTHREADCTXINT)RTMemAllocZ(sizeof(*pThis));
132 if (RT_UNLIKELY(!pThis))
133 return VERR_NO_MEMORY;
134 pThis->u32Magic = RTTHREADCTXINT_MAGIC;
135 pThis->hOwner = RTThreadNativeSelf();
136 pThis->fRegistered = false;
137 preempt_notifier_init(&pThis->hPreemptNotifier, &pThis->hPreemptOps);
138 pThis->cRefs = 1;
139
140 *phThreadCtx = pThis;
141 return VINF_SUCCESS;
142}
143RT_EXPORT_SYMBOL(RTThreadCtxHooksCreate);
144
145
146RTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
147{
148 /*
149 * Validate input.
150 */
151 uint32_t cRefs;
152 PRTTHREADCTXINT pThis = hThreadCtx;
153 AssertPtr(pThis);
154 AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
155 UINT32_MAX);
156
157 cRefs = ASMAtomicIncU32(&pThis->cRefs);
158 Assert(cRefs < UINT32_MAX / 2);
159 return cRefs;
160}
161RT_EXPORT_SYMBOL(RTThreadCtxHooksRetain);
162
163
164
165RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
166{
167 /*
168 * Validate input.
169 */
170 uint32_t cRefs;
171 PRTTHREADCTXINT pThis = hThreadCtx;
172 if (pThis == NIL_RTTHREADCTX)
173 return 0;
174
175 AssertPtr(pThis);
176 AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
177 UINT32_MAX);
178 Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
179
180 cRefs = ASMAtomicDecU32(&pThis->cRefs);
181 if (!cRefs)
182 {
183 /*
184 * If there's still a registered thread-context hook, deregister it now before destroying the object.
185 */
186 if (pThis->fRegistered)
187 rtThreadCtxHooksDeregister(pThis);
188
189 /*
190 * Paranoia... but since these are ring-0 threads we can't be too careful.
191 */
192 Assert(!pThis->fRegistered);
193 Assert(!pThis->hPreemptOps.sched_out);
194 Assert(!pThis->hPreemptOps.sched_in);
195
196 ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXINT_MAGIC);
197 RTMemFree(pThis);
198 }
199 else
200 Assert(cRefs < UINT32_MAX / 2);
201
202 return cRefs;
203}
204RT_EXPORT_SYMBOL(RTThreadCtxHooksRelease);
205
206
207RTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnThreadCtxHook, void *pvUser)
208{
209 /*
210 * Validate input.
211 */
212 PRTTHREADCTXINT pThis = hThreadCtx;
213 if (pThis == NIL_RTTHREADCTX)
214 return VERR_INVALID_HANDLE;
215 AssertPtr(pThis);
216 AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
217 VERR_INVALID_HANDLE);
218 Assert(pThis->hOwner == RTThreadNativeSelf());
219 Assert(!pThis->hPreemptOps.sched_out);
220 Assert(!pThis->hPreemptOps.sched_in);
221
222 /*
223 * Register the callback.
224 */
225 pThis->hPreemptOps.sched_out = rtThreadCtxHooksLnxSchedOut;
226 pThis->hPreemptOps.sched_in = rtThreadCtxHooksLnxSchedIn;
227 pThis->pvUser = pvUser;
228 pThis->pfnThreadCtxHook = pfnThreadCtxHook;
229 pThis->fRegistered = true;
230 preempt_notifier_register(&pThis->hPreemptNotifier);
231
232 return VINF_SUCCESS;
233}
234RT_EXPORT_SYMBOL(RTThreadCtxHooksRegister);
235
236
237RTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx)
238{
239 /*
240 * Validate input.
241 */
242 PRTTHREADCTXINT pThis = hThreadCtx;
243 if (pThis == NIL_RTTHREADCTX)
244 return VERR_INVALID_HANDLE;
245 AssertPtr(pThis);
246 AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
247 VERR_INVALID_HANDLE);
248 Assert(pThis->hOwner == RTThreadNativeSelf());
249 Assert(pThis->fRegistered);
250
251 /*
252 * Deregister the callback.
253 */
254 rtThreadCtxHooksDeregister(pThis);
255 return VINF_SUCCESS;
256}
257RT_EXPORT_SYMBOL(RTThreadCtxHooksDeregister);
258
259
260RTDECL(bool) RTThreadCtxHooksAreRegistered(RTTHREADCTX hThreadCtx)
261{
262 /*
263 * Validate input.
264 */
265 PRTTHREADCTXINT pThis = hThreadCtx;
266 if (pThis == NIL_RTTHREADCTX)
267 return false;
268 AssertPtr(pThis);
269 AssertMsg(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis));
270
271 return pThis->fRegistered;
272}
273
274#else /* Not supported / Not needed */
275
276RTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx)
277{
278 NOREF(phThreadCtx);
279 return VERR_NOT_SUPPORTED;
280}
281RT_EXPORT_SYMBOL(RTThreadCtxHooksCreate);
282
283
284RTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
285{
286 NOREF(hThreadCtx);
287 return UINT32_MAX;
288}
289RT_EXPORT_SYMBOL(RTThreadCtxHooksRetain);
290
291
292RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
293{
294 NOREF(hThreadCtx);
295 return UINT32_MAX;
296}
297RT_EXPORT_SYMBOL(RTThreadCtxHooksRelease);
298
299
300RTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnThreadCtxHook, void *pvUser)
301{
302 NOREF(hThreadCtx);
303 NOREF(pfnThreadCtxHook);
304 NOREF(pvUser);
305 return VERR_NOT_SUPPORTED;
306}
307RT_EXPORT_SYMBOL(RTThreadCtxHooksRegister);
308
309
310RTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx)
311{
312 NOREF(hThreadCtx);
313 return VERR_NOT_SUPPORTED;
314}
315RT_EXPORT_SYMBOL(RTThreadCtxHooksDeregister);
316
317
318RTDECL(bool) RTThreadCtxHooksAreRegistered(RTTHREADCTX hThreadCtx)
319{
320 NOREF(hThreadCtx);
321 return false;
322}
323RT_EXPORT_SYMBOL(RTThreadCtxHooksAreRegistered);
324
325#endif /* Not supported / Not needed */
326
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette