WCSLIB: Thread-safety

WCSLIB 8.1

Thread-safety

Thanks to feedback and patches provided by Rodrigo Tobar Carrizo, as of release 5.18, WCSLIB is now completely thread-safe, with only a couple of minor provisos.

In particular, a number of new routines were introduced to preclude altering the global variables NPVMAX, NPSMAX, and NDPMAX, which determine how much memory to allocate for storing PVi_ma, PSi_ma, DPja, and DQia keyvalues: wcsinit(), lininit(), lindist(), and disinit(). Specifically, these new routines are now used by various WCSLIB routines, such as the header parsers, which previously temporarily altered the global variables, thus posing a thread hazard.

In addition, the Flex scanners were made reentrant and consequently should now be thread-safe. This was achieved by rewriting them as thin wrappers (with the same API) over scanners that were modified (with changed API), as required to use Flex's "reentrant" option.

For complete thread-safety, please observe the following provisos:

- The low-level routines wcsnpv(), wcsnps(), and disndp() are not thread-safe, but they are not used within WCSLIB itself other than to get (not set) the values of the global variables NPVMAX, NPSMAX, and NDPMAX.

  wcsinit() and disinit() only do so to get default values if the relevant parameters are not provided as function arguments. Note that wcsini() invokes wcsinit() with defaults which cause this behavior, as does disini() invoking disinit().

  The preset values of NPVMAX(=64), NPSMAX(=8), and NDPMAX(=256) are large enough to cover most practical cases. However, it may be desirable to tailor them to avoid allocating memory that remains unused. If so, and thread-safety is an issue, then use wcsinit() and disinit() instead with the relevant values specified. This is what WCSLIB routines, such as the header parsers wcspih() and wcsbth(), do to avoid wasting memory.

- wcserr_enable() sets a static variable and so is not thread-safe. However, the error reporting facility is not intended to be used dynamically. If detailed error messages are required, enable wcserr when execution starts and don't change it.

Note that diagnostic routines that print the contents of the various structs, namely celprt(), disprt(), linprt(), prjprt(), spcprt(), tabprt(), wcsprt(), and wcsperr() use printf() which is thread-safe by the POSIX requirement on `stdio`. However, this is only at the function level. Where multiple threads invoke these routines simultaneously their output is likely to be interleaved.