VirtualBox

source: vbox/trunk/src/libs/openssl-3.3.2/crypto/threads_iprt.c@ 108358

最後變更 在這個檔案從108358是 108218,由 vboxsync 提交於 5 週 前

openssl-3.3.2: Do not call RTSemRWDestroy inside AssertRC ​​bugref:10757

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 9.2 KB
 
1/* $Id: threads_iprt.c 108218 2025-02-14 09:42:27Z vboxsync $ */
2/** @file
3 * Crypto threading and atomic functions built upon IPRT.
4 */
5
6/*
7 * Copyright (C) 2016-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.alldomusa.eu.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#include <openssl/crypto.h>
29#include <crypto/cryptlib.h>
30//#include "internal/cryptlib.h"
31#include "internal/thread_arch.h"
32
33#if defined(OPENSSL_THREADS)
34
35# include <iprt/asm.h>
36# include <iprt/assert.h>
37# include <iprt/critsect.h>
38# include <iprt/errcore.h>
39# include <iprt/log.h>
40# include <iprt/process.h>
41# include <iprt/semaphore.h>
42
43/*
44 * @todo Replace this simple R/W lock implementation with proper RCU if better
45 * multithreaded openssl performance is actually needed (and gained via using RCU).
46 */
47# define VBOX_OPENSSL_WITH_RCU_SUPPORT
48# ifdef VBOX_OPENSSL_WITH_RCU_SUPPORT
49#include "internal/rcu.h"
50#include "rcu_internal.h"
51
52typedef struct rcu_cb_item *prcu_cb_item;
53
54/*
55 * This is the internal version of a CRYPTO_RCU_LOCK
56 * it is cast from CRYPTO_RCU_LOCK
57 */
58struct rcu_lock_st {
59 /* Callbacks to call for next ossl_synchronize_rcu */
60 struct rcu_cb_item *cb_items;
61
62 /* Read/write semaphore */
63 RTSEMRW rw_lock;
64};
65
66void *ossl_rcu_uptr_deref(void **p)
67{
68 /*
69 * Our automic reads include memory fence, so the thread that dereferences a pointer should be able
70 * to see the memory with all modifications that were made by other threads that did 'ossl_rcu_assign_uptr'
71 * prior to this dereference.
72 */
73 return ASMAtomicReadPtr(p);
74}
75
76void ossl_rcu_assign_uptr(void **p, void **v)
77{
78 ASMAtomicWritePtr(p, *v);
79}
80
81void ossl_rcu_read_lock(CRYPTO_RCU_LOCK *lock)
82{
83 RTSemRWRequestRead(lock->rw_lock, RT_INDEFINITE_WAIT);
84}
85
86void ossl_rcu_read_unlock(CRYPTO_RCU_LOCK *lock)
87{
88 RTSemRWReleaseRead(lock->rw_lock);
89}
90
91void ossl_rcu_write_lock(CRYPTO_RCU_LOCK *lock)
92{
93 RTSemRWRequestWrite(lock->rw_lock, RT_INDEFINITE_WAIT);
94}
95
96void ossl_rcu_write_unlock(CRYPTO_RCU_LOCK *lock)
97{
98 RTSemRWReleaseWrite(lock->rw_lock);
99}
100
101
102int ossl_rcu_call(CRYPTO_RCU_LOCK *lock, rcu_cb_fn cb, void *data)
103{
104 struct rcu_cb_item *new =
105 OPENSSL_zalloc(sizeof(*new));
106
107 if (new == NULL)
108 return 0;
109
110 new->data = data;
111 new->fn = cb;
112 /*
113 * Use __ATOMIC_ACQ_REL here to indicate that any prior writes to this
114 * list are visible to us prior to reading, and publish the new value
115 * immediately
116 * VBOX: Our atomic primitives do memory fence, which should be equivalent
117 * to __ATOMIC_ACQ_REL behavior.
118 */
119 new->next = ASMAtomicXchgPtrT(&lock->cb_items, new, prcu_cb_item);
120
121 return 1;
122}
123
124/* VBOX: no need to do any synchronization here, as we use simple R/W lock */
125void ossl_synchronize_rcu(CRYPTO_RCU_LOCK *lock)
126{
127 struct rcu_cb_item *cb_items, *tmpcb;
128
129 cb_items = ASMAtomicXchgPtrT(&lock->cb_items, NULL, prcu_cb_item);
130 /* handle any callbacks that we have */
131 while (cb_items != NULL) {
132 tmpcb = cb_items;
133 cb_items = cb_items->next;
134 tmpcb->fn(tmpcb->data);
135 OPENSSL_free(tmpcb);
136 }
137}
138
139CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers, OSSL_LIB_CTX *ctx)
140{
141 struct rcu_lock_st *new;
142
143 RT_NOREF(num_writers, ctx);
144
145 new = OPENSSL_zalloc(sizeof(*new));
146 if (new == NULL)
147 return NULL;
148
149 if (RT_FAILURE(RTSemRWCreate(&new->rw_lock)))
150 {
151 OPENSSL_free(new);
152 return NULL;
153 }
154 return new;
155}
156
157void ossl_rcu_lock_free(CRYPTO_RCU_LOCK *lock)
158{
159 struct rcu_lock_st *rlock = (struct rcu_lock_st *)lock;
160
161 if (lock == NULL)
162 return;
163
164 /* make sure we're synchronized */
165 ossl_synchronize_rcu(rlock);
166
167 int rc = RTSemRWDestroy(rlock->rw_lock);
168 AssertRC(rc);
169 OPENSSL_free(rlock);
170}
171# endif /* VBOX_OPENSSL_WITH_RCU_SUPPORT */
172
173/* Use read/write sections. */
174/*# define USE_RW_CRITSECT */ /** @todo test the code */
175
176# ifndef USE_RW_CRITSECT
177/*
178 * Of course it's wrong to use a critical section to implement a read/write
179 * lock. But as the OpenSSL interface is too simple (there is only read_lock()/
180 * write_lock() and only unspecified unlock() and the Windows implementatio
181 * (threads_win.c) uses {Enter,Leave}CriticalSection we do that here as well.
182 */
183# endif
184
185CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
186{
187# ifdef USE_RW_CRITSECT
188 PRTCRITSECTRW const pCritSect = (PRTCRITSECTRW)OPENSSL_zalloc(sizeof(*pCritSect));
189# else
190 PRTCRITSECT const pCritSect = (PRTCRITSECT)OPENSSL_zalloc(sizeof(*pCritSect));
191# endif
192 if (pCritSect)
193 {
194# ifdef USE_RW_CRITSECT
195 int const rc = RTCritSectRwInitEx(pCritSect, 0, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
196# else
197 int const rc = RTCritSectInitEx(pCritSect, 0, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
198# endif
199 if (RT_SUCCESS(rc))
200 return (CRYPTO_RWLOCK *)pCritSect;
201 OPENSSL_free(pCritSect);
202 }
203 return NULL;
204}
205
206int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
207{
208# ifdef USE_RW_CRITSECT
209 PRTCRITSECTRW const pCritSect = (PRTCRITSECTRW)lock;
210 int rc;
211
212 /* writers cannot acquire read locks the way CRYPTO_THREAD_unlock works
213 right now. It's also looks incompatible with pthread_rwlock_rdlock,
214 so this should never trigger. */
215 Assert(!RTCritSectRwIsWriteOwner(pCritSect));
216
217 rc = RTCritSectRwEnterShared(pCritSect);
218# else
219 int const rc = RTCritSectEnter((PRTCRITSECT)lock);
220# endif
221 AssertRCReturn(rc, 0);
222 return 1;
223}
224
225int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
226{
227# ifdef USE_RW_CRITSECT
228 int const rc = RTCritSectRwEnterExcl((PRTCRITSECTRW)lock);
229# else
230 int const rc = RTCritSectEnter((PRTCRITSECT)lock);
231# endif
232 AssertRCReturn(rc, 0);
233 return 1;
234}
235
236int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
237{
238# ifdef USE_RW_CRITSECT
239 PRTCRITSECTRW const pCritSect = (PRTCRITSECTRW)lock;
240 if (RTCritSectRwIsWriteOwner(pCritSect))
241 {
242 int const rc1 = RTCritSectRwLeaveExcl(pCritSect);
243 AssertRCReturn(rc1, 0);
244 }
245 else
246 {
247 int const rc2 = RTCritSectRwLeaveShared(pCritSect);
248 AssertRCReturn(rc2, 0);
249 }
250# else
251 int const rc = RTCritSectLeave((PRTCRITSECT)lock);
252 AssertRCReturn(rc, 0);
253# endif
254 return 1;
255}
256
257void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
258{
259 if (lock)
260 {
261# ifdef USE_RW_CRITSECT
262 PRTCRITSECTRW const pCritSect = (PRTCRITSECTRW)lock;
263 int const rc = RTCritSectRwDelete(pCritSect);
264# else
265 PRTCRITSECT const pCritSect = (PRTCRITSECT)lock;
266 int const rc = RTCritSectDelete(pCritSect);
267# endif
268 AssertRC(rc);
269 OPENSSL_free(pCritSect);
270 }
271}
272
273int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
274{
275 int rc = RTTlsAllocEx(key, (PFNRTTLSDTOR)cleanup); /* ASSUMES default calling convention is __cdecl, or close enough to it. */
276 AssertRCReturn(rc, 0);
277 return 1;
278}
279
280void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
281{
282 return RTTlsGet(*key);
283}
284
285int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
286{
287 int rc = RTTlsSet(*key, val);
288 AssertRCReturn(rc, 0);
289 return 1;
290}
291
292int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
293{
294 int rc = RTTlsFree(*key);
295 AssertRCReturn(rc, 0);
296 return 1;
297}
298
299CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
300{
301 return RTThreadSelf();
302}
303
304int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
305{
306 return (a == b);
307}
308
309/** @callback_method_impl{FNRTONCE,
310 * Wrapper that calls the @a init function given CRYPTO_THREAD_run_once().}
311 */
312static DECLCALLBACK(int32_t) cryptoThreadRunOnceWrapper(void *pvUser)
313{
314 void (*pfnInit)(void) = (void (*)(void))pvUser;
315 pfnInit();
316 return VINF_SUCCESS;
317}
318
319int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
320{
321 int rc = RTOnce(once, cryptoThreadRunOnceWrapper, (void *)(uintptr_t)init);
322 AssertRCReturn(rc, 0);
323 return 1;
324}
325
326int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
327{
328 *ret = ASMAtomicAddS32((int32_t volatile*)val, amount) + amount;
329 return 1;
330}
331
332int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret,
333 CRYPTO_RWLOCK *lock)
334{
335 uint64_t u64RetOld = ASMAtomicUoReadU64(val);
336 uint64_t u64New;
337 do
338 u64New = u64RetOld | op;
339 while (!ASMAtomicCmpXchgExU64(val, u64New, u64RetOld, &u64RetOld));
340 *ret = u64RetOld;
341
342 return 1;
343}
344
345int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock)
346{
347 *ret = ASMAtomicReadU64((uint64_t volatile *)val);
348 return 1;
349}
350
351int CRYPTO_atomic_load_int(int *val, int *ret, CRYPTO_RWLOCK *lock)
352{
353 *ret = ASMAtomicReadS32(val);
354 return 1;
355}
356
357#endif /* defined(OPENSSL_THREADS) */
358
359int openssl_init_fork_handlers(void)
360{
361 return 0;
362}
363
364int openssl_get_fork_id(void)
365{
366 return (int)RTProcSelf();
367}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette