VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/solaris/threadctxhooks-r0drv-solaris.c@ 47373

Last change on this file since 47373 was 47373, checked in by vboxsync, 12 years ago

nit.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.7 KB
Line 
1/* $Id: threadctxhooks-r0drv-solaris.c 47373 2013-07-24 13:05:53Z vboxsync $ */
2/** @file
3 * IPRT - Thread-Context Hook, Ring-0 Driver, Solaris.
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-solaris-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
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45/**
46 * The internal thread-context object.
47 */
48typedef struct RTTHREADCTXINT
49{
50 /** Magic value (RTTHREADCTXINT_MAGIC). */
51 uint32_t volatile u32Magic;
52 /** The thread handle (owner) for which the context-hooks are registered. */
53 RTNATIVETHREAD hOwner;
54 /** Pointer to the registered thread-context hook. */
55 PFNRTTHREADCTXHOOK pfnThreadCtxHook;
56 /** User argument passed to the thread-context hook. */
57 void *pvUser;
58 /** Whether this handle has any hooks registered or not. */
59 bool fRegistered;
60 /** Number of references to this object. */
61 uint32_t volatile cRefs;
62} RTTHREADCTXINT, *PRTTHREADCTXINT;
63
64
65/*******************************************************************************
66* Defined Constants And Macros *
67*******************************************************************************/
68/** Validates a thread-context hook handle and returns rc if not valid. */
69#define RTTHREADCTX_VALID_RETURN_RC(pThis, rc) \
70 do { \
71 AssertPtrReturn((pThis), (rc)); \
72 AssertReturn((pThis)->u32Magic == RTTHREADCTXINT_MAGIC, (rc)); \
73 AssertReturn((pThis)->cRefs > 0, (rc)); \
74 } while (0)
75
76
77/**
78 * Hook function for the thread-preempting event.
79 *
80 * @param pvThreadCtxInt Opaque pointer to the internal thread-context
81 * object.
82 *
83 * @remarks Called with the with preemption disabled!
84 */
85static void rtThreadCtxHooksSolPreempting(void *pvThreadCtxInt)
86{
87 PRTTHREADCTXINT pThis = (PRTTHREADCTXINT)pvThreadCtxInt;
88 AssertPtr(pThis);
89 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
90
91 if (pThis->fRegistered)
92 {
93 Assert(pThis->pfnThreadCtxHook);
94 pThis->pfnThreadCtxHook(RTTHREADCTXEVENT_PREEMPTING, pThis->pvUser);
95 }
96}
97
98
99/**
100 * Hook function for the thread-resumed event.
101 *
102 * @param pvThreadCtxInt Opaque pointer to the internal thread-context
103 * object.
104 */
105static void rtThreadCtxHooksSolResumed(void *pvThreadCtxInt)
106{
107 PRTTHREADCTXINT pThis = (PRTTHREADCTXINT)pvThreadCtxInt;
108 AssertPtr(pThis);
109 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
110
111 if (pThis->fRegistered)
112 {
113 Assert(pThis->pfnThreadCtxHook);
114 pThis->pfnThreadCtxHook(RTTHREADCTXEVENT_RESUMED, pThis->pvUser);
115 }
116}
117
118
119/**
120 * Hook function for the thread-free event.
121 *
122 * @param pvThreadCtxInt Opaque pointer to the internal thread-context
123 * object.
124 * @param fIsExec Whether this event is triggered due to exec().
125 */
126static void rtThreadCtxHooksSolFree(void *pvThreadCtxInt, int fIsExec)
127{
128 PRTTHREADCTXINT pThis = (PRTTHREADCTXINT)pvThreadCtxInt;
129 AssertPtrReturnVoid(pThis);
130 AssertMsgReturnVoid(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis));
131
132 uint32_t cRefs = ASMAtomicReadU32(&pThis->cRefs);
133 if (RT_UNLIKELY(!cRefs))
134 {
135 /* Should never happen. */
136 AssertMsgFailed(("rtThreadCtxHooksSolFree with cRefs=0 pThis=%p\n", pThis));
137 return;
138 }
139
140 cRefs = ASMAtomicDecU32(&pThis->cRefs)
141 if (!cRefs)
142 {
143 Assert(!pThis->fRegistered);
144 ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXINT_MAGIC);
145 RTMemFree(pThis);
146 }
147}
148
149
150RTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx)
151{
152 PRTTHREADCTXINT pThis;
153 Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
154
155 pThis = (PRTTHREADCTXINT)RTMemAllocZ(sizeof(*pThis));
156 if (RT_UNLIKELY(!pThis))
157 return VERR_NO_MEMORY;
158 pThis->u32Magic = RTTHREADCTXINT_MAGIC;
159 pThis->hOwner = RTThreadNativeSelf();
160 pThis->fRegistered = false;
161 pThis->cRefs = 2; /* One reference for the thread, one for the hook object. */
162
163 /*
164 * installctx() allocates memory and thus cannot be used in RTThreadCtxHooksRegister() which can be used
165 * with preemption disabled. We allocate the context-hooks here and use 'fRegistered' to determine if we can
166 * invoke the consumer's hook or not.
167 */
168 if (g_frtSolOldThreadCtx)
169 {
170 g_rtSolThreadCtx.Install.pfnSol_installctx_old(curthread,
171 pThis,
172 rtThreadCtxHooksSolPreempting,
173 rtThreadCtxHooksSolResumed,
174 NULL, /* fork */
175 NULL, /* lwp_create */
176 rtThreadCtxHooksSolFree);
177 }
178 else
179 {
180 g_rtSolThreadCtx.Install.pfnSol_installctx(curthread,
181 pThis,
182 rtThreadCtxHooksSolPreempting,
183 rtThreadCtxHooksSolResumed,
184 NULL, /* fork */
185 NULL, /* lwp_create */
186 NULL, /* exit */
187 rtThreadCtxHooksSolFree);
188 }
189
190 *phThreadCtx = pThis;
191 return VINF_SUCCESS;
192}
193
194
195RTDECL(uint32_t) RTThreadCtxHooksRetain(RTTHREADCTX hThreadCtx)
196{
197 PRTTHREADCTXINT pThis = hThreadCtx;
198 RTTHREADCTX_VALID_RETURN_RC(hThreadCtx, UINT32_MAX);
199
200 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
201 Assert(cRefs < UINT32_MAX / 2);
202 return cRefs;
203}
204
205
206RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
207{
208 PRTTHREADCTXINT pThis = hThreadCtx;
209 if (pThis == NIL_RTTHREADCTX)
210 return 0;
211
212 RTTHREADCTX_VALID_RETURN_RC(hThreadCtx, UINT32_MAX);
213 Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
214
215 pThis->fRegistered = false;
216 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
217
218 if ( pThis->hOwner == RTThreadNativeSelf()
219 && cRefs == 1)
220 {
221 /*
222 * removectx() will invoke rtThreadCtxHooksSolFree() and there is no way to bypass it and still use
223 * rtThreadCtxHooksSolFree() at the same time. Hence the convulated reference counting.
224 *
225 * When this function is called from the owner thread and is the last reference, we call removectx() which
226 * will invoke rtThreadCtxHooksSolFree() with cRefs = 1 and that will then free the hook object.
227 *
228 * When the function is called from a different thread, we simply decrement the reference. Whenever the
229 * ring-0 thread dies, Solaris will call rtThreadCtxHooksSolFree() which will free the hook object.
230 */
231 int rc;
232 if (g_frtSolOldThreadCtx)
233 {
234 rc = g_rtSolThreadCtx.Remove.pfnSol_removectx_old(curthread,
235 pThis,
236 rtThreadCtxHooksSolPreempting,
237 rtThreadCtxHooksSolResumed,
238 NULL, /* fork */
239 NULL, /* lwp_create */
240 rtThreadCtxHooksSolFree);
241 }
242 else
243 {
244 rc = g_rtSolThreadCtx.Remove.pfnSol_removectx(curthread,
245 pThis,
246 rtThreadCtxHooksSolPreempting,
247 rtThreadCtxHooksSolResumed,
248 NULL, /* fork */
249 NULL, /* lwp_create */
250 NULL, /* exit */
251 rtThreadCtxHooksSolFree);
252 }
253 AssertMsg(rc, ("removectx failed. rc=%d\n", rc));
254 NOREF(rc);
255
256#ifdef VBOX_STRICT
257 cRefs = ASMAtomicReadU32(&pThis->cRefs);
258 Assert(!cRefs);
259#endif
260 cRefs = 0;
261 }
262 else if (!cRefs)
263 {
264 /*
265 * The ring-0 thread for this hook object has already died. Free up the object as we have no more references.
266 */
267 Assert(pThis->hOwner != RTThreadNativeSelf());
268 ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXINT_MAGIC);
269 RTMemFree(pThis);
270 }
271
272 return cRefs;
273}
274
275
276RTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnThreadCtxHook, void *pvUser)
277{
278 /*
279 * Validate input.
280 */
281 PRTTHREADCTXINT pThis = hThreadCtx;
282 if (pThis == NIL_RTTHREADCTX)
283 return VINF_SUCCESS;
284 AssertPtr(pThis);
285 AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
286 VERR_INVALID_HANDLE);
287 Assert(pThis->hOwner == RTThreadNativeSelf());
288
289 /*
290 * Register the callback.
291 */
292 pThis->pvUser = pvUser;
293 pThis->pfnThreadCtxHook = pfnThreadCtxHook;
294 pThis->fRegistered = true;
295
296 return VINF_SUCCESS;
297}
298
299
300RTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx)
301{
302 /*
303 * Validate input.
304 */
305 PRTTHREADCTXINT pThis = hThreadCtx;
306 if (pThis == NIL_RTTHREADCTX)
307 return VINF_SUCCESS;
308 AssertPtr(pThis);
309 AssertMsgReturn(pThis->u32Magic == RTTHREADCTXINT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis),
310 VERR_INVALID_HANDLE);
311 Assert(pThis->hOwner == RTThreadNativeSelf());
312 Assert(pThis->fRegistered);
313
314 /*
315 * Deregister the callback.
316 */
317 pThis->fRegistered = false;
318
319 return VINF_SUCCESS;
320}
321
Note: See TracBrowser for help on using the repository browser.

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