Changeset 55863 in vbox for trunk/src/VBox/Runtime/r0drv/linux/threadctxhooks-r0drv-linux.c
- Timestamp:
- May 14, 2015 6:29:34 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r0drv/linux/threadctxhooks-r0drv-linux.c
r54872 r55863 1 1 /* $Id$ */ 2 2 /** @file 3 * IPRT - Thread -ContextHook, Ring-0 Driver, Linux.3 * IPRT - Thread Context Switching Hook, Ring-0 Driver, Linux. 4 4 */ 5 5 … … 42 42 #include "internal/thread.h" 43 43 44 44 45 /* 45 * Linux kernel 2.6.23 introduced thread-context hooks but RedHat 2.6.18 kernels46 * Linux kernel 2.6.23 introduced preemption notifiers but RedHat 2.6.18 kernels 46 47 * got it backported. 47 48 */ … … 52 53 *******************************************************************************/ 53 54 /** 54 * The internal thread-context object.55 */ 56 typedef struct RTTHREADCTX INT57 { 58 /** Magic value (RTTHREADCTX INT_MAGIC). */55 * The internal hook object for linux. 56 */ 57 typedef struct RTTHREADCTXHOOKINT 58 { 59 /** Magic value (RTTHREADCTXHOOKINT_MAGIC). */ 59 60 uint32_t volatile u32Magic; 60 /** The thread handle (owner) for which the context-hooks areregistered. */61 /** The thread handle (owner) for which the hook is registered. */ 61 62 RTNATIVETHREAD hOwner; 62 63 /** The preemption notifier object. */ 63 struct preempt_notifier hPreemptNotifier; 64 /** Whether this handle has any hooks registered or not. */ 65 bool fRegistered; 66 /** Pointer to the registered thread-context hook. */ 67 PFNRTTHREADCTXHOOK pfnThreadCtxHook; 68 /** User argument passed to the thread-context hook. */ 64 struct preempt_notifier LnxPreemptNotifier; 65 /** Whether the hook is enabled or not. If enabled, the LnxPreemptNotifier 66 * is linked into the owning thread's list of preemption callouts. */ 67 bool fEnabled; 68 /** Pointer to the user callback. */ 69 PFNRTTHREADCTXHOOK pfnCallback; 70 /** User argument passed to the callback. */ 69 71 void *pvUser; 70 /** The thread-context operations. */ 71 struct preempt_ops hPreemptOps; 72 /** The reference count for this object. */ 73 uint32_t volatile cRefs; 72 /** The linux callbacks. */ 73 struct preempt_ops PreemptOps; 74 74 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 19) && defined(RT_ARCH_AMD64) 75 75 /** Starting with 3.1.19, the linux kernel doesn't restore kernel RFLAGS during … … 77 77 RTCCUINTREG fSavedRFlags; 78 78 #endif 79 } RTTHREADCTXINT, *PRTTHREADCTXINT; 79 } RTTHREADCTXHOOKINT; 80 typedef RTTHREADCTXHOOKINT *PRTTHREADCTXHOOKINT; 80 81 81 82 82 83 /** 83 * Hook function for the thread -preemptingevent.84 * Hook function for the thread schedule out event. 84 85 * 85 86 * @param pPreemptNotifier Pointer to the preempt_notifier struct. 86 * @param pNext Pointer to the task that is preempting the87 * current thread.87 * @param pNext Pointer to the task that is being scheduled 88 * instead of the current thread. 88 89 * 89 90 * @remarks Called with the rq (runqueue) lock held and with preemption and … … 92 93 static void rtThreadCtxHooksLnxSchedOut(struct preempt_notifier *pPreemptNotifier, struct task_struct *pNext) 93 94 { 94 PRTTHREADCTX INT pThis = RT_FROM_MEMBER(pPreemptNotifier, RTTHREADCTXINT, hPreemptNotifier);95 PRTTHREADCTXHOOKINT pThis = RT_FROM_MEMBER(pPreemptNotifier, RTTHREADCTXHOOKINT, LnxPreemptNotifier); 95 96 #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) 96 97 RTCCUINTREG fSavedEFlags = ASMGetFlags(); … … 99 100 100 101 AssertPtr(pThis); 101 AssertPtr(pThis->pfn ThreadCtxHook);102 Assert(pThis->f Registered);102 AssertPtr(pThis->pfnCallback); 103 Assert(pThis->fEnabled); 103 104 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD)); 104 105 105 pThis->pfn ThreadCtxHook(RTTHREADCTXEVENT_PREEMPTING, pThis->pvUser);106 pThis->pfnCallback(RTTHREADCTXEVENT_OUT, pThis->pvUser); 106 107 107 108 #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) … … 115 116 116 117 /** 117 * Hook function for the thread -resumedevent.118 * Hook function for the thread schedule in event. 118 119 * 119 120 * @param pPreemptNotifier Pointer to the preempt_notifier struct. 120 * @param iCpu The CPU this thread is scheduled on.121 * @param iCpu The CPU this thread is being scheduled on. 121 122 * 122 123 * @remarks Called without holding the rq (runqueue) lock and with preemption 123 124 * enabled! 125 * @todo r=bird: Preemption is of course disabled when it is called. 124 126 */ 125 127 static void rtThreadCtxHooksLnxSchedIn(struct preempt_notifier *pPreemptNotifier, int iCpu) 126 128 { 127 PRTTHREADCTX INT pThis = RT_FROM_MEMBER(pPreemptNotifier, RTTHREADCTXINT, hPreemptNotifier);129 PRTTHREADCTXHOOKINT pThis = RT_FROM_MEMBER(pPreemptNotifier, RTTHREADCTXHOOKINT, LnxPreemptNotifier); 128 130 #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) 129 131 RTCCUINTREG fSavedEFlags = ASMGetFlags(); … … 132 134 133 135 AssertPtr(pThis); 134 AssertPtr(pThis->pfn ThreadCtxHook);135 Assert(pThis->f Registered);136 137 pThis->pfn ThreadCtxHook(RTTHREADCTXEVENT_RESUMED, pThis->pvUser);136 AssertPtr(pThis->pfnCallback); 137 Assert(pThis->fEnabled); 138 139 pThis->pfnCallback(RTTHREADCTXEVENT_IN, pThis->pvUser); 138 140 139 141 #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) … … 152 154 * @param pThis Pointer to the internal thread-context object. 153 155 */ 154 DECLINLINE(void) rtThreadCtxHooksDeregister(PRTTHREADCTXINT pThis) 155 { 156 preempt_notifier_unregister(&pThis->hPreemptNotifier); 157 pThis->hPreemptOps.sched_out = NULL; 158 pThis->hPreemptOps.sched_in = NULL; 159 pThis->fRegistered = false; 160 } 161 162 163 RTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx) 164 { 165 PRTTHREADCTXINT pThis; 156 DECLINLINE(void) rtThreadCtxHookDisable(PRTTHREADCTXHOOKINT pThis) 157 { 158 Assert(pThis->PreemptOps.sched_out == rtThreadCtxHooksLnxSchedOut); 159 Assert(pThis->PreemptOps.sched_in == rtThreadCtxHooksLnxSchedIn); 160 preempt_disable(); 161 preempt_notifier_unregister(&pThis->LnxPreemptNotifier); 162 pThis->fEnabled = false; 163 preempt_enable(); 164 } 165 166 167 RTDECL(int) RTThreadCtxHookCreate(PRTTHREADCTXHOOK phCtxHook, uint32_t fFlags, PFNRTTHREADCTXHOOK pfnCallback, void *pvUser) 168 { 169 /* 170 * Validate input. 171 */ 172 PRTTHREADCTXHOOKINT pThis; 166 173 Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD)); 167 168 pThis = (PRTTHREADCTXINT)RTMemAllocZ(sizeof(*pThis)); 174 AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER); 175 AssertReturn(fFlags == 0, VERR_INVALID_FLAGS); 176 177 /* 178 * Allocate and initialize a new hook. We don't register it yet, just 179 * create it. 180 */ 181 pThis = (PRTTHREADCTXHOOKINT)RTMemAllocZ(sizeof(*pThis)); 169 182 if (RT_UNLIKELY(!pThis)) 170 183 return VERR_NO_MEMORY; 171 pThis->u32Magic = RTTHREADCTXINT_MAGIC; 172 pThis->hOwner = RTThreadNativeSelf(); 173 pThis->fRegistered = false; 174 preempt_notifier_init(&pThis->hPreemptNotifier, &pThis->hPreemptOps); 175 pThis->cRefs = 1; 176 177 *phThreadCtx = pThis; 184 pThis->u32Magic = RTTHREADCTXHOOKINT_MAGIC; 185 pThis->hOwner = RTThreadNativeSelf(); 186 pThis->fEnabled = false; 187 pThis->pfnCallback = pfnCallback; 188 pThis->pvUser = pvUser; 189 preempt_notifier_init(&pThis->LnxPreemptNotifier, &pThis->PreemptOps); 190 pThis->PreemptOps.sched_out = rtThreadCtxHooksLnxSchedOut; 191 pThis->PreemptOps.sched_in = rtThreadCtxHooksLnxSchedIn; 192 193 *phCtxHook = pThis; 178 194 return VINF_SUCCESS; 179 195 } 180 RT_EXPORT_SYMBOL(RTThreadCtxHooksCreate); 181 182 183 RTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx) 184 { 185 /* 186 * Validate input. 187 */ 188 uint32_t cRefs; 189 PRTTHREADCTXINT pThis = hThreadCtx; 190 AssertPtr(pThis); 191 AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), 192 UINT32_MAX); 193 194 cRefs = ASMAtomicIncU32(&pThis->cRefs); 195 Assert(cRefs < UINT32_MAX / 2); 196 return cRefs; 197 } 198 RT_EXPORT_SYMBOL(RTThreadCtxHooksRetain); 199 200 201 202 RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx) 203 { 204 /* 205 * Validate input. 206 */ 207 uint32_t cRefs; 208 PRTTHREADCTXINT pThis = hThreadCtx; 209 if (pThis == NIL_RTTHREADCTX) 210 return 0; 211 212 AssertPtr(pThis); 213 AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), 214 UINT32_MAX); 196 RT_EXPORT_SYMBOL(RTThreadCtxHookCreate); 197 198 199 RTDECL(int ) RTThreadCtxHookDestroy(RTTHREADCTXHOOK hCtxHook) 200 { 201 /* 202 * Validate input. 203 */ 204 PRTTHREADCTXHOOKINT pThis = hCtxHook; 205 if (pThis == NIL_RTTHREADCTXHOOK) 206 return VINF_SUCCESS; 207 AssertPtr(pThis); 208 AssertMsgReturn(pThis->u32Magic == RTTHREADCTXHOOKINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), 209 VERR_INVALID_HANDLE); 215 210 Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD)); 216 217 cRefs = ASMAtomicDecU32(&pThis->cRefs); 218 if (!cRefs) 211 Assert(pThis->fEnabled || pThis->hOwner == RTThreadNativeSelf()); 212 213 /* 214 * If there's still a registered thread-context hook, deregister it now before destroying the object. 215 */ 216 if (pThis->fEnabled) 219 217 { 220 /* 221 * If there's still a registered thread-context hook, deregister it now before destroying the object. 222 */ 223 if (pThis->fRegistered) 224 rtThreadCtxHooksDeregister(pThis); 225 226 /* 227 * Paranoia... but since these are ring-0 threads we can't be too careful. 228 */ 229 Assert(!pThis->fRegistered); 230 Assert(!pThis->hPreemptOps.sched_out); 231 Assert(!pThis->hPreemptOps.sched_in); 232 233 ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXINT_MAGIC); 234 RTMemFree(pThis); 218 Assert(pThis->hOwner == RTThreadNativeSelf()); 219 rtThreadCtxHookDisable(pThis); 220 Assert(!pThis->fEnabled); /* paranoia */ 235 221 } 236 else 237 Assert(cRefs < UINT32_MAX / 2); 238 239 return cRefs; 240 } 241 RT_EXPORT_SYMBOL(RTThreadCtxHooksRelease); 242 243 244 RTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnThreadCtxHook, void *pvUser) 245 { 246 /* 247 * Validate input. 248 */ 249 PRTTHREADCTXINT pThis = hThreadCtx; 250 if (pThis == NIL_RTTHREADCTX) 251 return VERR_INVALID_HANDLE; 252 AssertPtr(pThis); 253 AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), 222 223 ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXHOOKINT_MAGIC); 224 RTMemFree(pThis); 225 226 return VINF_SUCCESS; 227 } 228 RT_EXPORT_SYMBOL(RTThreadCtxHookDestroy); 229 230 231 RTDECL(int) RTThreadCtxHookEnable(RTTHREADCTXHOOK hCtxHook) 232 { 233 /* 234 * Validate input. 235 */ 236 PRTTHREADCTXHOOKINT pThis = hCtxHook; 237 AssertPtr(pThis); 238 AssertMsgReturn(pThis->u32Magic == RTTHREADCTXHOOKINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), 254 239 VERR_INVALID_HANDLE); 255 240 Assert(pThis->hOwner == RTThreadNativeSelf()); 256 Assert(!pThis->hPreemptOps.sched_out); 257 Assert(!pThis->hPreemptOps.sched_in); 258 259 /* 260 * Register the callback. 261 */ 262 pThis->hPreemptOps.sched_out = rtThreadCtxHooksLnxSchedOut; 263 pThis->hPreemptOps.sched_in = rtThreadCtxHooksLnxSchedIn; 264 pThis->pvUser = pvUser; 265 pThis->pfnThreadCtxHook = pfnThreadCtxHook; 266 pThis->fRegistered = true; 267 preempt_notifier_register(&pThis->hPreemptNotifier); 241 Assert(!pThis->fEnabled); 242 if (!pThis->fEnabled) 243 { 244 Assert(pThis->PreemptOps.sched_out == rtThreadCtxHooksLnxSchedOut); 245 Assert(pThis->PreemptOps.sched_in == rtThreadCtxHooksLnxSchedIn); 246 247 /* 248 * Register the callback. 249 */ 250 preempt_disable(); 251 pThis->fEnabled = true; 252 preempt_notifier_register(&pThis->LnxPreemptNotifier); 253 preempt_enable(); 254 } 268 255 269 256 return VINF_SUCCESS; 270 257 } 271 RT_EXPORT_SYMBOL(RTThreadCtxHooksRegister); 272 273 274 RTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx) 275 { 276 /* 277 * Validate input. 278 */ 279 PRTTHREADCTXINT pThis = hThreadCtx; 280 if (pThis == NIL_RTTHREADCTX) 281 return VERR_INVALID_HANDLE; 282 AssertPtr(pThis); 283 AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), 284 VERR_INVALID_HANDLE); 285 Assert(pThis->hOwner == RTThreadNativeSelf()); 286 Assert(pThis->fRegistered); 287 288 /* 289 * Deregister the callback. 290 */ 291 rtThreadCtxHooksDeregister(pThis); 258 RT_EXPORT_SYMBOL(RTThreadCtxHookEnable); 259 260 261 RTDECL(int) RTThreadCtxHookDisable(RTTHREADCTXHOOK hCtxHook) 262 { 263 /* 264 * Validate input. 265 */ 266 PRTTHREADCTXHOOKINT pThis = hCtxHook; 267 if (pThis != NIL_RTTHREADCTXHOOK) 268 { 269 AssertPtr(pThis); 270 AssertMsgReturn(pThis->u32Magic == RTTHREADCTXHOOKINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), 271 VERR_INVALID_HANDLE); 272 Assert(pThis->hOwner == RTThreadNativeSelf()); 273 274 /* 275 * Deregister the callback. 276 */ 277 if (pThis->fEnabled) 278 rtThreadCtxHookDisable(pThis); 279 } 292 280 return VINF_SUCCESS; 293 281 } 294 RT_EXPORT_SYMBOL(RTThreadCtxHook sDeregister);295 296 297 RTDECL(bool) RTThreadCtxHook sAreRegistered(RTTHREADCTX hThreadCtx)298 { 299 /* 300 * Validate input. 301 */ 302 PRTTHREADCTX INT pThis = hThreadCtx;303 if (pThis == NIL_RTTHREADCTX )282 RT_EXPORT_SYMBOL(RTThreadCtxHookDisable); 283 284 285 RTDECL(bool) RTThreadCtxHookIsEnabled(RTTHREADCTXHOOK hCtxHook) 286 { 287 /* 288 * Validate input. 289 */ 290 PRTTHREADCTXHOOKINT pThis = hCtxHook; 291 if (pThis == NIL_RTTHREADCTXHOOK) 304 292 return false; 305 293 AssertPtr(pThis); 306 AssertMsg(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis)); 307 308 return pThis->fRegistered; 294 AssertMsgReturn(pThis->u32Magic == RTTHREADCTXHOOKINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), 295 false); 296 297 return pThis->fEnabled; 309 298 } 310 299 311 300 #else /* Not supported / Not needed */ 312 313 RTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx) 314 { 315 NOREF(phThreadCtx); 316 return VERR_NOT_SUPPORTED; 317 } 318 RT_EXPORT_SYMBOL(RTThreadCtxHooksCreate); 319 320 321 RTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx) 322 { 323 NOREF(hThreadCtx); 324 return UINT32_MAX; 325 } 326 RT_EXPORT_SYMBOL(RTThreadCtxHooksRetain); 327 328 329 RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx) 330 { 331 NOREF(hThreadCtx); 332 return UINT32_MAX; 333 } 334 RT_EXPORT_SYMBOL(RTThreadCtxHooksRelease); 335 336 337 RTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnThreadCtxHook, void *pvUser) 338 { 339 NOREF(hThreadCtx); 340 NOREF(pfnThreadCtxHook); 341 NOREF(pvUser); 342 return VERR_NOT_SUPPORTED; 343 } 344 RT_EXPORT_SYMBOL(RTThreadCtxHooksRegister); 345 346 347 RTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx) 348 { 349 NOREF(hThreadCtx); 350 return VERR_NOT_SUPPORTED; 351 } 352 RT_EXPORT_SYMBOL(RTThreadCtxHooksDeregister); 353 354 355 RTDECL(bool) RTThreadCtxHooksAreRegistered(RTTHREADCTX hThreadCtx) 356 { 357 NOREF(hThreadCtx); 358 return false; 359 } 360 RT_EXPORT_SYMBOL(RTThreadCtxHooksAreRegistered); 361 301 # include "../generic/threadctxhooks-r0drv-generic.cpp" 362 302 #endif /* Not supported / Not needed */ 363 303
Note:
See TracChangeset
for help on using the changeset viewer.