VirtualBox

source: vbox/trunk/include/iprt/once.h

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.6 KB
Line 
1/** @file
2 * IPRT - Execute Once.
3 */
4
5/*
6 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
7 *
8 * This file is part of VirtualBox base platform packages, as
9 * available from https://www.virtualbox.org.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation, in version 3 of the
14 * License.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses>.
23 *
24 * The contents of this file may alternatively be used under the terms
25 * of the Common Development and Distribution License Version 1.0
26 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
27 * in the VirtualBox distribution, in which case the provisions of the
28 * CDDL are applicable instead of those of the GPL.
29 *
30 * You may elect to license modified versions of this file under the
31 * terms and conditions of either the GPL or the CDDL or both.
32 *
33 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
34 */
35
36#ifndef IPRT_INCLUDED_once_h
37#define IPRT_INCLUDED_once_h
38#ifndef RT_WITHOUT_PRAGMA_ONCE
39# pragma once
40#endif
41
42#include <iprt/cdefs.h>
43#include <iprt/types.h>
44#include <iprt/asm.h>
45#include <iprt/errcore.h>
46#include <iprt/list.h>
47
48RT_C_DECLS_BEGIN
49
50/** @defgroup grp_rt_once RTOnce - Execute Once
51 * @ingroup grp_rt
52 * @{
53 */
54
55/**
56 * Callback that gets executed once.
57 *
58 * @returns IPRT style status code, RTOnce returns this.
59 *
60 * @param pvUser The user parameter.
61 */
62typedef DECLCALLBACKTYPE(int32_t, FNRTONCE,(void *pvUser));
63/** Pointer to a FNRTONCE. */
64typedef FNRTONCE *PFNRTONCE;
65
66/**
67 * Callback that gets executed on IPRT/process termination.
68 *
69 * @param pvUser The user parameter.
70 * @param fLazyCleanUpOk Indicates whether lazy clean-up is OK (see
71 * initterm.h).
72 */
73typedef DECLCALLBACKTYPE(void, FNRTONCECLEANUP,(void *pvUser, bool fLazyCleanUpOk));
74/** Pointer to a FNRTONCE. */
75typedef FNRTONCECLEANUP *PFNRTONCECLEANUP;
76
77/**
78 * Execute once structure.
79 *
80 * This is typically a global variable that is statically initialized
81 * by RTONCE_INITIALIZER.
82 */
83typedef struct RTONCE
84{
85 /** Event semaphore that the other guys are blocking on. */
86 RTSEMEVENTMULTI volatile hEventMulti;
87 /** Reference counter for hEventMulti. */
88 int32_t volatile cEventRefs;
89 /** See RTONCESTATE. */
90 int32_t volatile iState;
91 /** The return code of pfnOnce. */
92 int32_t volatile rc;
93
94 /** Pointer to the clean-up function. */
95 PFNRTONCECLEANUP pfnCleanUp;
96 /** Argument to hand to the clean-up function. */
97 void *pvUser;
98 /** Clean-up list entry. */
99 RTLISTNODE CleanUpNode;
100} RTONCE;
101/** Pointer to a execute once struct. */
102typedef RTONCE *PRTONCE;
103
104/**
105 * The execute once statemachine.
106 */
107typedef enum RTONCESTATE
108{
109 /** RTOnce() has not been called.
110 * Next: NO_SEM */
111 RTONCESTATE_UNINITIALIZED = 1,
112 /** RTOnce() is busy, no race.
113 * Next: CREATING_SEM, DONE */
114 RTONCESTATE_BUSY_NO_SEM,
115 /** More than one RTOnce() caller is busy.
116 * Next: BUSY_HAVE_SEM, BUSY_SPIN, DONE_CREATING_SEM, DONE */
117 RTONCESTATE_BUSY_CREATING_SEM,
118 /** More than one RTOnce() caller, the first is busy, the others are
119 * waiting.
120 * Next: DONE */
121 RTONCESTATE_BUSY_HAVE_SEM,
122 /** More than one RTOnce() caller, the first is busy, the others failed to
123 * create a semaphore and are spinning.
124 * Next: DONE */
125 RTONCESTATE_BUSY_SPIN,
126 /** More than one RTOnce() caller, the first has completed, the others
127 * are busy creating the semaphore.
128 * Next: DONE_HAVE_SEM */
129 RTONCESTATE_DONE_CREATING_SEM,
130 /** More than one RTOnce() caller, the first is busy grabbing the
131 * semaphore, while the others are waiting.
132 * Next: DONE */
133 RTONCESTATE_DONE_HAVE_SEM,
134 /** The execute once stuff has completed. */
135 RTONCESTATE_DONE = 16
136} RTONCESTATE;
137
138/** Static initializer for RTONCE variables. */
139#define RTONCE_INITIALIZER \
140 { NIL_RTSEMEVENTMULTI, 0, RTONCESTATE_UNINITIALIZED, VERR_INTERNAL_ERROR, NULL, NULL, { NULL, NULL } }
141
142
143/**
144 * Serializes execution of the pfnOnce function, making sure it's
145 * executed exactly once and that nobody returns from RTOnce before
146 * it has executed successfully.
147 *
148 * @returns IPRT like status code returned by pfnOnce.
149 *
150 * @param pOnce Pointer to the execute once variable.
151 * @param pfnOnce The function to executed once.
152 * @param pfnCleanUp The function that will be doing the cleaning up.
153 * Optional.
154 * @param pvUser The user parameter for pfnOnce.
155 */
156RTDECL(int) RTOnceSlow(PRTONCE pOnce, PFNRTONCE pfnOnce, FNRTONCECLEANUP pfnCleanUp, void *pvUser);
157
158/**
159 * Serializes execution of the pfnOnce function, making sure it's
160 * executed exactly once and that nobody returns from RTOnce before
161 * it has executed successfully.
162 *
163 * @returns IPRT like status code returned by pfnOnce.
164 *
165 * @param pOnce Pointer to the execute once variable.
166 * @param pfnOnce The function to executed once.
167 * @param pvUser The user parameter for pfnOnce.
168 */
169DECLINLINE(int) RTOnce(PRTONCE pOnce, PFNRTONCE pfnOnce, void *pvUser)
170{
171 int32_t iState = ASMAtomicUoReadS32(&pOnce->iState);
172 if (RT_LIKELY( iState == RTONCESTATE_DONE
173 || iState == RTONCESTATE_DONE_CREATING_SEM
174 || iState == RTONCESTATE_DONE_HAVE_SEM ))
175 return ASMAtomicUoReadS32(&pOnce->rc);
176 return RTOnceSlow(pOnce, pfnOnce, NULL, pvUser);
177}
178
179/**
180 * Execute pfnOnce once and register a termination clean-up callback.
181 *
182 * Serializes execution of the pfnOnce function, making sure it's
183 * executed exactly once and that nobody returns from RTOnce before
184 * it has executed successfully.
185 *
186 * @returns IPRT like status code returned by pfnOnce.
187 *
188 * @param pOnce Pointer to the execute once variable.
189 * @param pfnOnce The function to executed once.
190 * @param pfnCleanUp The function that will be doing the cleaning up.
191 * @param pvUser The user parameter for pfnOnce.
192 */
193DECLINLINE(int) RTOnceEx(PRTONCE pOnce, PFNRTONCE pfnOnce, PFNRTONCECLEANUP pfnCleanUp, void *pvUser)
194{
195 int32_t iState = ASMAtomicUoReadS32(&pOnce->iState);
196 if (RT_LIKELY( iState == RTONCESTATE_DONE
197 || iState == RTONCESTATE_DONE_CREATING_SEM
198 || iState == RTONCESTATE_DONE_HAVE_SEM ))
199 return ASMAtomicUoReadS32(&pOnce->rc);
200 return RTOnceSlow(pOnce, pfnOnce, pfnCleanUp, pvUser);
201}
202
203/**
204 * Resets an execute once variable.
205 *
206 * The caller is responsible for making sure there are no concurrent accesses to
207 * the execute once variable.
208 *
209 * @param pOnce Pointer to the execute once variable.
210 */
211RTDECL(void) RTOnceReset(PRTONCE pOnce);
212
213/**
214 * Check whether the execute once variable was successfullly initialized.
215 */
216DECLINLINE(bool) RTOnceWasInitialized(PRTONCE pOnce)
217{
218 int32_t const iState = ASMAtomicUoReadS32(&pOnce->iState);
219 int32_t const rc = ASMAtomicUoReadS32(&pOnce->rc);
220 return RT_SUCCESS(rc)
221 && ( iState == RTONCESTATE_DONE
222 || iState == RTONCESTATE_DONE_CREATING_SEM
223 || iState == RTONCESTATE_DONE_HAVE_SEM);
224}
225
226/** @} */
227
228RT_C_DECLS_END
229
230#endif /* !IPRT_INCLUDED_once_h */
231
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use