summaryrefslogtreecommitdiffstats
path: root/lib/qpthreads.h
blob: 2084545b82f75e230a931ab72e37ab350fcbc313 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
/* Quagga Pthreads support -- header
 * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
 *
 * This file is part of GNU Zebra.
 *
 * GNU Zebra is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2, or (at your
 * option) any later version.
 *
 * GNU Zebra is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GNU Zebra; see the file COPYING.  If not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#ifndef _ZEBRA_QPTHREADS_H
#define _ZEBRA_QPTHREADS_H

#include "misc.h"
#include <time.h>
#if HAVE_PTHREAD_H
#include <pthread.h>
#else
#error "do not HAVE_PTHREAD_H ???"
#endif
#if HAVE_PTHREAD_NP_H           /* For FreeBSD  */
#include <pthread_np.h>
#endif
#include <sched.h>
#include <unistd.h>
#include <errno.h>

#include "zassert.h"
#include "qtime.h"
#include "qstring.h"
#include "list_util.h"

/*==============================================================================
 * Quagga Pthread Interface -- qpt_xxxx
 *
 * Here are captured all the pthreads features used in Quagga.
 *
 * This provides:
 *
 *   * "wrappers" around functions which should not fail, but whose return
 *     code it is best to check... at least in a debug environment.
 *
 *   * the possibility of a separate no pthreads build where pthread facilities
 *     are either dummied out or otherwise dealt with.
 *
 *   * the ability to add any work-arounds which may be required if poorly
 *     conforming pthreads implementations are encountered
 */

#if !defined(_POSIX_THREADS) || (_POSIX_THREADS <= 0)
#error Require _POSIX_THREADS
#endif

/*------------------------------------------------------------------------------
 * Sort out QPTHREADS_DEBUG.
 *
 *   Set to 1 if defined, but blank.
 *   Set to QDEBUG if not defined.
 *
 *   Force to 0 if QPTHREADS_NO_DEBUG is defined and not zero.
 *
 * So: defaults to same as QDEBUG, but no matter what QDEBUG is set to:
 *
 *       * can set QPTHREADS_DEBUG    == 0 to turn off debug
 *       *  or set QPTHREADS_DEBUG    != 0 to turn on debug
 *       *  or set QPTHREADS_NO_DEBUG != 0 to force debug off
 */

#ifdef QPTHREADS_DEBUG          /* If defined, make it 1 or 0           */
# if IS_BLANK_OPTION(QPTHREADS_DEBUG)
#  undef  QPTHREADS_DEBUG
#  define QPTHREADS_DEBUG 1
# endif
#else                           /* If not defined, follow QDEBUG        */
# define QPTHREADS_DEBUG QDEBUG
#endif

#ifdef QPTHREADS_NO_DEBUG       /* Override, if defined                 */
# if IS_NOT_ZERO_OPTION(QPTHREADS_NO_DEBUG)
#  undef  QPTHREADS_DEBUG
#  define QPTHREADS_DEBUG 0
# endif
#endif

enum { qpthreads_debug = QPTHREADS_DEBUG } ;

/*==============================================================================
 * Global Switch -- this allows the library to be run WITHOUT pthreads !
 *
 * Nearly every qpthreads function is a NOP if either !qpthreads_enabled or
 * !qpthreads_active.
 *
 * Early in the morning a decision may be made to enable qpthreads -- that must
 * be done before any threads are created (or will zabort) and before any
 * mutexes and condition variables are initialised (or it will be too late).
 *
 * During shut down, if all but one pthread has been brought to a halt, then
 * it is safe to do many things which during normal running require locks etc.
 * to be obtained.  The qpthreads_active state is for those things which no
 * longer apply once all but one pthread has been stopped.
 *
 * Use: qpthreads_enabled   -- to test for the enabled-ness
 *      qpthreads_active    -- main pthread started and pthreads not (yet)
 *                             shut down
 *      qpthreads_freeze()  -- to test and freeze unset if not yet enabled
 */

#define qpthreads_enabled  ((const bool)qpthreads_enabled_flag)
#define qpthreads_active   ((const bool)qpthreads_active_flag)

#define qpthreads_main_started  ((const bool)qpthreads_main_started_flag)

extern bool qpthreads_freeze(void) ;
extern bool qpthreads_decided(void) ;

/*==============================================================================
 * Data types
 */

/*------------------------------------------------------------------------------
 * The qpt_xxx versions of the basic pthread_xxx structures
 */
typedef struct qpt_thread*  qpt_thread ;

typedef struct qpt_mutex*   qpt_mutex ;

typedef pthread_cond_t      qpt_cond_t[1] ;
typedef pthread_cond_t*     qpt_cond ;

typedef pthread_spinlock_t  qpt_spin_t[1] ;
typedef pthread_spinlock_t* qpt_spin ;

/*------------------------------------------------------------------------------
 * Arguments for the initialisation of a qpt_thread object.
 */
enum qpt_init
{
  qpt_init_main,

  qpt_init_system_scope,
  qpt_init_process_scope,
} ;

typedef enum qpt_init qpt_init_t ;

/*------------------------------------------------------------------------------
 * The struct qpt_thread_attr captures the attributes of the underlying
 * pthread.
 *
 * Some attributes are set when the pthread is created, and some may be set
 * both then and changed thereafter.  For the main (or only) pthread the
 * attributes which cannot be set after pthread creation are (implicitly)
 * unchangeable.
 *
 * The attributes we know about are:
 *
 *   * scope                   -- process/system at creation time *only*.
 *
 *     aka contention scope.  Two are specified: process and system scopes.
 *
 *     POSIX is vague in this area.  It specifies that if a process contains
 *     both process and system scope pthreads, the interaction between them is
 *     unspecified.  POSIX does not specify what the scope of the main pthread
 *     is (AFAICS) -- though if all other pthreads have the same scope the main
 *     pthread is assumed to follow suit.  A system may support one or both of
 *     process and system.
 *
 *     The system default is implementation defined.
 *
 *     FreeBSD and Linux, for example, only support system scope, which
 *     simplifies things.
 *
 *     Generally one would prefer system scope, and that is the default here.
 *
 *   * scheduling policy and parameters   -- settable at any time
 *
 *     POSIX is wonderfully vague in this area, and most things are
 *     implementation defined.
 *
 *     There are four known policies:
 *
 *       SCHED_FIFO
 *       SCHED_RR       -- these are preemptive and the same as each other,
 *                         except that in SCHED_RR a running pthread may be
 *                         preempted by another at the same priority after some
 *                         time period.
 *
 *                         The only known parameter is a priority.
 *
 *       SCHED_OTHER    -- this is non-premptive, but otherwise may or may not
 *                         be the same as one of the above.  According to
 *                         POSIX, it is provided so that applications can
 *                         "indicate that they no longer need a realtime
 *                         scheduling policy".
 *
 *                         SCHED_OTHER may have a priority value, though its
 *                         meaning os implementation defined.  It may have
 *                         other, implementation defined, parameters.
 *
 *       SCHED_SPORADIC -- this is an optional policy, not further considered
 *                         here.  However, it uses three further fields in the
 *                         scheduling params -- which confirms the need to
 *                         handle those as "partly opaque".
 *
 *     The POSIX "struct sched_param" contains only one known entry -- the
 *     priority -- except for SCHED_SPORADIC, for which three other entries are
 *     specified.  The min and max allowed priorities are given by
 *     sched_get_priority_min() and sched_get_priority_max() for the policy
 *     in question.
 *
 *     This whole area is implementation and system specific, so here we use
 *     the defaults as given.  If at some point some configuration options
 *     are implemented to override the default, then extra facilities will
 *     be required to apply those.
 *
 *   * inherit scheduling properties
 *
 *     The default for this is implementation defined.  Linux man page for
 *     pthread_attr_setschedinherit() says that PTHREAD_INHERIT_SCHED is the
 *     default.
 *
 *     The properties inherited are (by POSIX): scope, policy and params.
 *
 *     The effect on scope, policy and params of clearing the inherit option
 *     (ie setting PTHREAD_EXPLICIT_SCHED) is not defined.
 *
 *     If the inherit option is set by default, what are the scope, policy
 *     and params set to ?  Given that a single set of attributes may be used
 *     many times, presumably the attributes are *not* the attributes that will
 *     be inherited (since many threads could use the attribute set).  So,
 *     are they undefined or are they the default attributes (so that clearing
 *     the inherit option naturally takes them) ?  Or does clearing the inherit
 *     option have a side effect which sets the policy and params ?  Or does
 *     clearing the inherit option require the policy and params to be set
 *     explicitly ?  If the last, how do we establish what policy and
 *     params (particularly for SCHED_OTHER) should be adopted ?
 *
 *     Given that we feel that PTHREAD_SCOPE_SYSTEM is the appropriate scope,
 *     how do we ensure that is what is asked for, given that we have no idea
 *     how to set the policy and params ?
 *
 *     Finally, is it possible that *different* policy and params are suitable
 *     for the two contention scopes ?  Would PTHREAD_SCOPE_PROCESS be running
 *     SCHED_RR or SCHED_FIFO ?  Or some policy quite different ?
 *
 *     Would the scheduling policy and params of the main thread be a suitable
 *     default for PTHREAD_SCOPE_SYSTEM ?
 *
 *     What is more, it may or may not be necessary to have special privileges
 *     in order to change the scheduling properties.
 *
 *     Who can tell ?
 *
 *     See qpt_thread_init() for the chosen approach to inheritance and
 *     default scope/policy/param.
 *
 *   * guardsize, stackaddr & stacksize
 *
 *     These can only be set at pthread creation time.
 *
 *     We use the defaults.  No support is currently provided for changing
 *     any of these.
 *
 *   * cancel state & type   -- settable once the pthread starts running.
 *
 *     The default cancel state and type are PTHREAD_CANCEL_ENABLE and
 *     PTHREAD_CANCEL_DEFERRED.
 *
 *     At present there is no qpt_thread_cancel(), so the cancel state and
 *     type are moot.
 */

/* Scheduling attributes -- those which may be changed once a pthread is
 * running (or at any time, for the main thread).
 */
struct qpt_sched
{
  int     policy ;              /* SCHED_FIFO/_RR/_OTHER etc.           */

  struct sched_param param[1] ; /* At least "sched_priority"            */

  int     min_priority ;
  int     max_priority ;
} ;

typedef struct qpt_sched* qpt_sched ;
typedef struct qpt_sched  qpt_sched_t[1] ;

/* The attributes of a qpt_thread.
 */
struct qpt_attr
{
  /* If it is possible to get the actual pthread attributes, then when those
   * are read this flag is set.
   */
  bool      actual ;

  /* Once a thread has been detached, it can never by joined.
   *
   * The POSIX default for all threads is joinable.
   *
   * If !qpthreads_enabled, then the main (and only) thread is marked as
   * detached.
   */
  bool      detached ;

  /* cancel_disabled and cancel_async are initialised false -- as per the
   * POSIX default.
   *
   * Changed by qpt_set_cancel_state() and qpt_set_cancel_type() -- TBA.
   *
   * If !qpthreads_enabled, then these will stay false.
   *
   * These are not members of the pthread_attr_t, but are here so that the
   * complete state of a running thread is all in one place.
   */
  bool      cancel_disabled ;   /* default is false: state = enabled    */
  bool      cancel_async ;      /* default is false: type  = deferred   */

  /* Scheduling attributes.
   *
   * The scheduling contention scope is set when the qpt_thread is initialised,
   * and when actual pthread attributes are read.
   *
   * The inheritance of scheduling attributes is not supported by the qpt code,
   * but we capture the state here when actual pthread attributes are read.
   *
   * The qpt_sched_t values (policy/param and min_/max_priority) are settable
   * at any time and are settable if !qpthreads_enabled for the main and only
   * thread.  Once the main thread is started or a pthread is created, these
   * will reflect the actual scheduling parameters.
   */
  int       sched_scope ;       /* PTHREAD_SCOPE_PROCESS/_SYSTEM        */

  bool      sched_inherited ;
  bool      sched_main_start ;  /* do qpt_sched_set() at main start     */

  qpt_sched_t sched ;           /* policy/param and min_/max_priority   */

  /* For all threads these are set to the defaults when the qpt_thread is
   * initialised -- and the stack_address is set NULL.  If the actual values
   * are available, those are read when the pthread is created.
   *
   * If !qpthread_enabled these are all zero.
   *
   * It is not specified that the main pthread will have the default guard and
   * stack size -- but its hard to see why it would not.
   */
  size_t    guard_size ;
  size_t    stack_size ;
  void*     stack_addr ;
} ;

typedef struct qpt_attr  qpt_attr_t[1] ;
typedef struct qpt_attr* qpt_attr ;

/*------------------------------------------------------------------------------
 * The struct qpt_thread allows us to keep track of which pthreads have
 * started and have been joined.  It is used by the "watch-dog" to keep track
 * of the state and cpu time utilisation, per thread.
 *
 * So, we have a qpt_thread type, which is a pointer to the information we
 * keep about each qpt_thread we have not yet discarded.
 */
enum qpt_thread_state
{
  qpts_initial  = 0,    /* not on known list    */

  qpts_running,
  qpts_ended,
  qpts_joined,

  qpts_final,           /* not on known list    */
} ;

typedef enum qpt_thread_state qpt_thread_state_t ;

/* The qpt_thread stats capture when it started, when it ended, when the
 * cpu clock (if any) was last read and what its value was.
 */
typedef struct qpt_thread_stats* qpt_thread_stats ;

struct qpt_thread_stats
{
  qtime_mono_t  start ;

  qtime_mono_t  cpu_when ;      /* when last reading was taken  */
  qtime_t       cpu_used ;      /* what the last reading was    */

  qtime_mono_t  end ;
} ;

typedef struct qpt_thread_stats qpt_thread_stats_t[1] ;

/* The qpt_thread_type is a structure which allows the qpt_thread_destroy
 * level to free the "data" and/or "ret" values when destroying a qpt_thread
 * object.
 *
 * Users of the qpt_thread stuff may use this to distinguish different types
 * of pthreads.
 *
 * The "destroy" function is passed the relevant entry from the qpt_thread,
 * which (NB) may be NULL -- so the "destroy" function(s) also act as more
 * general destroy hooks.
 *
 * A NULL type is ignored, and NULL destroy functions are also ignored.
 *
 * NB: the destroy functions are most likely going to be called in some
 *     pthread *other* than the pthread itself.
 *
 *     If a qth_thread is destroyed at qpt_finish() time -- for example a
 *     detached pthread that does not destroy itself -- then the destroy
 *     functions will be called in tha last remaining pthread, with
 *     !qpthreads_active.
 */
typedef void (*qpt_destroy_func)(void* val) ;

typedef const struct qpt_thread_type* qpt_thread_type ;

struct qpt_thread_type
{
  const char*   name ;                  /* Name of the type             */

  qpt_destroy_func  data_destroy ;      /* to destroy qpth->data        */
  qpt_destroy_func  ret_destroy ;       /* to destroy qpth->ret         */
} ;

typedef const struct qpt_thread_type qpt_thread_type_ct ;
typedef struct qpt_thread_type qpt_thread_type_t ;

/* For each thread a qpt_thread structure is created.  This includes the
 * main thread, whether or not is running qpthreads_enabled.  The following
 * affect the progress of a thread and its qpt_thread structure, and will
 * work when !qpthreads_enabled, unless specified otherwise:
 *
 *   qpt_thread_init()       -- allocates and initialises the structure
 *
 *                              sets qpts_initial.
 *
 *                              must be done for the main (and possibly only)
 *                              thread, before any other threads.  May be done
 *                              any time *after* qpthreads_enabled has been
 *                              decided.
 *
 *                              NB: freezes qpthreads_enabled state.
 *
 *   qpt_main_thread_start() -- does what qpt_thread_create() and
 *                              qpt_thread_start() do, but for the main (and
 *                              possibly only) thread.
 *
 *                              this is when the main thread has reached the
 *                              point that it is deemed to be "started", which
 *                              must be:
 *
 *                                - after any daemonisation.
 *
 *                                - after qpt_thread_init(), so implicitly
 *                                  after qpthreads_enabled is decided
 *
 *                                - before any other threads are created.
 *
 *                              NB: sets qpthreads_active = qpthreads_enabled
 *
 *                                  So from this moment on mutex etc. operations
 *                                  are real actions (if qpthreads_enabled).
 *
 *   qpt_thread_create()     -- creates and sets new pthread running
 *
 *                              fills in pth_id and cpu_clock_id, and sets
 *                              the starting stats
 *
 *                              adds qpt_thread to the known threads
 *
 *                              sets qpts_running
 *
 *                              logs the start of the qpt_thread.
 *
 *                              must NOT be used if !qpthreads_enabled (!).
 *
 *   qpt_thread_start()      -- this must be the first thing that a new
 *                              pthread does.
 *
 *                              sets the thread specific qpt_self pointer to
 *                              point at the qpt_thread.
 *
 *                              does nothing at all for the main thread (and
 *                              hence nothing at all if !qpthreads_enabled).
 *
 *   qpt_thread_end()        -- fills in final stats and sets the ret value
 *
 *                              sets qpts_ended
 *
 *   qpt_thread_join()       -- sets qpts_joined (if not already joined, or
 *                              is detached).
 *
 *   qpt_thread_destroy()    -- if there is only one reference to the
 *                              qpt_thread, it is destroyed.
 *
 * Note that while access to the qpt_thread can be protected by the qpt_mutex,
 * some other mechanism is required to deal with dangling references to the
 * qpt_thread when it is freed.
 *
 * Note that all qpt_thread objects are dynamically allocated.  So we do not
 * define qpt_thread_t, so there is no temptation to allocate a static or
 * embedded qpt_thread !
 */
struct qpt_thread
{
  /* The state is set/changed under the list mutex.
   */
  qpt_thread_state_t state ;

  /* The main thread state is set very early for the main pthread, and not
   * for any other, and never changes.
   */
  bool          main ;

  /* The name is set when the structure is created, and not changed thereafter.
   */
  char          name[30] ;

  /* The structure is not destroyed unless the reference count is zero, or
   * falls to zero when the destroy flag is set.
   *
   * In qpt_thread_set_ref() increments the refcount.
   * In qpt_thread_clear_ref() decrements the refcount, and if a destroy action
   * is pending, the structure destroyed if the count reaches zero.
   */
  bool          destroy ;
  uint          refcount ;

  /* In qpt_thread_create() and qpt_main_thread_start(), the structure is
   * placed on the list of known qpt_thread.  When it is destroyed, it is
   * removed from that list.
   */
  struct dl_list_pair(qpt_thread) list ;

  /* The attributes the pthread has.
   */
  qpt_attr_t    attr ;

  pthread_attr_t* pth_attr ;

  /* The pthread and cpu_clock are set in qpt_thread_create() and
   * qpt_main_thread_start(), under the mutex.
   *
   * It is not known whether the cpu_clock can be accessed once the thread has
   * exited or been joined.  To be safe, we read the clock only if is
   * qpts_running (and when the qpt_thread starts and ends).
   *
   * If !qpthread_enabled the pth_id is invalid, but the cpu_clock_id is
   * set to CLOCK_PROCESS_CPUTIME_ID (if available).
   *
   * If required cpu clock is not available, cpu_clock_id is set to
   * CLOCK_REALTIME -- for want of anything better.
   */
  pthread_t     pth_id ;

  clockid_t     cpu_clock_id ;

  /* We implement qpt_thread_join() without using pthread_join()...
   *
   * ...which finesses the problem of two threads trying to join another at
   * the same time, and allows for the main pthread to join itself at shut-down.
   *
   * ...also, for detached pthreads we want to be able to "collect" any which
   * are still running at shut-down.
   *
   * When qpthreads_enabled we need to be able to wait until the pthread in
   * question has ended.
   */
  qpt_cond_t    end_cond ;

  bool          enjoined ;      /* true <=> 1 or more joiners waiting   */

  /* The "type" allows qpt_thread_destroy() to destroy any "data" or "ret"
   * which has not already been dealt with.
   *
   * The type may also be used to distinguish different uses of qpt_threads.
   * (So, all qpt_thread are held on the one list, but a walker of that list
   * can distinguish different types of same.)
   *
   * NB: this is set in qpt_thread_create() and qpt_main_thread_start(), and
   *     may not be changed thereafter -- nor may the contents be changed.
   */
  qpt_thread_type type ;

  /* The data pointer is set by qpt_thread_create() and not changed thereafter.
   * So, the pointer may be read and used while the qpt_thread object exists.
   *
   * The qpt_thread is passed to the new pthread as the pthread_create() "arg"
   * -- so the pthread knows its qpt_thread "id" and can access its data
   * through here.
   *
   * The data belongs to the pthread -- and may be used for thread specific
   * data.  If there are contents of the data which are shared, then those must
   * be protected by their own locking.  The pthread may free this (and set
   * to NULL) before ending, or may leave that to the pthread which "owns" the
   * qpt_thread after qpt_thread_join().
   *
   * If the qpt_thread is detached, the pthread is responsible for this and
   * MUST free it if required.
   */
  void*         data ;

  /* The ret pointer is set by qpt_thread_end() and not changed thereafter.
   *
   * Once the qpt_thread is joined, the "owner" is responsible for this.
   *
   * If the qpt_thread is detached, the pthread is responsible for this and
   * MUST free it if required.
   */
  void*         ret ;

  /* The stats are set and read under the qpt mutex.
   */
  qpt_thread_stats_t stats ;
} ;

/*------------------------------------------------------------------------------
 * The struct qpt_mutex allows "watch-dog" and other debug stuff to keep track
 * of all mutexes in the system.
 *
 * Note that all qpt_mutex objects are dynamically allocated.  So we do not
 * define qpt_mutex_t, so there is no temptation to allocate a static or
 * embedded qpt_mutex !
 */
struct qpt_mutex
{
  pthread_mutex_t pm[1] ;

  struct dl_list_pair(qpt_mutex) list ;

  char  name[30] ;

  bool  destroy ;
  uint  held ;
} ;

/*==============================================================================
 * Start up, qpthreads_enabled setting etc
 */
Private bool qpthreads_enabled_flag ;        /* DO NOT TOUCH THIS PLEASE  */
Private bool qpthreads_active_flag ;         /* DO NOT TOUCH THIS PLEASE  */
Private bool qpthreads_main_started_flag ;   /* DO NOT TOUCH THIS PLEASE  */

extern void qpt_start_up(int cputime, int thread_cputime) ;
extern const char* qpt_set_new_thread_options(const char* opts) ;
extern void qpt_second_stage(bool want_enabled) ;
extern void qpt_finish(void) ;

/*==============================================================================
 * Thread Creation etc -- see qpthreads.c for further discussion.
 */
extern qpt_thread qpt_thread_init(qpt_init_t init, const char* name) ;
extern bool qpt_thread_detach(qpt_thread qpth) ;
extern qpt_thread_state_t qpt_thread_get_attr(qpt_thread qpth, qpt_attr attr) ;
extern bool qpt_sched_set_policy(qpt_sched sched, int policy) ;
extern qpt_sched qpt_thread_get_sched(qpt_thread qpth, qpt_sched sched) ;
extern bool qpt_thread_set_sched(qpt_thread qpth, qpt_sched sched) ;
extern void qpt_main_thread_start(qpt_thread qpth,
                                             qpt_thread_type type, void* data) ;
extern void qpt_thread_create(qpt_thread qpth,
                                             qpt_thread_type type, void* data,
                                                   void* (*start)(qpt_thread)) ;
extern void* qpt_thread_start(qpt_thread qpth) ;
extern void* qpt_thread_end(void* ret) ;
extern qpt_thread_state_t qpt_thread_join(qpt_thread qpth) ;
extern qpt_thread qpt_thread_set_ref(qpt_thread qpth) ;
extern qpt_thread qpt_thread_clear_ref(qpt_thread qpth) ;
extern qpt_thread qpt_thread_destroy(qpt_thread qpth) ;
extern void qpt_thread_collect(void) ;

extern qpt_thread qpt_thread_walk(qpt_thread qpth) ;
extern qpt_thread_state_t qpt_thread_get_stats(qpt_thread qpth,
                                                       qpt_thread_stats stats) ;

/*==============================================================================
 * Signal Handling.
 *
 * If !qpthreads_enabled these map to process level equivalents.
 */
extern void qpt_thread_sigmask(int how, const sigset_t* set, sigset_t* oset) ;
extern void qpt_thread_raise(qpt_thread qpth, int signum) ;

/*==============================================================================
 * Mutex handling.
 *
 * Quagga's default mutex type is:
 *
 *   * PTHREAD_MUTEX_ERRORCHECK if QPTHREADS_DEBUG
 *   * QPT_MUTEX_TYPE_DEFAULT
 *
 * QPT_MUTEX_TYPE_DEFAULT may be set elsewhere.  If it is not set then it is
 * set here to be PTHREAD_MUTEX_NORMAL.
 *
 * NB: on the face of it PTHREAD_MUTEX_NORMAL should be the fastest.  It is
 *     possible that PTHREAD_MUTEX_DEFAULT may have system specific semantics
 *     that make it faster than the standard _NORMAL.  It is also possible that
 *     a given system may elect to provide a safer mutex than the _NORMAL by
 *     default.
 *
 *     If _DEFAULT is faster than _NORMAL, then QPT_MUTEX_TYPE_DEFAULT may be
 *     used to override this choice.
 *
 * NB: if NOT qpthreads_active, all mutex actions are EMPTY.  This allows
 *     code to be made thread-safe for when pthreads is running, but to work
 *     perfectly well without pthreads and once pthreads have been brought to
 *     a close.
 *
 * NB: do not (currently) support pthread_mutex_timedlock().
 */

enum qpt_mutex_options
{
  qpt_mutex_quagga      = 0,            /* Quagga's default     */
  qpt_mutex_normal,
  qpt_mutex_recursive,
  qpt_mutex_errorcheck,
  qpt_mutex_default,                    /* system default       */
} ;

typedef enum qpt_mutex_options qpt_mutex_options_t ;

#ifndef QPT_MUTEX_TYPE_DEFAULT
# define QPT_MUTEX_TYPE_DEFAULT  PTHREAD_MUTEX_NORMAL
#endif

enum
{
#if QPTHREADS_DEBUG
  QPT_MUTEX_TYPE  = PTHREAD_MUTEX_ERRORCHECK
#else
  QPT_MUTEX_TYPE  = QPT_MUTEX_TYPE_DEFAULT
#endif
} ;

extern qpt_mutex qpt_mutex_new(qpt_mutex_options_t opts, const char* name) ;
extern qpt_mutex qpt_mutex_destroy(qpt_mutex mx) ;
extern qpt_mutex qpt_mutex_step_next(qpt_mutex mx) ;
extern void qpt_mutex_step_last(qpt_mutex mx) ;
Inline void qpt_mutex_lock(qpt_mutex mx) ;
Inline bool qpt_mutex_trylock(qpt_mutex mx) ;
extern bool qpt_mutex_timedlock(qpt_mutex mx, qtime_t timeout) ;
Inline void qpt_mutex_unlock(qpt_mutex mx) ;

/*==============================================================================
 * Condition Variable handling
 *
 * Quagga's clock for condition variables is QPT_COND_CLOCK_ID, which
 * may be set elsewhere.  If it is not set then it is set here to be:
 *
 *   * CLOCK_MONOTONIC if available
 *   * CLOCK_REALTIME otherwise  -- this is the standard default.
 *
 * QPT_COND_CLOCK_MONOTONIC is set if CLOCK_MONOTONIC is used (and must be set
 * if QPT_COND_CLOCK_ID is set elsewhere to something that is monotonic).
 *
 * NB: the time-out time passed to qpt_cond_timedwait() is a qtime_mono_t
 *     time (so based on qtime's monotonic time, which is CLOCK_MONOTONIC if
 *     that is available.
 *
 *     Otherwise, there is a conversion step from qtime_mono_t to whatever the
 *     timebase for the condition variable is.
 *
 * NB: static initialisation of condition variables is not supported, to avoid
 *     confusion between the standard default and Quagga's default.

 * NB: if NOT qpthreads_active, all condition actions are EMPTY.  This allows
 *     code to be made thread-safe for when pthreads is running, but to work
 *     perfectly well without pthreads and once pthreads have been brought to
 *     a close.
 */

#ifndef QPT_COND_CLOCK_ID
# ifdef HAVE_CLOCK_MONOTONIC
#  define QPT_COND_CLOCK_ID  CLOCK_MONOTONIC
#  define QPT_COND_CLOCK_MONOTONIC  1
# else
#  define QPT_COND_CLOCK_ID  CLOCK_REALTIME
#  undef  QPT_COND_CLOCK_MONOTONIC
# endif
#endif

enum qpt_cond_options
{
  qpt_cond_quagga      = 0x0000,  /* Quagga's default   */
} ;

extern qpt_cond qpt_cond_init_new(qpt_cond cv, enum qpt_cond_options opts) ;
extern qpt_cond qpt_cond_destroy(qpt_cond cv, free_keep_b free_cond) ;
Inline void qpt_cond_wait(qpt_cond cv, qpt_mutex mx) ;
extern bool qpt_cond_timedwait(qpt_cond cv, qpt_mutex mx,
                                                    qtime_mono_t timeout_time) ;
Inline void qpt_cond_signal(qpt_cond cv) ;
Inline void qpt_cond_broadcast(qpt_cond cv) ;

/*==============================================================================
 * Spinlock handling
 *
 * Spinlocks are pretty trivial -- requiring only to be initialised, locked,
 * unlocked and, finally, destroyed.
 *
 * NB: recursive spinlocks are not supported !
 *
 * NB: if NOT qpthreads_active, locking and unlocking always succeed.  This
 *     allows code to be made thread-safe for when pthreads is running, but to
 *     work perfectly well without pthreads.
 */
extern void qpt_spin_init(qpt_spin slk) ;
extern void qpt_spin_destroy(qpt_spin slk) ;
Inline void qpt_spin_lock(qpt_spin slk) ;
Inline void qpt_spin_unlock(qpt_spin slk) ;

/*==============================================================================
 * Mutex inline functions
 */

Private void qpt_mutex_lock_failed(qpt_mutex mx, int err) ;
Private void qpt_mutex_trylock_failed(qpt_mutex mx, int err) ;
Private void qpt_mutex_unlock_failed(qpt_mutex mx, int err) ;

/*------------------------------------------------------------------------------
 * Lock given mutex  -- or do nothing if !qpthreads_active.
 *
 * Checks that the return value is valid -- zabort_errno if it isn't.
 */

Inline void
qpt_mutex_lock(qpt_mutex mx)
{
  if (qpthreads_active)
    {
      int err = pthread_mutex_lock(mx->pm) ;
      if (err != 0)
        qpt_mutex_lock_failed(mx, err) ;
    } ;
} ;

/*------------------------------------------------------------------------------
 * Try to lock given mutex  -- every time a winner if !qpthreads_active.
 *
 * Returns: lock succeeded (false <=> unable to lock).
 *
 * Checks that the return value is valid -- zabort_errno if it isn't.
 */
Inline bool
qpt_mutex_trylock(qpt_mutex mx)
{
  if (qpthreads_active)
    {
      int err = pthread_mutex_trylock(mx->pm) ;
      if (err != 0)
        {
          if (err != EBUSY)
            qpt_mutex_trylock_failed(mx, err) ;

          return false ;        /* unable to lock               */
        } ;
    } ;

  return true ;
} ;

/*------------------------------------------------------------------------------
 * Unlock given mutex  -- or do nothing if !qpthreads_active.
 *
 * Checks that the return value is valid -- zabort_err if it isn't.
 */
Inline void
qpt_mutex_unlock(qpt_mutex mx)
{
  if (qpthreads_active)
    {
      int err = pthread_mutex_unlock(mx->pm) ;
      if (err != 0)
        qpt_mutex_unlock_failed(mx, err) ;
    } ;
} ;

/*==============================================================================
 * Condition variable inline functions
 */

/*------------------------------------------------------------------------------
 * Wait for given condition variable  -- do nothing if !qpthreads_active
 *
 * Checks that the return value is valid -- zabort_err if it isn't.
 */
Inline void
qpt_cond_wait(qpt_cond cv, qpt_mutex mx)
{
  if (qpthreads_active)
    {
      int err = pthread_cond_wait(cv, mx->pm) ;
      if (err != 0)
        zabort_err("pthread_cond_wait failed", err) ;
    } ;
} ;

/*------------------------------------------------------------------------------
 * Signal given condition   -- do nothing if !qpthreads_active
 *
 * Checks that the return value is valid -- zabort_err if it isn't.
 */
Inline void
qpt_cond_signal(qpt_cond cv)
{
  if (qpthreads_active)
    {
      int err = pthread_cond_signal(cv) ;
      if (err != 0)
        zabort_err("pthread_cond_signal failed", err) ;
    } ;
} ;

/*------------------------------------------------------------------------------
 * Broadcast given condition   -- do nothing if !qpthreads_active
 *
 * Checks that the return value is valid -- zabort_err if it isn't.
 */
Inline void
qpt_cond_broadcast(qpt_cond cv)
{
  if (qpthreads_active)
    {
      int err = pthread_cond_broadcast(cv) ;
      if (err != 0)
        zabort_err("pthread_cond_broadcast failed", err) ;
    } ;
} ;

/*==============================================================================
 * Spinlock inline functions
 */

/*------------------------------------------------------------------------------
 * Lock spinlock  -- do nothing if !qpthreads_active
 *
 * Checks that the return value is valid -- zabort_errno if it isn't.
 */
Inline void
qpt_spin_lock(qpt_spin slk)
{
  if (qpthreads_active)
    {
      int err = pthread_spin_lock(slk) ;
      if (err != 0)
        zabort_err("pthread_spin_lock failed", err) ;
    } ;
} ;

/*------------------------------------------------------------------------------
 * Unlock spinlock  -- do nothing if !qpthreads_active
 *
 * Checks that the return value is valid -- zabort_errno if it isn't.
 */
Inline void
qpt_spin_unlock(qpt_spin slk)
{
  if (qpthreads_active)
    {
      int err = pthread_spin_unlock(slk) ;
      if (err != 0)
        zabort_err("pthread_spin_unlock failed", err) ;
    } ;
} ;

/*==============================================================================
 * Thread Specific Data Handling.
 *
 * Note that if !qpthreads_enabled, this maintains the data value, without
 * using any pthread primitives.
 *
 * Note also that this does not support the pthread value destructor -- because
 * cannot support that for non qpthreads_enabled (straightforwardly, anyway).
 */
union qpt_own_data
{
  pthread_key_t key ;           /* if qpthreads_enabled         */

  struct
    {
      void*     value ;
      void      (*destructor)(void*) ;
    } proxy ;                   /* otherwise                    */
} ;

typedef union qpt_own_data  qpt_own_data_t[1] ;
typedef union qpt_own_data* qpt_own_data ;

extern void qpt_own_data_create(qpt_own_data data, void (*destructor)(void*)) ;
extern void qpt_own_data_delete(qpt_own_data data) ;

/*------------------------------------------------------------------------------
 * Set thread specific data value -- value is void*
 */
Inline void
qpt_own_data_set_value(qpt_own_data data, void* value)
{
  if (qpthreads_enabled)
    {
      int err = pthread_setspecific(data->key, value) ;
      if (err != 0)
        zabort_err("pthread_setspecific failed", err) ;
    }
  else
    data->proxy.value = value ;
} ;

/*------------------------------------------------------------------------------
 * Get thread specific data value -- value is void*
 */
Inline void*
qpt_own_data_get_value(qpt_own_data data)
{
  if (qpthreads_enabled)
    return pthread_getspecific(data->key) ;
  else
    return data->proxy.value ;
} ;

/*==============================================================================
 * Thread self knowledge -- even when !qpthreads_enabled there is one
 * qpt_thread -- the main thread.
 *
 * The thread-specific data item qpt_self is set by qpt_thread_start() and
 * by qpt_main_thread_start().
 */

qpt_own_data_t qpt_self ;

/*------------------------------------------------------------------------------
 * Get the current pthread's qpt_thread object.
 *
 * If is !qpthreads_enabled, this returns the qpt_thread for the main thread.
 */
Inline qpt_thread
qpt_thread_self(void)
{
  return qpt_own_data_get_value(qpt_self) ;
} ;

/*------------------------------------------------------------------------------
 * Get the current pthread's qpt_thread "data" value.
 *
 * If is !qpthreads_enabled, this returns the "data" for the main thread.
 */
Inline void*
qpt_thread_self_data(void)
{
  return ((qpt_thread)qpt_own_data_get_value(qpt_self))->data ;
} ;

#endif /* _ZEBRA_QPTHREADS_H */