]> git.ipfire.org Git - thirdparty/openssl.git/blob - doc/internal/man3/ossl_rcu_lock_new.pod
Make rcu_thread_key context-aware
[thirdparty/openssl.git] / doc / internal / man3 / ossl_rcu_lock_new.pod
1 =pod
2
3 =head1 NAME
4
5 ossl_rcu_lock_new,
6 ossl_rcu_lock_free, ossl_rcu_read_lock,
7 ossl_rcu_read_unlock, ossl_rcu_write_lock,
8 ossl_rcu_write_unlock, ossl_synchronize_rcu,
9 ossl_rcu_call, ossl_rcu_deref,
10 ossl_rcu_assign_ptr, ossl_rcu_uptr_deref,
11 ossl_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
31 OpenSSL can be safely used in multi-threaded applications provided that
32 support for the underlying OS threading API is built-in. Currently, OpenSSL
33 supports the pthread and Windows APIs. OpenSSL can also be built without
34 any multi-threading support, for example on platforms that don't provide
35 any threading support or that provide a threading API that is not yet
36 supported by OpenSSL.
37
38 In addition to more traditional Read/Write locks, OpenSSL provides
39 Read-Copy-Update (RCU) locks, which allow for always nonblocking read paths.
40
41 The following multi-threading functions are provided:
42
43 =over 2
44
45 =item *
46
47 ossl_rcu_assign_uptr() assigns the value pointed to by v to the
48 location pointed to by p. This function should typically not be used, rely
49 instead on the ossl_rcu_assign_ptr() macro.
50
51 =item *
52
53 ossl_rcu_uptr_deref() returns the value stored at the
54 location pointed to by p. This function should typically not be used, rely
55 instead on the ossl_rcu_deref() macro.
56
57 =item *
58
59 ossl_rcu_assign_ptr() assigns the value pointed to by v to
60 location pointed to by p.
61
62 =item *
63
64 ossl_rcu_lock_new() allocates a new RCU lock. The I<num_writers> param
65 indicates the number of write side threads which may execute
66 ossl_synchronize_rcu() in parallel. The value must be at least 1, but may be
67 larger to obtain increased write side throughput at the cost of additional
68 internal memory usage. A value of 1 is generally recommended. The I<ctx>
69 parameter references the library context in which the lock is allocated.
70
71 =item *
72
73 ossl_rcu_read_lock() acquires a read side hold on data protected by
74 the lock.
75
76 =item *
77
78 ossl_rcu_read_unlock() releases a read side hold on data protected by
79 the lock.
80
81 =item *
82
83 ossl_rcu_write_lock() acquires a write side hold on data protected by
84 the lock. Note only one writer per lock is permitted, as with read/write locks.
85
86 =item *
87
88 ossl_rcu_write_unlock() releases a write side hold on data protected
89 by the lock.
90
91 =item *
92
93 ossl_synchronize_rcu() blocks the calling thread until all read side
94 holds on the lock have been released, guaranteeing that any old data updated by
95 the write side thread is safe to free.
96
97 =item *
98
99 ossl_rcu_call() enqueues a callback function to the lock, to be called
100 when the next synchronization completes. Note: It is not guaranteed that the
101 thread which enqueued the callback will be the thread which executes the
102 callback
103
104 =item *
105
106 ossl_rcu_deref(p) atomically reads a pointer under an RCU locks
107 protection
108
109 =item *
110
111 ossl_rcu_assign_ptr(p,v) atomically writes to a pointer under an
112 RCU locks protection
113
114 =item *
115
116 ossl_rcu_lock_free() frees an allocated RCU lock
117
118 =back
119
120 =head1 RETURN VALUES
121
122 ossl_rcu_lock_new() returns a pointer to a newly created RCU lock structure.
123
124 ossl_rcu_deref() and ossl_rcu_uptr_deref() return the value pointed
125 to by the passed in value v.
126
127 All other functions return no value.
128
129 =head1 EXAMPLES
130
131 You 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
140 This 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
248 L<crypto(7)>, L<openssl-threads(7)>.
249
250 =head1 COPYRIGHT
251
252 Copyright 2023-2024 The OpenSSL Project Authors. All Rights Reserved.
253
254 Licensed under the Apache License 2.0 (the "License"). You may not use
255 this file except in compliance with the License. You can obtain a copy
256 in the file LICENSE in the source distribution or at
257 L<https://www.openssl.org/source/license.html>.
258
259 =cut