VirtualBox

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

Last change on this file since 28800 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

  • 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 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 * IPRT - Common Termination Code.
4 */
5
6/*
7 * Copyright (C) 2009 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* Header Files *
29*******************************************************************************/
30#include <iprt/initterm.h>
31#include "internal/iprt.h"
32
33#include <iprt/asm.h>
34#include <iprt/assert.h>
35#include <iprt/err.h>
36#include <iprt/mem.h>
37#include <iprt/once.h>
38#include <iprt/semaphore.h>
39#include <iprt/thread.h>
40
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45/** Pointer to a termination callback record. */
46typedef struct RTTERMCALLBACKREC *PRTTERMCALLBACKREC;
47/**
48 * Termination callback record.
49 */
50typedef struct RTTERMCALLBACKREC
51{
52 /** Pointer to the next record. */
53 PRTTERMCALLBACKREC pNext;
54 /** Pointer to the callback. */
55 PFNRTTERMCALLBACK pfnCallback;
56 /** The user argument. */
57 void *pvUser;
58} RTTERMCALLBACKREC;
59
60
61/*******************************************************************************
62* Global Variables *
63*******************************************************************************/
64/** Execute once construct protecting lazy callback initialization. */
65static RTONCE g_InitTermCallbacksOnce = RTONCE_INITIALIZER;
66/** Mutex protecting the callback globals. */
67static RTSEMFASTMUTEX g_hFastMutex = NIL_RTSEMFASTMUTEX;
68/** Number of registered callbacks. */
69static uint32_t g_cCallbacks = 0;
70/** The callback head. */
71static PRTTERMCALLBACKREC g_pCallbackHead = NULL;
72
73
74
75/**
76 * Initializes the globals.
77 *
78 * @returns IPRT status code
79 * @param pvUser1 Ignored.
80 * @param pvUser2 Ignored.
81 */
82static DECLCALLBACK(int32_t) rtTermInitOnce(void *pvUser1, void *pvUser2)
83{
84 RTSEMFASTMUTEX hFastMutex;
85 int rc;
86
87 Assert(!g_cCallbacks);
88 Assert(!g_pCallbackHead);
89 Assert(g_hFastMutex == NIL_RTSEMFASTMUTEX);
90
91 rc = RTSemFastMutexCreate(&hFastMutex);
92 if (RT_SUCCESS(rc))
93 g_hFastMutex = hFastMutex;
94
95 NOREF(pvUser1);
96 NOREF(pvUser2);
97
98 return rc;
99}
100
101
102
103RTDECL(int) RTTermRegisterCallback(PFNRTTERMCALLBACK pfnCallback, void *pvUser)
104{
105 int rc;
106 PRTTERMCALLBACKREC pNew;
107
108 /*
109 * Validation and lazy init.
110 */
111 AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
112
113 rc = RTOnce(&g_InitTermCallbacksOnce, rtTermInitOnce, NULL, NULL);
114 if (RT_FAILURE(rc))
115 return rc;
116
117 /*
118 * Allocate and initialize a new callback record.
119 */
120 pNew = (PRTTERMCALLBACKREC)RTMemAlloc(sizeof(*pNew));
121 if (!pNew)
122 return VERR_NO_MEMORY;
123 pNew->pfnCallback = pfnCallback;
124 pNew->pvUser = pvUser;
125
126 /*
127 * Insert into the list.
128 */
129 rc = RTSemFastMutexRequest(g_hFastMutex);
130 if (RT_SUCCESS(rc))
131 {
132 g_cCallbacks++;
133 pNew->pNext = g_pCallbackHead;
134 g_pCallbackHead = pNew;
135
136 RTSemFastMutexRelease(g_hFastMutex);
137 }
138 else
139 RTMemFree(pNew);
140
141 return rc;
142}
143RT_EXPORT_SYMBOL(RTTermRegisterCallback);
144
145
146RTDECL(int) RTTermDeregisterCallback(PFNRTTERMCALLBACK pfnCallback, void *pvUser)
147{
148 /*
149 * g_hFastMutex will be NIL if we're not initialized.
150 */
151 int rc;
152 RTSEMFASTMUTEX hFastMutex = g_hFastMutex;
153 if (hFastMutex == NIL_RTSEMFASTMUTEX)
154 return VERR_NOT_FOUND;
155
156 rc = RTSemFastMutexRequest(hFastMutex);
157 if (RT_SUCCESS(rc))
158 {
159
160 /*
161 * Search for the specified pfnCallback/pvUser pair.
162 */
163 PRTTERMCALLBACKREC pPrev = NULL;
164 PRTTERMCALLBACKREC pCur = g_pCallbackHead;
165 while (pCur)
166 {
167 if ( pCur->pfnCallback == pfnCallback
168 && pCur->pvUser == pvUser)
169 {
170 if (pPrev)
171 pPrev->pNext = pCur->pNext;
172 else
173 g_pCallbackHead = pCur->pNext;
174 g_cCallbacks--;
175 RTSemFastMutexRelease(hFastMutex);
176
177 pCur->pfnCallback = NULL;
178 RTMemFree(pCur);
179 return VINF_SUCCESS;
180 }
181
182 /* next */
183 pPrev = pCur;
184 pCur = pCur->pNext;
185 }
186
187 RTSemFastMutexRelease(hFastMutex);
188 rc = VERR_NOT_FOUND;
189 }
190
191 return rc;
192}
193RT_EXPORT_SYMBOL(RTTermDeregisterCallback);
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}
242RT_EXPORT_SYMBOL(RTTermRunCallbacks);
243
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