VirtualBox

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

Last change on this file since 96201 was 95902, checked in by vboxsync, 2 years ago

iprt/once.h: Added RTOnceWasInitialized. bugref:10261

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