VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/term.cpp@ 20008

Last change on this file since 20008 was 19898, checked in by vboxsync, 16 years ago

IPRT: Termination callback framework - missing file. (not hooked up to anything yet)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.9 KB
Line 
1/* $Id: term.cpp 19898 2009-05-21 22:24:26Z vboxsync $ */
2/** @file
3 * IPRT - Common Termination Code.
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include <iprt/initterm.h>
35#include <iprt/asm.h>
36#include <iprt/assert.h>
37#include <iprt/err.h>
38#include <iprt/mem.h>
39#include <iprt/once.h>
40#include <iprt/semaphore.h>
41#include <iprt/thread.h>
42
43
44/*******************************************************************************
45* Structures and Typedefs *
46*******************************************************************************/
47/** Pointer to a termination callback record. */
48typedef struct RTTERMCALLBACKREC *PRTTERMCALLBACKREC;
49/**
50 * Termination callback record.
51 */
52typedef struct RTTERMCALLBACKREC
53{
54 /** Pointer to the next record. */
55 PRTTERMCALLBACKREC pNext;
56 /** Pointer to the callback. */
57 PFNRTTERMCALLBACK pfnCallback;
58 /** The user argument. */
59 void *pvUser;
60} RTTERMCALLBACKREC;
61
62
63/*******************************************************************************
64* Global Variables *
65*******************************************************************************/
66/** Execute once construct protecting lazy callback initialization. */
67static RTONCE g_InitTermCallbacksOnce = RTONCE_INITIALIZER;
68/** Mutex protecting the callback globals. */
69static RTSEMFASTMUTEX g_hFastMutex = NIL_RTSEMFASTMUTEX;
70/** Number of registered callbacks. */
71static uint32_t g_cCallbacks = 0;
72/** The callback head. */
73static PRTTERMCALLBACKREC g_pCallbackHead = NULL;
74
75
76
77/**
78 * Initializes the globals.
79 *
80 * @returns IPRT status code
81 * @param pvUser1 Ignored.
82 * @param pvUser2 Ignored.
83 */
84static DECLCALLBACK(int32_t) rtTermInitOnce(void *pvUser1, void *pvUser2)
85{
86 RTSEMFASTMUTEX hFastMutex;
87 int rc;
88
89 Assert(!g_cCallbacks);
90 Assert(!g_pCallbackHead);
91 Assert(g_hFastMutex == NIL_RTSEMFASTMUTEX);
92
93 rc = RTSemFastMutexCreate(&hFastMutex);
94 if (RT_SUCCESS(rc))
95 g_hFastMutex = hFastMutex;
96
97 NOREF(pvUser1);
98 NOREF(pvUser2);
99
100 return rc;
101}
102
103
104
105RTDECL(int) RTTermRegisterCallback(PFNRTTERMCALLBACK pfnCallback, void *pvUser)
106{
107 int rc;
108 PRTTERMCALLBACKREC pNew;
109
110 /*
111 * Validation and lazy init.
112 */
113 AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
114
115 rc = RTOnce(&g_InitTermCallbacksOnce, rtTermInitOnce, NULL, NULL);
116 if (RT_FAILURE(rc))
117 return rc;
118
119 /*
120 * Allocate and initialize a new callback record.
121 */
122 pNew = (PRTTERMCALLBACKREC)RTMemAlloc(sizeof(*pNew));
123 if (!pNew)
124 return VERR_NO_MEMORY;
125 pNew->pfnCallback = pfnCallback;
126 pNew->pvUser = pvUser;
127
128 /*
129 * Insert into the list.
130 */
131 rc = RTSemFastMutexRequest(g_hFastMutex);
132 if (RT_SUCCESS(rc))
133 {
134 g_cCallbacks++;
135 pNew->pNext = g_pCallbackHead;
136 g_pCallbackHead = pNew;
137
138 RTSemFastMutexRelease(g_hFastMutex);
139 }
140 else
141 RTMemFree(pNew);
142
143 return rc;
144}
145
146
147RTDECL(int) RTTermDeregisterCallback(PFNRTTERMCALLBACK pfnCallback, void *pvUser)
148{
149 /*
150 * g_hFastMutex will be NIL if we're not initialized.
151 */
152 int rc;
153 RTSEMFASTMUTEX hFastMutex = g_hFastMutex;
154 if (hFastMutex == NIL_RTSEMFASTMUTEX)
155 return VERR_NOT_FOUND;
156
157 rc = RTSemFastMutexRequest(hFastMutex);
158 if (RT_SUCCESS(rc))
159 {
160
161 /*
162 * Search for the specified pfnCallback/pvUser pair.
163 */
164 PRTTERMCALLBACKREC pPrev = NULL;
165 PRTTERMCALLBACKREC pCur = g_pCallbackHead;
166 while (pCur)
167 {
168 if ( pCur->pfnCallback == pfnCallback
169 && pCur->pvUser == pvUser)
170 {
171 if (pPrev)
172 pPrev->pNext = pCur->pNext;
173 else
174 g_pCallbackHead = pCur->pNext;
175 g_cCallbacks--;
176 RTSemFastMutexRelease(hFastMutex);
177
178 pCur->pfnCallback = NULL;
179 RTMemFree(pCur);
180 return VINF_SUCCESS;
181 }
182
183 /* next */
184 pPrev = pCur;
185 pCur = pCur->pNext;
186 }
187
188 RTSemFastMutexRelease(hFastMutex);
189 rc = VERR_NOT_FOUND;
190 }
191
192 return rc;
193}
194
195
196RTDECL(void) RTTermRunCallbacks(RTTERMREASON enmReason, int32_t iStatus)
197{
198 RTSEMFASTMUTEX hFastMutex;
199 Assert( enmReason == RTTERMREASON_EXIT
200 || enmReason == RTTERMREASON_ABEND
201 || enmReason == RTTERMREASON_SIGNAL
202 || enmReason == RTTERMREASON_UNLOAD);
203
204 /*
205 * Run the callback list. This is a bit paranoid in order to guard aginst
206 * recursive calls to RTTermRunCallbacks.
207 */
208 while (g_hFastMutex != NIL_RTSEMFASTMUTEX)
209 {
210 PRTTERMCALLBACKREC pCur;
211 RTTERMCALLBACKREC CurCopy;
212 int rc;
213
214 /* Unlink the head of the chain. */
215 rc = RTSemFastMutexRequest(g_hFastMutex);
216 AssertRCReturnVoid(rc);
217 pCur = g_pCallbackHead;
218 if (pCur)
219 {
220 g_pCallbackHead = pCur->pNext;
221 g_cCallbacks--;
222 }
223 RTSemFastMutexRelease(g_hFastMutex);
224 if (!pCur)
225 break;
226
227 /* Copy and free it. */
228 CurCopy = *pCur;
229 RTMemFree(pCur);
230
231 /* Make the call. */
232 CurCopy.pfnCallback(enmReason, iStatus, CurCopy.pvUser);
233 }
234
235 /*
236 * Free the lock.
237 */
238 ASMAtomicXchgHandle(&g_hFastMutex, NIL_RTSEMFASTMUTEX, &hFastMutex);
239 RTSemFastMutexDestroy(hFastMutex);
240 RTOnceReset(&g_InitTermCallbacksOnce); /* for the testcase */
241}
242
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