TurboJPEG: Make global error handling thread-safe

... on platforms that support thread-local storage.  This currently
includes all supported platforms except 32-bit macOS.

Fixes #396
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fe16d8e..8656d7a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -451,6 +451,21 @@
 endif()
 message(STATUS "INLINE = ${INLINE} (FORCE_INLINE = ${FORCE_INLINE})")
 
+if(WITH_TURBOJPEG)
+  if(MSVC)
+    set(THREAD_LOCAL "__declspec(thread)")
+  else()
+    set(THREAD_LOCAL "__thread")
+  endif()
+  check_c_source_compiles("${THREAD_LOCAL} int i;  int main(void) { i = 0;  return i; }" HAVE_THREAD_LOCAL)
+  if(HAVE_THREAD_LOCAL)
+    message(STATUS "THREAD_LOCAL = ${THREAD_LOCAL}")
+  else()
+    message(WARNING "Thread-local storage is not available.  The TurboJPEG API library's global error handler will not be thread-safe.")
+    unset(THREAD_LOCAL)
+  endif()
+endif()
+
 if(UNIX AND NOT APPLE)
   file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/conftest.map "VERS_1 { global: *; };")
   set(CMAKE_REQUIRED_FLAGS
diff --git a/ChangeLog.md b/ChangeLog.md
index 685da69..59fb2de 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -22,6 +22,11 @@
 included a similar fix for binary PPM/PGM files with maximum values greater
 than 255.
 
+4. The TurboJPEG API library's global error handler, which is used in functions
+such as `tjBufSize()` and `tjLoadImage()` that do not require a TurboJPEG
+instance handle, is now thread-safe on platforms that support thread-local
+storage.
+
 
 2.0.4
 =====
diff --git a/doc/html/group___turbo_j_p_e_g.html b/doc/html/group___turbo_j_p_e_g.html
index 5d67d78..2ee145f 100644
--- a/doc/html/group___turbo_j_p_e_g.html
+++ b/doc/html/group___turbo_j_p_e_g.html
@@ -2129,7 +2129,7 @@
 <p>Returns a descriptive error message explaining why the last command failed. </p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG compressor, decompressor, or transformer instance, or NULL if the error was generated by a global function (but note that retrieving the error message for a global function is not thread-safe.)</td></tr>
+    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG compressor, decompressor, or transformer instance, or NULL if the error was generated by a global function (but note that retrieving the error message for a global function is thread-safe only on platforms that support thread-local storage.)</td></tr>
   </table>
   </dd>
 </dl>
diff --git a/jconfigint.h.in b/jconfigint.h.in
index 55df053..68cbc2a 100644
--- a/jconfigint.h.in
+++ b/jconfigint.h.in
@@ -7,6 +7,9 @@
 /* How to obtain function inlining. */
 #define INLINE  @INLINE@
 
+/* How to obtain thread-local storage */
+#define THREAD_LOCAL  @THREAD_LOCAL@
+
 /* Define to the full name of this package. */
 #define PACKAGE_NAME  "@CMAKE_PROJECT_NAME@"
 
diff --git a/turbojpeg.c b/turbojpeg.c
index 6226bc9..e63d113 100644
--- a/turbojpeg.c
+++ b/turbojpeg.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2009-2019 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2009-2020 D. R. Commander.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -43,6 +43,7 @@
 #include "transupp.h"
 #include "./jpegcomp.h"
 #include "./cdjpeg.h"
+#include "jconfigint.h"
 
 extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **, unsigned long *,
                              boolean);
@@ -55,7 +56,7 @@
 
 /* Error handling (based on example in example.txt) */
 
-static char errStr[JMSG_LENGTH_MAX] = "No error";
+static THREAD_LOCAL char errStr[JMSG_LENGTH_MAX] = "No error";
 
 struct my_error_mgr {
   struct jpeg_error_mgr pub;
diff --git a/turbojpeg.h b/turbojpeg.h
index 074f015..f3209dd 100644
--- a/turbojpeg.h
+++ b/turbojpeg.h
@@ -1650,7 +1650,7 @@
  * @param handle a handle to a TurboJPEG compressor, decompressor, or
  * transformer instance, or NULL if the error was generated by a global
  * function (but note that retrieving the error message for a global function
- * is not thread-safe.)
+ * is thread-safe only on platforms that support thread-local storage.)
  *
  * @return a descriptive error message explaining why the last command failed.
  */