ossl_rcu_lock_new.pod 6.2 KB

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