1=pod 2 3=head1 NAME 4 5ossl_rcu_lock_new, 6ossl_rcu_lock_free, ossl_rcu_read_lock, 7ossl_rcu_read_unlock, ossl_rcu_write_lock, 8ossl_rcu_write_unlock, ossl_synchronize_rcu, 9ossl_rcu_call, ossl_rcu_deref, 10ossl_rcu_assign_ptr, ossl_rcu_uptr_deref, 11ossl_rcu_assign_uptr 12- perform read-copy-update locking 13 14=head1 SYNOPSIS 15 16 CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers, OSSL_LIB_CTX *ctx); 17 void ossl_rcu_read_lock(CRYPTO_RCU_LOCK *lock); 18 void ossl_rcu_write_lock(CRYPTO_RCU_LOCK *lock); 19 void ossl_rcu_write_unlock(CRYPTO_RCU_LOCK *lock); 20 void ossl_rcu_read_unlock(CRYPTO_RCU_LOCK *lock); 21 void ossl_synchronize_rcu(CRYPTO_RCU_LOCK *lock); 22 void ossl_rcu_call(CRYPTO_RCU_LOCK *lock, rcu_cb_fn cb, void *data); 23 void *ossl_rcu_deref(void **p); 24 void ossl_rcu_uptr_deref(void **p); 25 void ossl_rcu_assign_ptr(void **p, void **v); 26 void ossl_rcu_assign_uptr(void **p, void **v); 27 void ossl_rcu_lock_free(CRYPTO_RCU_LOCK *lock); 28 29=head1 DESCRIPTION 30 31OpenSSL can be safely used in multi-threaded applications provided that 32support for the underlying OS threading API is built-in. Currently, OpenSSL 33supports the pthread and Windows APIs. OpenSSL can also be built without 34any multi-threading support, for example on platforms that don't provide 35any threading support or that provide a threading API that is not yet 36supported by OpenSSL. 37 38In addition to more traditional Read/Write locks, OpenSSL provides 39Read-Copy-Update (RCU) locks, which allow for always nonblocking read paths. 40 41The following multi-threading functions are provided: 42 43=over 2 44 45=item * 46 47ossl_rcu_assign_uptr() assigns the value pointed to by v to the 48location pointed to by p. This function should typically not be used, rely 49instead on the ossl_rcu_assign_ptr() macro. 50 51=item * 52 53ossl_rcu_uptr_deref() returns the value stored at the 54location pointed to by p. This function should typically not be used, rely 55instead on the ossl_rcu_deref() macro. 56 57=item * 58 59ossl_rcu_assign_ptr() assigns the value pointed to by v to 60location pointed to by p. 61 62=item * 63 64ossl_rcu_lock_new() allocates a new RCU lock. The I<num_writers> param 65indicates the number of write side threads which may execute 66ossl_synchronize_rcu() in parallel. The value must be at least 1, but may be 67larger to obtain increased write side throughput at the cost of additional 68internal memory usage. A value of 1 is generally recommended. The I<ctx> 69parameter references the library context in which the lock is allocated. 70 71=item * 72 73ossl_rcu_read_lock() acquires a read side hold on data protected by 74the lock. 75 76=item * 77 78ossl_rcu_read_unlock() releases a read side hold on data protected by 79the lock. 80 81=item * 82 83ossl_rcu_write_lock() acquires a write side hold on data protected by 84the lock. Note only one writer per lock is permitted, as with read/write locks. 85 86=item * 87 88ossl_rcu_write_unlock() releases a write side hold on data protected 89by the lock. 90 91=item * 92 93ossl_synchronize_rcu() blocks the calling thread until all read side 94holds on the lock have been released, guaranteeing that any old data updated by 95the write side thread is safe to free. 96 97=item * 98 99ossl_rcu_call() enqueues a callback function to the lock, to be called 100when the next synchronization completes. Note: It is not guaranteed that the 101thread which enqueued the callback will be the thread which executes the 102callback 103 104=item * 105 106ossl_rcu_deref(p) atomically reads a pointer under an RCU locks 107protection 108 109=item * 110 111ossl_rcu_assign_ptr(p,v) atomically writes to a pointer under an 112RCU locks protection 113 114=item * 115 116ossl_rcu_lock_free() frees an allocated RCU lock 117 118=back 119 120=head1 RETURN VALUES 121 122ossl_rcu_lock_new() returns a pointer to a newly created RCU lock structure. 123 124ossl_rcu_deref() and ossl_rcu_uptr_deref() return the value pointed 125to by the passed in value v. 126 127All other functions return no value. 128 129=head1 EXAMPLES 130 131You can find out if OpenSSL was configured with thread support: 132 133 #include <openssl/opensslconf.h> 134 #if defined(OPENSSL_THREADS) 135 /* thread support enabled */ 136 #else 137 /* no thread support */ 138 #endif 139 140This example safely initializes and uses a lock. 141 142 #include "internal/rcu.h" 143 144 struct foo { 145 int aval; 146 char *name; 147 }; 148 149 static CRYPTO_ONCE once = CRYPTO_ONCE_STATIC_INIT; 150 static CRYPTO_RCU_LOCK *lock; 151 static struct foo *fooptr = NULL; 152 153 static void myinit(void) 154 { 155 lock = ossl_rcu_lock_new(1); 156 } 157 158 static int initlock(void) 159 { 160 if (!RUN_ONCE(&once, myinit) || lock == NULL) 161 return 0; 162 return 1; 163 } 164 165 static void writer_thread() 166 { 167 struct foo *newfoo; 168 struct foo *oldfoo; 169 170 initlock(); 171 172 /* 173 * update steps in an rcu model 174 */ 175 176 /* 177 * 1) create a new shared object 178 */ 179 newfoo = OPENSSL_zalloc(sizeof(struct foo)); 180 181 /* 182 * acquire the write side lock 183 */ 184 ossl_rcu_write_lock(lock); 185 186 /* 187 * 2) read the old pointer 188 */ 189 oldfoo = ossl_rcu_deref(&fooptr); 190 191 /* 192 * 3) Copy the old pointer to the new object, and 193 * make any needed adjustments 194 */ 195 memcpy(newfoo, oldfoo, sizeof(struct foo)); 196 newfoo->aval++; 197 198 /* 199 * 4) Update the shared pointer to the new value 200 */ 201 ossl_rcu_assign_ptr(&fooptr, &newfoo); 202 203 /* 204 * 5) Release the write side lock 205 */ 206 ossl_rcu_write_unlock(lock); 207 208 /* 209 * 6) wait for any read side holds on the old data 210 * to be released 211 */ 212 ossl_synchronize_rcu(lock); 213 214 /* 215 * 7) free the old pointer, now that there are no 216 * further readers 217 */ 218 OPENSSL_free(oldfoo); 219 } 220 221 static void reader_thread() 222 { 223 struct foo *myfoo = NULL; 224 int a; 225 /* 226 * 1) Acquire a read side hold on the shared data 227 */ 228 ossl_rcu_read_lock(lock); 229 230 /* 231 * 2) Access the shared data pointer 232 */ 233 myfoo = ossl_rcu_deref(&fooptr); 234 235 /* 236 * 3) Read the data from the pointer 237 */ 238 a = myfoo->aval; 239 240 /* 241 * 4) Indicate our hold on the shared data is complete 242 */ 243 ossl_rcu_read_unlock(lock); 244 } 245 246=head1 SEE ALSO 247 248L<crypto(7)>, L<openssl-threads(7)>. 249 250=head1 COPYRIGHT 251 252Copyright 2023-2024 The OpenSSL Project Authors. All Rights Reserved. 253 254Licensed under the Apache License 2.0 (the "License"). You may not use 255this file except in compliance with the License. You can obtain a copy 256in the file LICENSE in the source distribution or at 257L<https://www.openssl.org/source/license.html>. 258 259=cut 260