1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the COPYING file, which can be found at the root of the source code       *
9  * distribution tree, or in https://www.hdfgroup.org/licenses.               *
10  * If you do not have access to either file, you may request a copy from     *
11  * help@hdfgroup.org.                                                        *
12  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13 
14 /*-------------------------------------------------------------------------
15  *
16  * Created:     H5TSprivate.h
17  *
18  * Purpose:     Thread-safety abstractions used by the library
19  *
20  *-------------------------------------------------------------------------
21  */
22 #ifndef H5TSprivate_H_
23 #define H5TSprivate_H_
24 
25 #ifdef H5_HAVE_THREADSAFE
26 
27 /* Public headers needed by this file */
28 #ifdef LATER
29 #include "H5TSpublic.h" /* Public API prototypes */
30 #endif                  /* LATER */
31 
32 /**************************/
33 /* Library Private Macros */
34 /**************************/
35 
36 /* Defines */
37 
38 #ifdef H5_HAVE_WIN_THREADS
39 
40 /* Scope Definitions (Pthreads only) */
41 #define H5TS_SCOPE_SYSTEM  0
42 #define H5TS_SCOPE_PROCESS 0
43 
44 /* Calling convention (Windows only) */
45 #define H5TS_CALL_CONV WINAPI
46 
47 /* Portability function aliases */
48 #define H5TS_get_thread_local_value(key)        TlsGetValue(key)
49 #define H5TS_set_thread_local_value(key, value) TlsSetValue(key, value)
50 #define H5TS_attr_init(attr)                    0
51 #define H5TS_attr_setscope(attr, scope)         0
52 #define H5TS_attr_destroy(attr)                 0
53 #define H5TS_wait_for_thread(thread)            WaitForSingleObject(thread, INFINITE)
54 #define H5TS_mutex_init(mutex)                  InitializeCriticalSection(mutex)
55 #define H5TS_mutex_lock_simple(mutex)           EnterCriticalSection(mutex)
56 #define H5TS_mutex_unlock_simple(mutex)         LeaveCriticalSection(mutex)
57 
58 /* No Pthreads equivalent - we use a custom H5TS call with that thread library */
59 #define H5TS_thread_id() ((uint64_t)GetCurrentThreadId())
60 
61 #else
62 
63 /* Scope Definitions (Pthreads only) */
64 #define H5TS_SCOPE_SYSTEM                       PTHREAD_SCOPE_SYSTEM
65 #define H5TS_SCOPE_PROCESS                      PTHREAD_SCOPE_PROCESS
66 
67 /* Calling convention (Windows only) */
68 #define H5TS_CALL_CONV                          /* N/A */
69 
70 /* Portability function aliases */
71 #define H5TS_get_thread_local_value(key)        pthread_getspecific(key)
72 #define H5TS_set_thread_local_value(key, value) pthread_setspecific(key, value)
73 #define H5TS_attr_init(attr)                    pthread_attr_init((attr))
74 #define H5TS_attr_setscope(attr, scope)         pthread_attr_setscope(attr, scope)
75 #define H5TS_attr_destroy(attr)                 pthread_attr_destroy(attr)
76 #define H5TS_wait_for_thread(thread)            pthread_join(thread, NULL)
77 #define H5TS_mutex_init(mutex)                  pthread_mutex_init(mutex, NULL)
78 #define H5TS_mutex_lock_simple(mutex)           pthread_mutex_lock(mutex)
79 #define H5TS_mutex_unlock_simple(mutex)         pthread_mutex_unlock(mutex)
80 
81 /* No Win32 thread equivalent - only needed for RW locks which are not supported
82  * under Windows threads.
83  */
84 #define H5TS_mutex_destroy(mutex)               pthread_mutex_destroy(mutex)
85 #define H5TS_cond_init(cond)                    pthread_cond_init(cond, NULL)
86 #define H5TS_cond_destroy(cond)                 pthread_cond_destroy(cond)
87 #define H5TS_cond_wait(cond, mutex)             pthread_cond_wait(cond, mutex)
88 #define H5TS_cond_signal(cond)                  pthread_cond_signal(cond)
89 #define H5TS_cond_broadcast(cond)               pthread_cond_broadcast(cond)
90 
91 #endif /* H5_HAVE_WIN_THREADS */
92 
93 /******************************************************************************
94  * Macros to maintain statistics on the Pthreads recursive R/W lock.
95  ******************************************************************************/
96 
97 #ifdef H5_USE_RECURSIVE_WRITER_LOCKS
98 
99 /* Magic values for struct sanity checking */
100 
101 /* RW lock */
102 #define H5TS_RW_LOCK_MAGIC 0XABCD
103 
104 /* RW lock entry counts */
105 #define H5TS_RW_ENTRY_COUNT_MAGIC 0XABBA
106 
107 /* Flag for favoring writers */
108 /* THIS SHOULD BE AN ENUM */
109 #define H5TS_RW_LOCK_POLICY_FAVOR_WRITERS 0
110 
111 #endif /* H5_USE_RECURSIVE_WRITER_LOCKS */
112 
113 /****************************/
114 /* Library Private Typedefs */
115 /****************************/
116 
117 /* Mutexes, Threads, and Attributes */
118 
119 #ifdef H5_HAVE_WIN_THREADS
120 
121 typedef struct H5TS_mutex_struct {
122     CRITICAL_SECTION CriticalSection;
123 } H5TS_mutex_t;
124 
125 #else
126 
127 typedef struct H5TS_mutex_struct {
128     pthread_t       owner_thread; /* current lock owner */
129     pthread_mutex_t atomic_lock;  /* lock for atomicity of new mechanism */
130     pthread_cond_t  cond_var;     /* condition variable */
131     unsigned int    lock_count;
132 } H5TS_mutex_t;
133 
134 #endif /* H5_HAVE_WIN_THREADS */
135 
136 /* Portability wrappers */
137 
138 #ifdef H5_HAVE_WIN_THREADS
139 
140 typedef HANDLE             H5TS_thread_t;
141 typedef HANDLE             H5TS_attr_t;
142 typedef CRITICAL_SECTION   H5TS_mutex_simple_t;
143 typedef DWORD              H5TS_key_t;
144 typedef INIT_ONCE          H5TS_once_t;
145 typedef CONDITION_VARIABLE H5TS_cond_t;
146 
147 #else
148 
149 typedef pthread_t       H5TS_thread_t;
150 typedef pthread_attr_t  H5TS_attr_t;
151 typedef pthread_mutex_t H5TS_mutex_simple_t;
152 typedef pthread_key_t   H5TS_key_t;
153 typedef pthread_once_t  H5TS_once_t;
154 typedef pthread_cond_t  H5TS_cond_t;
155 
156 #endif /* H5_HAVE_WIN_THREADS */
157 
158 #ifdef H5_USE_RECURSIVE_WRITER_LOCKS
159 
160 /******************************************************************************
161  *
162  * Structure H5TS_rw_lock_stats_t
163  *
164  * Catchall structure for statistics on the recursive p-threads based
165  * recursive R/W lock (see declaration of H5TS_rw_lock_t below).
166  *
167  * Since the mutex must be held when reading a consistent set of statistics
168  * from the recursibe R/W lock, it simplifies matters to bundle them into
169  * a single structure.  This structure exists for that purpose.
170  *
171  * If you modify this structure, be sure to make equivalent changes to
172  * the reset_stats initializer in H5TS_rw_lock_reset_stats().
173  *
174  * Individual fields are discussed below.
175  *
176  *                                           JRM -- 8/28/20
177  *
178  * Read lock stats:
179  *
180  * read_locks_granted: 64 bit integer used to count the total number of read
181  *              locks granted.  Note that this includes recursive lock
182  *              requests.
183  *
184  * read_locks_released: 64 bit integer used to count the total number of read
185  *              locks released.  Note that this includes recursive lock
186  *              release requests.
187  *
188  * real_read_locks_granted: 64 bit integer used to count the total number of
189  *              read locks granted, less any recursive lock requests.
190  *
191  * real_read_locks_released:  64 bit integer used to count the total number of
192  *              read locks released, less any recursive lock releases.
193  *
194  * max_read_locks; 64 bit integer used to track the maximum number of read
195  *              locks active at any point in time.
196  *
197  * max_read_lock_recursion_depth; 64 bit integer used to track the maximum
198  *              recursion depth observed for any read lock.
199  *
200  * read_locks_delayed: 64 bit integer used to track the number of read locks
201  *              that were not granted immediately.
202  *
203  * max_read_locks_delayed; 64 bit integer used to track the maximum number of
204  *              pending read locks at any point in time.
205  *
206  *
207  * Write lock stats:
208  *
209  * write_locks_granted: 64 bit integer used to count the total number of write
210  *              locks granted.  Note that this includes recursive lock
211  *              requests.
212  *
213  * write_locks_released: 64 bit integer used to count the total number of write
214  *              locks released.  Note that this includes recursive lock
215  *              release requests.
216  *
217  * real_write_locks_granted: 64 bit integer used to count the total number of
218  *              write locks granted, less any recursive lock requests.
219  *
220  * real_write_locks_released:  64 bit integer used to count the total number of
221  *              write locks released, less any recursive lock releases.
222  *
223  * max_write_locks; 64 bit integer used to track the maximum number of write
224  *              locks active at any point in time.  Must be either zero or one.
225  *
226  * max_write_lock_recursion_depth; 64 bit integer used to track the maximum
227  *              recursion depth observed for any write lock.
228  *
229  * write_locks_delayed: 64 bit integer used to track the number of write locks
230  *              that were not granted immediately.
231  *
232  * max_write_locks_delayed; 64 bit integer used to track the maximum number of
233  *              pending write locks at any point in time.
234  *
235  ******************************************************************************/
236 
237 typedef struct H5TS_rw_lock_stats_t {
238 
239     int64_t read_locks_granted;
240     int64_t read_locks_released;
241     int64_t real_read_locks_granted;
242     int64_t real_read_locks_released;
243     int64_t max_read_locks;
244     int64_t max_read_lock_recursion_depth;
245     int64_t read_locks_delayed;
246     int64_t max_read_locks_pending;
247     int64_t write_locks_granted;
248     int64_t write_locks_released;
249     int64_t real_write_locks_granted;
250     int64_t real_write_locks_released;
251     int64_t max_write_locks;
252     int64_t max_write_lock_recursion_depth;
253     int64_t write_locks_delayed;
254     int64_t max_write_locks_pending;
255 
256 } H5TS_rw_lock_stats_t;
257 
258 /******************************************************************************
259  *
260  * Structure H5TS_rw_lock_t
261  *
262  * A read / write lock, is a lock that allows either an arbitrary number
263  * of readers, or a single writer into a critical region.  A recurssive
264  * lock is one that allows a thread that already has a lock (be it read or
265  * write) to successfully request the lock again, only dropping the lock
266  * when the number of un-lock calls equals the number of lock calls.
267  *
268  * Note that we can't use the Pthreads or Win32 R/W locks, as while they
269  * permit recursive read locks, they disallow recursive write locks.
270  *
271  * This structure is a catchall for the fields needed to implement a
272  * recursive R/W lock that allows recursive write locks, and for the
273  * associate statistics collection fields.
274  *
275  * This recursive R/W lock implementation is an extension of the R/W lock
276  * implementation given in "UNIX network programming" Volume 2, Chapter 8
277  * by w. Richard Stevens, 2nd edition.
278  *
279  * Individual fields are discussed below.
280  *
281  *                                           JRM  -- 8/28/20
282  *
283  * magic:       Unsigned 32 bit integer field used for sanity checking.  This
284  *              fields must always be set to H5TS_RW_LOCK_MAGIC.
285  *              If this structure is allocated dynamically, remember to set
286  *              it to some invalid value before discarding the structure.
287  *
288  * policy       Integer containing a code indicating the precidence policy
289  *              used by the R/W lock.  The supported policies are listed
290  *              below:
291  *
292  *              H5TS__RW_LOCK_POLICY__FAVOR_WRITERS:
293  *
294  *              If selected, the R/W lock will grant access to a pending
295  *              writer if there are both pending readers and writers.
296  *
297  *
298  *              --- Define other policies here ---
299  *
300  *
301  * mutex:       Mutex used to maintain mutual exclusion on the fields of
302  *              of this structure.
303  *
304  * readers_cv:  Condition variable used for waiting readers.
305  *
306  * writers_cv:  Condition variable used for waiting writers.
307  *
308  * waiting_readers_count: 32 bit integer used to maintain a count of
309  *              waiting readers.  This value should always be non-negative.
310  *
311  * waiting_writers_count: 32 bit integer used to maintain a count of
312  *              waiting writers.  This value should always be non-negative.
313  *
314  * The following two fields could be combined into a single field, with
315  * the count of active readers being represented by a positive value, and
316  * the number of writers by a negative value.  Two fields are used to
317  * facilitate sanity checking.
318  *
319  * active_readers: 32 bit integer used to maintain a count of
320  *              readers that currently hold a read lock.  This value
321  *              must be zero if active_writers is positive. It should
322  *              never be negative.
323  *
324  * active_writers: 32 bit integer used to maintain a count of
325  *              writers that currently hold a write lock.  This value
326  *              must always be either 0 or 1, and must be zero if
327  *              active_readers is positive.  It should never be negative.
328  *
329  * rec_entry_count_key: Instance of thread-local key used to maintain
330  *              a thread specific lock type and recursive entry count
331  *              for all threads holding a lock.
332  *
333  * stats:       Instance of H5TS_rw_lock_stats_t used to track
334  *              statistics on the recursive R/W lock.  See the declaration
335  *              of the structure for discussion of its fields.
336  *
337  *              Note that the stats are gathered into a structure because
338  *              we must obtain the mutex when reading the statistics to
339  *              avoid changes while the statistics are being read.  Collecting
340  *              them into a structure facilitates this.
341  *
342  ******************************************************************************/
343 
344 typedef struct H5TS_rw_lock_t {
345 
346     uint32_t                    magic;
347     int32_t                     policy;
348     H5TS_mutex_simple_t         mutex;
349     H5TS_cond_t                 readers_cv;
350     H5TS_cond_t                 writers_cv;
351     int32_t                     waiting_readers_count;
352     int32_t                     waiting_writers_count;
353     int32_t                     active_readers;
354     int32_t                     active_writers;
355     H5TS_key_t                  rec_entry_count_key;
356     int32_t                     writer_rec_entry_count;
357     struct H5TS_rw_lock_stats_t stats;
358 
359 } H5TS_rw_lock_t;
360 
361 /******************************************************************************
362  *
363  * Structure H5TS_rec_entry_count
364  *
365  * Strucure associated with the reader_rec_entry_count_key defined in
366  * H5TS_rw_lock_t.
367  *
368  * The primary purpose of this structure is to maintain a count of recursive
369  * locks so that the lock can be dropped when the count drops to zero.
370  *
371  * Aditional fields are included for purposes of sanity checking.
372  *
373  * Individual fields are discussed below.
374  *
375  *                                           JRM  -- 8/28/20
376  *
377  * magic:       Unsigned 32 bit integer field used for sanity checking.  This
378  *              field must always be set to H5TS_RW_ENTRY_COUNT_MAGIC, and
379  *              should be set to some invalid value just before the structure
380  *              is freed.
381  *
382  * write_lock:  Boolean field that is set to TRUE if the count is for a write
383  *              lock, and to FALSE if it is for a read lock.
384  *
385  * rec_lock_count: Count of the number of recursive lock calls, less
386  *              the number of recursive unlock calls.  The lock in question
387  *              is dropped when the count drops to zero.
388  *
389  ******************************************************************************/
390 
391 typedef struct H5TS_rec_entry_count {
392 
393     uint32_t magic;
394     hbool_t  write_lock;
395     int64_t  rec_lock_count;
396 
397 } H5TS_rec_entry_count;
398 
399 #endif /* H5_USE_RECURSIVE_WRITER_LOCKS */
400 
401 /*****************************/
402 /* Library-private Variables */
403 /*****************************/
404 
405 /* Library-scope global variables */
406 
407 /* Library initialization */
408 extern H5TS_once_t H5TS_first_init_g;
409 
410 /* Error stacks */
411 extern H5TS_key_t H5TS_errstk_key_g;
412 
413 /* Function stacks */
414 #ifdef H5_HAVE_CODESTACK
415 extern H5TS_key_t H5TS_funcstk_key_g;
416 #endif
417 
418 /* API contexts */
419 extern H5TS_key_t H5TS_apictx_key_g;
420 
421 /***********************************/
422 /* Private static inline functions */
423 /***********************************/
424 
425 #ifdef H5_USE_RECURSIVE_WRITER_LOCKS
426 
427 static inline void
H5TS_update_stats_rd_lock(H5TS_rw_lock_t * rw_lock,H5TS_rec_entry_count * count)428 H5TS_update_stats_rd_lock(H5TS_rw_lock_t *rw_lock, H5TS_rec_entry_count *count)
429 {
430     HDassert(rw_lock);
431     HDassert(rw_lock->magic == H5TS_RW_LOCK_MAGIC);
432     HDassert(count);
433     HDassert(count->magic == H5TS_RW_ENTRY_COUNT_MAGIC);
434     HDassert(count->rec_lock_count >= 1);
435     HDassert(!count->write_lock);
436 
437     rw_lock->stats.read_locks_granted++;
438 
439     if (count->rec_lock_count == 1) {
440 
441         rw_lock->stats.real_read_locks_granted++;
442 
443         if (rw_lock->active_readers > rw_lock->stats.max_read_locks)
444             rw_lock->stats.max_read_locks = rw_lock->active_readers;
445     }
446 
447     if (count->rec_lock_count > rw_lock->stats.max_read_lock_recursion_depth)
448         rw_lock->stats.max_read_lock_recursion_depth = count->rec_lock_count;
449 
450 } /* end H5TS_update_stats_rd_lock() */
451 
452 static inline void
H5TS_update_stats_rd_lock_delay(H5TS_rw_lock_t * rw_lock,int waiting_count)453 H5TS_update_stats_rd_lock_delay(H5TS_rw_lock_t *rw_lock, int waiting_count)
454 {
455     HDassert(rw_lock);
456     HDassert(rw_lock->magic == H5TS_RW_LOCK_MAGIC);
457     HDassert((waiting_count) > 0);
458 
459     rw_lock->stats.read_locks_delayed++;
460 
461     if (rw_lock->stats.max_read_locks_pending < waiting_count)
462         rw_lock->stats.max_read_locks_pending = (waiting_count);
463 
464 } /* end H5TS_update_stats_rd_lock_delay() */
465 
466 static inline void
H5TS_update_stats_rd_unlock(H5TS_rw_lock_t * rw_lock,H5TS_rec_entry_count * count)467 H5TS_update_stats_rd_unlock(H5TS_rw_lock_t *rw_lock, H5TS_rec_entry_count *count)
468 {
469     HDassert(rw_lock);
470     HDassert(rw_lock->magic == H5TS_RW_LOCK_MAGIC);
471     HDassert(count);
472     HDassert(count->magic == H5TS_RW_ENTRY_COUNT_MAGIC);
473     HDassert(count->rec_lock_count >= 0);
474     HDassert(!count->write_lock);
475 
476     rw_lock->stats.read_locks_released++;
477 
478     if (count->rec_lock_count == 0)
479         rw_lock->stats.real_read_locks_released++;
480 
481 } /* end H5TS_update_stats_rd_unlock() */
482 
483 static inline void
H5TS_update_stats_wr_lock(H5TS_rw_lock_t * rw_lock,H5TS_rec_entry_count * count)484 H5TS_update_stats_wr_lock(H5TS_rw_lock_t *rw_lock, H5TS_rec_entry_count *count)
485 {
486     HDassert(rw_lock);
487     HDassert(rw_lock->magic == H5TS_RW_LOCK_MAGIC);
488     HDassert(count);
489     HDassert(count->magic == H5TS_RW_ENTRY_COUNT_MAGIC);
490     HDassert(count->rec_lock_count >= 1);
491     HDassert(count->write_lock);
492 
493     rw_lock->stats.write_locks_granted++;
494 
495     if (count->rec_lock_count == 1) {
496 
497         rw_lock->stats.real_write_locks_granted++;
498 
499         if (rw_lock->active_writers > rw_lock->stats.max_write_locks)
500             rw_lock->stats.max_write_locks = rw_lock->active_writers;
501     }
502 
503     if (count->rec_lock_count > rw_lock->stats.max_write_lock_recursion_depth)
504         rw_lock->stats.max_write_lock_recursion_depth = count->rec_lock_count;
505 
506 } /* end H5TS_update_stats_wr_lock() */
507 
508 static inline void
H5TS_update_stats_wr_lock_delay(H5TS_rw_lock_t * rw_lock,int waiting_count)509 H5TS_update_stats_wr_lock_delay(H5TS_rw_lock_t *rw_lock, int waiting_count)
510 {
511     HDassert(rw_lock);
512     HDassert(rw_lock->magic == H5TS_RW_LOCK_MAGIC);
513     HDassert(waiting_count > 0);
514 
515     rw_lock->stats.write_locks_delayed++;
516 
517     if (rw_lock->stats.max_write_locks_pending < waiting_count)
518         rw_lock->stats.max_write_locks_pending = waiting_count;
519 
520 } /* end H5TS_update_stats_wr_lock_delay() */
521 
522 static inline void
H5TS_update_stats_wr_unlock(H5TS_rw_lock_t * rw_lock,H5TS_rec_entry_count * count)523 H5TS_update_stats_wr_unlock(H5TS_rw_lock_t *rw_lock, H5TS_rec_entry_count *count)
524 {
525     HDassert(rw_lock);
526     HDassert(rw_lock->magic == H5TS_RW_LOCK_MAGIC);
527     HDassert(count);
528     HDassert(count->magic == H5TS_RW_ENTRY_COUNT_MAGIC);
529     HDassert(count->rec_lock_count >= 0);
530     HDassert(count->write_lock);
531 
532     rw_lock->stats.write_locks_released++;
533 
534     if (count->rec_lock_count == 0)
535         rw_lock->stats.real_write_locks_released++;
536 
537 } /* end H5TS_update_stats_wr_unlock() */
538 #endif
539 
540 /***************************************/
541 /* Library-private Function Prototypes */
542 /***************************************/
543 
544 /* Platform-specific functions */
545 #ifdef H5_HAVE_WIN_THREADS
546 
547 /* Functions called from DllMain */
548 H5_DLL BOOL CALLBACK H5TS_win32_process_enter(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex);
549 H5_DLL void          H5TS_win32_process_exit(void);
550 H5_DLL herr_t        H5TS_win32_thread_enter(void);
551 H5_DLL herr_t        H5TS_win32_thread_exit(void);
552 
553 #else
554 
555 H5_DLL uint64_t H5TS_thread_id(void);
556 H5_DLL void     H5TS_pthread_first_thread_init(void);
557 
558 #endif /* H5_HAVE_WIN_THREADS */
559 
560 /* Library-scope routines */
561 /* (Only used within H5private.h macros) */
562 H5_DLL herr_t H5TS_mutex_lock(H5TS_mutex_t *mutex);
563 H5_DLL herr_t H5TS_mutex_unlock(H5TS_mutex_t *mutex);
564 H5_DLL herr_t H5TS_cancel_count_inc(void);
565 H5_DLL herr_t H5TS_cancel_count_dec(void);
566 
567 /* Fully recursive R/W lock related function declarations */
568 #ifdef H5_USE_RECURSIVE_WRITER_LOCKS
569 H5_DLL H5TS_rec_entry_count *H5TS_alloc_rec_entry_count(hbool_t write_lock);
570 H5_DLL void                  H5TS_free_rec_entry_count(void *target);
571 H5_DLL herr_t                H5TS_rw_lock_init(H5TS_rw_lock_t *rw_lock, int policy);
572 H5_DLL herr_t                H5TS_rw_lock_destroy(H5TS_rw_lock_t *rw_lock);
573 H5_DLL herr_t                H5TS_rw_rdlock(H5TS_rw_lock_t *rw_lock);
574 H5_DLL herr_t                H5TS_rw_wrlock(H5TS_rw_lock_t *rw_lock);
575 H5_DLL herr_t                H5TS_rw_unlock(H5TS_rw_lock_t *rw_lock);
576 H5_DLL herr_t                H5TS_rw_lock_get_stats(H5TS_rw_lock_t *rw_lock, H5TS_rw_lock_stats_t *stats);
577 H5_DLL herr_t                H5TS_rw_lock_reset_stats(H5TS_rw_lock_t *rw_lock);
578 H5_DLL herr_t                H5TS_rw_lock_print_stats(const char *header_str, H5TS_rw_lock_stats_t *stats);
579 #endif
580 
581 /* Testing routines */
582 H5_DLL H5TS_thread_t H5TS_create_thread(void *(*func)(void *), H5TS_attr_t *attr, void *udata);
583 
584 #else /* H5_HAVE_THREADSAFE */
585 
586 /* Non-threadsafe code needs this */
587 #define H5TS_thread_id() ((uint64_t)0)
588 
589 #endif /* H5_HAVE_THREADSAFE */
590 
591 #endif /* H5TSprivate_H_ */
592