summaryrefslogtreecommitdiff
path: root/doc/html/pcre2api.html
diff options
context:
space:
mode:
Diffstat (limited to 'doc/html/pcre2api.html')
-rw-r--r--doc/html/pcre2api.html46
1 files changed, 38 insertions, 8 deletions
diff --git a/doc/html/pcre2api.html b/doc/html/pcre2api.html
index 5cd7ae0..e456647 100644
--- a/doc/html/pcre2api.html
+++ b/doc/html/pcre2api.html
@@ -626,14 +626,15 @@ documentation for more details.
<P>
In a more complicated situation, where patterns are compiled only when they are
first needed, but are still shared between threads, pointers to compiled
-patterns must be protected from simultaneous writing by multiple threads, at
-least until a pattern has been compiled. The logic can be something like this:
+patterns must be protected from simultaneous writing by multiple threads. This
+is somewhat tricky to do correctly. If you know that writing to a pointer is
+atomic in your environment, you can use logic like this:
<pre>
Get a read-only (shared) lock (mutex) for pointer
if (pointer == NULL)
{
Get a write (unique) lock for pointer
- pointer = pcre2_compile(...
+ if (pointer == NULL) pointer = pcre2_compile(...
}
Release the lock
Use pointer in pcre2_match()
@@ -641,10 +642,39 @@ least until a pattern has been compiled. The logic can be something like this:
Of course, testing for compilation errors should also be included in the code.
</P>
<P>
-If JIT is being used, but the JIT compilation is not being done immediately,
-(perhaps waiting to see if the pattern is used often enough) similar logic is
-required. JIT compilation updates a pointer within the compiled code block, so
-a thread must gain unique write access to the pointer before calling
+The reason for checking the pointer a second time is as follows: Several
+threads may have acquired the shared lock and tested the pointer for being
+NULL, but only one of them will be given the write lock, with the rest kept
+waiting. The winning thread will compile the pattern and store the result.
+After this thread releases the write lock, another thread will get it, and if
+it does not retest pointer for being NULL, will recompile the pattern and
+overwrite the pointer, creating a memory leak and possibly causing other
+issues.
+</P>
+<P>
+In an environment where writing to a pointer may not be atomic, the above logic
+is not sufficient. The thread that is doing the compiling may be descheduled
+after writing only part of the pointer, which could cause other threads to use
+an invalid value. Instead of checking the pointer itself, a separate "pointer
+is valid" flag (that can be updated atomically) must be used:
+<pre>
+ Get a read-only (shared) lock (mutex) for pointer
+ if (!pointer_is_valid)
+ {
+ Get a write (unique) lock for pointer
+ if (!pointer_is_valid)
+ {
+ pointer = pcre2_compile(...
+ pointer_is_valid = TRUE
+ }
+ }
+ Release the lock
+ Use pointer in pcre2_match()
+</pre>
+If JIT is being used, but the JIT compilation is not being done immediately
+(perhaps waiting to see if the pattern is used often enough), similar logic is
+required. JIT compilation updates a value within the compiled code block, so a
+thread must gain unique write access to the pointer before calling
<b>pcre2_jit_compile()</b>. Alternatively, <b>pcre2_code_copy()</b> or
<b>pcre2_code_copy_with_tables()</b> can be used to obtain a private copy of the
compiled code before calling the JIT compiler.
@@ -3959,7 +3989,7 @@ Cambridge, England.
</P>
<br><a name="SEC42" href="#TOC1">REVISION</a><br>
<P>
-Last updated: 05 October 2020
+Last updated: 04 November 2020
<br>
Copyright &copy; 1997-2020 University of Cambridge.
<br>