VirtualBox

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

Last change on this file since 87835 was 85121, checked in by vboxsync, 4 years ago

iprt/cdefs.h: Refactored the typedef use of DECLCALLBACK as well as DECLCALLBACKMEMBER to wrap the whole expression, similar to the DECLR?CALLBACKMEMBER macros. This allows adding a throw() at the end when compiling with the VC++ compiler to indicate that the callbacks won't throw anything, so we can stop supressing the C5039 warning about passing functions that can potential throw C++ exceptions to extern C code that can't necessarily cope with such (unwind,++). Introduced a few _EX variations that allows specifying different/no calling convention too, as that's handy when dynamically resolving host APIs. Fixed numerous places missing DECLCALLBACK and such. Left two angry @todos regarding use of CreateThread. bugref:9794

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.9 KB
Line 
1/** @file
2 * IPRT - Execute Once.
3 */
4
5/*
6 * Copyright (C) 2006-2020 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/**
195 * Resets an execute once variable.
196 *
197 * The caller is responsible for making sure there are no concurrent accesses to
198 * the execute once variable.
199 *
200 * @param pOnce Pointer to the execute once variable.
201 */
202RTDECL(void) RTOnceReset(PRTONCE pOnce);
203
204/** @} */
205
206RT_C_DECLS_END
207
208#endif /* !IPRT_INCLUDED_once_h */
209
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