openpmix-src 0.1.0-rc.1

Vendored build of OpenPMIx, developed for use by the Lamellar runtime.
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
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
 * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
 *                         University Research and Technology
 *                         Corporation.  All rights reserved.
 * Copyright (c) 2004-2005 The University of Tennessee and The University
 *                         of Tennessee Research Foundation.  All rights
 *                         reserved.
 * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
 *                         University of Stuttgart.  All rights reserved.
 * Copyright (c) 2004-2005 The Regents of the University of California.
 *                         All rights reserved.
 * Copyright (c) 2014-2020 Intel, Inc.  All rights reserved.
 * Copyright (c) 2019      Research Organization for Information Science
 *                         and Technology (RIST).  All rights reserved.
 * Copyright (c) 2019      Mellanox Technologies, Inc.
 *                         All rights reserved.
 * Copyright (c) 2021-2025 Nanook Consulting  All rights reserved.
 * Copyright (c) 2023      Triad National Security, LLC. All rights reserved.
 * $COPYRIGHT$
 *
 * Additional copyrights may follow
 *
 * $HEADER$
 */

#ifndef PMIX_GLOBALS_H
#define PMIX_GLOBALS_H

#include "src/include/pmix_config.h"
#include "src/include/pmix_types.h"

#include <unistd.h>
#ifdef HAVE_SYS_TYPES_H
#    include <sys/types.h>
#endif
#include <event.h>

#include "pmix.h"
#include "pmix_common.h"
#include "pmix_tool.h"

#include "src/class/pmix_hash_table.h"
#include "src/class/pmix_hotel.h"
#include "src/class/pmix_list.h"
#include "src/event/pmix_event.h"
#include "src/runtime/pmix_init_util.h"
#include "src/threads/pmix_threads.h"

#include "src/mca/bfrops/bfrops.h"
#include "src/mca/gds/gds.h"
#include "src/mca/psec/psec.h"
#include "src/mca/ptl/ptl.h"

#include "src/util/pmix_name_fns.h"

BEGIN_C_DECLS

/* some limits */
#define PMIX_MAX_CRED_SIZE    131072 // set max at 128kbytes
#define PMIX_MAX_ERR_CONSTANT INT_MIN

/* internal-only attributes */
#define PMIX_BFROPS_MODULE \
    "pmix.bfrops.mod" // (char*) name of bfrops plugin in-use by a given nspace
#define PMIX_PNET_SETUP_APP \
    "pmix.pnet.setapp" // (pmix_byte_object_t) blob containing info to be given to
                       //      pnet framework on remote nodes

// define some bit handling macros
#define PMIX_SET_BIT(a, f) \
    (a) |= (f)

#define PMIX_UNSET_BIT(a, f) \
    (a) &= ~(f)

#define PMIX_CHECK_BIT_IS_SET(a, f) \
    ((a) & (f))

#define PMIX_CHECK_BIT_NOT_SET(a, f) \
    !PMIX_CHECK_BIT_IS_SET(a, f)

#define PMIX_INFO_OP_COMPLETE       0x80000000
#define PMIX_INFO_OP_COMPLETED(m) \
      PMIX_SET_BIT((m)->flags, PMIX_INFO_OP_COMPLETE)
#define PMIX_INFO_OP_IS_COMPLETE(m) \
      PMIX_CHECK_BIT_IS_SET((m)->flags, PMIX_INFO_OP_COMPLETE)


/* define an internal-only object for creating
 * lists of names */
typedef struct {
    pmix_list_item_t super;
    pmix_name_t *pname;
} pmix_namelist_t;
PMIX_CLASS_DECLARATION(pmix_namelist_t);

/* define a struct for holding entries in the
 * dictionary of attributes */
typedef struct {
    uint32_t index;
    char *name;
    char *string;
    pmix_data_type_t type;
    char **description;
} pmix_regattr_input_t;
#define PMIX_REGATTR_INPUT_NEW(a, i, n, s, t, d)                            \
do {                                                                        \
    (a) = (pmix_regattr_input_t*)pmix_malloc(sizeof(pmix_regattr_input_t)); \
    if (NULL != (a)) {                                                      \
        memset((a), 0, sizeof(pmix_regattr_input_t));                       \
        (a)->index = (i);                                                   \
        if (NULL != (n)) {                                                    \
            (a)->name = strdup((n));                                       \
        }                                                                   \
        if (NULL != (s)) {                                                    \
            (a)->string = strdup((s));                                        \
        }                                                                   \
        (a)->type = (t);                                                    \
        if (NULL != (d)) {                                                    \
            (a)->description = PMIx_Argv_copy((d));                           \
        }                                                                   \
    }                                                                       \
} while(0)
#define PMIX_REGATTR_INPUT_FREE(a)      \
do {                                    \
    if (NULL != (a)) {                  \
        if (NULL != (a)->name) {        \
            free((a)->name);            \
        }                               \
        if (NULL != (a)->string)        \
            free((a)->string);          \
        }                               \
        if (NULL != (a)->description) { \
            free((a)->description);     \
        }                               \
    }                                   \
} while(0)

/* define a struct for holding entries in the
 * dictionary of event strings */
typedef struct {
    uint32_t index;
    char *name;
    int32_t code;
} pmix_event_string_t;

/* define a struct for storing data in memory */
typedef struct {
    uint32_t index;
    pmix_value_t *value;
} pmix_qual_t;
#define PMIX_QUAL_NEW(d, k)                                 \
do {                                                        \
    (d) = (pmix_qual_t*)pmix_malloc(sizeof(pmix_qual_t));   \
    if (NULL != (d)) {                                      \
        (d)->index = k;                                     \
        (d)->value = NULL;                                  \
    }                                                       \
} while(0)
#define PMIX_QUAL_RELEASE(d)            \
do {                                    \
    if (NULL != (d)->value) {           \
        PMIX_VALUE_RELEASE((d)->value); \
    }                                   \
} while(0)

typedef struct {
    uint32_t index;
    uint32_t qualindex;
    pmix_value_t *value;
} pmix_dstor_t;

PMIX_EXPORT pmix_dstor_t *
pmix_dstor_new_tma(
    uint32_t index,
    pmix_tma_t *tma
);

PMIX_EXPORT void
pmix_dstor_release_tma(
    pmix_dstor_t *d,
    pmix_tma_t *tma
);

#define PMIX_DSTOR_NEW(d, k)                                \
do {                                                        \
    (d) = pmix_dstor_new_tma((k), NULL);                    \
} while(0)

#define PMIX_DSTOR_RELEASE(d)           \
do {                                    \
    pmix_dstor_release_tma((d), NULL);  \
} while(0)

/* define a struct for passing topology objects */
typedef struct {
    pmix_object_t super;
    char *source;
    void *object;
} pmix_topo_obj_t;
PMIX_CLASS_DECLARATION(pmix_topo_obj_t);

/* define a command type for communicating to the
 * pmix server */
typedef uint8_t pmix_cmd_t;

/* define some commands */
#define PMIX_REQ_CMD                      0
#define PMIX_ABORT_CMD                    1
#define PMIX_COMMIT_CMD                   2
#define PMIX_FENCENB_CMD                  3
#define PMIX_GETNB_CMD                    4
#define PMIX_FINALIZE_CMD                 5
#define PMIX_PUBLISHNB_CMD                6
#define PMIX_LOOKUPNB_CMD                 7
#define PMIX_UNPUBLISHNB_CMD              8
#define PMIX_SPAWNNB_CMD                  9
#define PMIX_CONNECTNB_CMD                10
#define PMIX_DISCONNECTNB_CMD             11
#define PMIX_NOTIFY_CMD                   12
#define PMIX_REGEVENTS_CMD                13
#define PMIX_DEREGEVENTS_CMD              14
#define PMIX_QUERY_CMD                    15
#define PMIX_LOG_CMD                      16
#define PMIX_ALLOC_CMD                    17
#define PMIX_JOB_CONTROL_CMD              18
#define PMIX_MONITOR_CMD                  19
#define PMIX_GET_CREDENTIAL_CMD           20
#define PMIX_VALIDATE_CRED_CMD            21
#define PMIX_IOF_PULL_CMD                 22
#define PMIX_IOF_PUSH_CMD                 23
#define PMIX_GROUP_CONSTRUCT_CMD          24
#define PMIX_GROUP_JOIN_CMD               25
#define PMIX_GROUP_INVITE_CMD             26
#define PMIX_GROUP_LEAVE_CMD              27
#define PMIX_GROUP_DESTRUCT_CMD           28
#define PMIX_IOF_DEREG_CMD                29
#define PMIX_FABRIC_REGISTER_CMD          30
#define PMIX_FABRIC_UPDATE_CMD            31
#define PMIX_COMPUTE_DEVICE_DISTANCES_CMD 32
#define PMIX_REFRESH_CACHE                33
#define PMIX_RESOLVE_PEERS_CMD            37
#define PMIX_RESOLVE_NODE_CMD             38


/* provide a "pretty-print" function for cmds */
const char *pmix_command_string(pmix_cmd_t cmd);

/* provide a hook to init tool data */
PMIX_EXPORT extern pmix_status_t pmix_tool_init_info(void);

/* define a set of flags to direct collection
 * of data during operations */
typedef enum {
    PMIX_COLLECT_INVALID = -1,
    PMIX_COLLECT_NO,
    PMIX_COLLECT_YES,
    PMIX_COLLECT_MAX
} pmix_collect_t;

/****    PEER STRUCTURES    ****/

/* clients can only talk to their server, and servers are
 * assumed to all have the same personality. Thus, each
 * process only needs to track a single set of personality
 * modules. All interactions between a client and its local
 * server, or between servers, are done thru these modules */
typedef struct pmix_personality_t {
    pmix_bfrop_buffer_type_t type;
    pmix_bfrops_module_t *bfrops;
    pmix_psec_module_t *psec;
    pmix_gds_base_module_t *gds;
} pmix_personality_t;

/* define a set of structs for tracking post-termination cleanup */
typedef struct pmix_epilog_t {
    uid_t uid;
    gid_t gid;
    pmix_list_t cleanup_dirs;
    pmix_list_t cleanup_files;
    pmix_list_t ignores;
} pmix_epilog_t;

typedef struct {
    pmix_list_item_t super;
    char *path;
} pmix_cleanup_file_t;
PMIX_CLASS_DECLARATION(pmix_cleanup_file_t);

typedef struct {
    pmix_list_item_t super;
    char *path;
    bool recurse;
    bool leave_topdir;
} pmix_cleanup_dir_t;
PMIX_CLASS_DECLARATION(pmix_cleanup_dir_t);

/* define a struct to hold booleans controlling the
 * format/contents of the output */
typedef struct {
    bool set;
    bool xml;
    bool timestamp;
    bool tag;
    bool tag_detailed;
    bool tag_fullname;
    bool rank;
    char *file;
    char *directory;
    bool nocopy;
    bool merge;
    bool local_output;
    bool local_output_given;
    bool pattern;
    bool raw;
} pmix_iof_flags_t;

#define PMIX_IOF_FLAGS_STATIC_INIT  \
{                                   \
    .set = false,                   \
    .xml = false,                   \
    .timestamp = false,             \
    .tag = false,                   \
    .tag_detailed = false,          \
    .tag_fullname = false,          \
    .rank = false,                  \
    .file = NULL,                   \
    .directory = NULL,              \
    .nocopy = false,                \
    .merge = false,                 \
    .local_output = false,          \
    .local_output_given = false,    \
    .pattern = false,               \
    .raw = false                    \
}

/* objects used by servers for tracking active nspaces */
typedef struct {
    pmix_list_item_t super;
    char *nspace;
    struct {
        uint8_t major;
        uint8_t minor;
        uint8_t release;
    } version;
    pmix_rank_t nprocs; // num procs in this nspace
    size_t nlocalprocs;
    size_t num_waiting;    // number of local procs waiting for debugger attach/release
    bool all_registered;   // all local ranks have been defined
    bool version_stored;   // the version string used by this nspace has been stored
    pmix_buffer_t *jobbkt; // packed version of jobinfo
    size_t ndelivered;     // count of #local clients that have received the jobinfo
    size_t nfinalized;     // count of #local clients that have finalized
    pmix_list_t ranks;     // list of pmix_rank_info_t for connection support of my clients
    /* all members of an nspace are required to have the
     * same personality, but it can differ between nspaces.
     * Since servers may support clients from multiple nspaces,
     * track their respective compatibility modules here */
    pmix_personality_t compat;
    pmix_epilog_t epilog;   // things to do upon termination of all local clients
                            // from this nspace
    pmix_list_t setup_data; // list of pmix_kval_t containing info structs having blobs
                            // for setting up the local node for this nspace/application
    pmix_iof_flags_t iof_flags;   // output formatting flags
    pmix_list_t sinks;   // IOF write events for output to files or directories
} pmix_namespace_t;
PMIX_CLASS_DECLARATION(pmix_namespace_t);

/* define a caddy for quickly creating a list of pmix_namespace_t
 * objects for local, dedicated purposes */
typedef struct {
    pmix_list_item_t super;
    pmix_namespace_t *ns;
} pmix_nspace_caddy_t;
PMIX_CLASS_DECLARATION(pmix_nspace_caddy_t);

typedef struct {
    pmix_list_item_t super;
    pmix_namespace_t *ns;
    pmix_list_t envars;
} pmix_nspace_env_cache_t;
PMIX_CLASS_DECLARATION(pmix_nspace_env_cache_t);

typedef struct {
    pmix_list_item_t super;
    pmix_envar_t envar;
} pmix_envar_list_item_t;
PMIX_CLASS_DECLARATION(pmix_envar_list_item_t);


typedef struct pmix_rank_info_t {
    pmix_list_item_t super;
    int peerid; // peer object index into the local clients array on the server
    pmix_name_t pname;
    pid_t pid;
    uid_t realuid;
    uid_t uid;
    gid_t realgid;
    gid_t gid;
    bool modex_recvd;
    int proc_cnt;        // #clones of this rank we know about
    void *server_object; // pointer to rank-specific object provided by server
} pmix_rank_info_t;
PMIX_CLASS_DECLARATION(pmix_rank_info_t);

/* define a very simple caddy for dealing with pmix_info_t
 * and pmix_query_t objects when transferring portions of arrays */
typedef struct {
    pmix_list_item_t super;
    pmix_info_t *info;
    size_t ninfo;
} pmix_info_caddy_t;
PMIX_CLASS_DECLARATION(pmix_info_caddy_t);

typedef struct {
    pmix_list_item_t super;
    pmix_info_t info;
} pmix_infolist_t;
PMIX_CLASS_DECLARATION(pmix_infolist_t);

typedef struct {
    pmix_list_item_t super;
    pmix_query_t query;
} pmix_querylist_t;
PMIX_CLASS_DECLARATION(pmix_querylist_t);

typedef struct {
    pmix_list_item_t super;
    pmix_proc_t proc;
} pmix_proclist_t;
PMIX_CLASS_DECLARATION(pmix_proclist_t);

/* object for tracking peers - each peer can have multiple
 * connections. This can occur if the initial app executes
 * a fork/exec, and the child initiates its own connection
 * back to the PMIx server. Thus, the trackers should be "indexed"
 * by the socket, not the process nspace/rank */
typedef struct pmix_peer_t {
    pmix_object_t super;
    pmix_namespace_t *nptr; // point to the nspace object for this process
    pmix_rank_info_t *info;
    pmix_proc_type_t proc_type;
    pmix_listener_protocol_t protocol;
    int proc_cnt;
    int index; // index into the local clients array on the server
    int sd;
    bool finalized;          // peer has called finalize
    pmix_event_t send_event; /**< registration with event thread for send events */
    bool send_ev_active;
    pmix_event_t recv_event; /**< registration with event thread for recv events */
    bool recv_ev_active;
    pmix_list_t send_queue;    /**< list of messages to send */
    pmix_ptl_send_t *send_msg; /**< current send in progress */
    pmix_ptl_recv_t *recv_msg; /**< current recv in progress */
    int commit_cnt;
    pmix_epilog_t epilog; /**< things to be performed upon
                               termination of this peer */
} pmix_peer_t;
PMIX_CLASS_DECLARATION(pmix_peer_t);

/* tracker for IOF requests */
typedef struct {
    pmix_object_t super;
    pmix_event_t ev;
    pmix_peer_t *requestor;
    size_t local_id;
    size_t remote_id;
    pmix_proc_t *procs;
    size_t nprocs;
    pmix_iof_flags_t flags;
    pmix_iof_channel_t channels;
    pmix_iof_cbfunc_t cbfunc;
    pmix_hdlr_reg_cbfunc_t regcbfunc;
    void *cbdata;
} pmix_iof_req_t;
PMIX_CLASS_DECLARATION(pmix_iof_req_t);

/* caddy for query requests */
typedef struct {
    pmix_object_t super;
    pmix_event_t ev;
    pmix_lock_t lock;
    bool host_called;
    pmix_status_t status;
    pmix_query_t *queries;
    size_t nqueries;
    pmix_proc_t *targets;
    size_t ntargets;
    pmix_info_t *info;
    pmix_info_t *dirs;
    size_t ninfo;
    size_t ndirs;
    pmix_list_t results;
    size_t nreplies;
    size_t nrequests;
    pmix_byte_object_t bo;
    pmix_info_cbfunc_t cbfunc;
    pmix_value_cbfunc_t valcbfunc;
    pmix_release_cbfunc_t relcbfunc;
    pmix_credential_cbfunc_t credcbfunc;
    pmix_validation_cbfunc_t validcbfunc;
    void *cbdata;
} pmix_query_caddy_t;
PMIX_CLASS_DECLARATION(pmix_query_caddy_t);

typedef struct {
    pmix_list_item_t super;
    char *grpid;
    pmix_proc_t *members;
    size_t nmbrs;
} pmix_group_t;
PMIX_CLASS_DECLARATION(pmix_group_t);

typedef struct {
    pmix_list_item_t super;
    pmix_proc_t proc;
    pmix_byte_object_t blob;  // packed blob of info provided by this proc
} pmix_grpinfo_t;
PMIX_CLASS_DECLARATION(pmix_grpinfo_t);

/* define a tracker for collective operations
 * - instanced in pmix_server_ops.c */
typedef struct {
    pmix_list_item_t super;
    pmix_event_t ev;
    bool event_active;
    bool host_called; // tracker has been passed up to host
    bool local;       // operation is strictly local
    char *id;         // string identifier for the collective
    pmix_cmd_t type;
    pmix_proc_t pname;
    bool hybrid;            // true if participating procs are from more than one nspace
    pmix_proc_t *pcs;       // copy of the original array of participants
    size_t npcs;            // number of procs in the array
    pmix_list_t nslist;     // unique nspace list of participants
    pmix_lock_t lock;       // flag for waiting for completion
    bool def_complete;      // all local procs have been registered and the trk definition is complete
    pmix_list_t local_cbs;  // list of pmix_server_caddy_t for sending result to the local participants
                            //    Note: there may be multiple entries for a given proc if that proc
                            //    has fork/exec'd clones that are also participating
    uint32_t nlocal;        // number of local participants
    uint32_t local_cnt;     // number of local participants who have contributed
    pmix_info_t *info;      // array of info structs
    size_t ninfo;           // number of info structs in array
    pmix_list_t grpinfo;    // list of group info to be distributed
    int grpop;              // the group operation being tracked
    pmix_collect_t collect_type; // whether or not data is to be returned at completion
    pmix_modex_cbfunc_t modexcbfunc;
    pmix_op_cbfunc_t op_cbfunc;
    void *cbdata;
} pmix_server_trkr_t;
PMIX_CLASS_DECLARATION(pmix_server_trkr_t);

/* define an object for moving a send
 * request into the server's event base and
 * dealing with some request timeouts
 * - instanced in pmix_server_ops.c */
typedef struct {
    pmix_list_item_t super;
    pmix_event_t ev;
    bool event_active;
    pmix_server_trkr_t *trk;
    pmix_ptl_hdr_t hdr;
    pmix_peer_t *peer;
    pmix_info_t *info;
    size_t ninfo;
    pmix_query_t *query;
} pmix_server_caddy_t;
PMIX_CLASS_DECLARATION(pmix_server_caddy_t);

/****    THREAD-RELATED    ****/
/* define a caddy for thread-shifting operations */
typedef struct {
    pmix_object_t super;
    pmix_event_t ev;
    pmix_lock_t lock;
    pmix_status_t status;
    pmix_status_t *codes;
    size_t ncodes;
    uint32_t sessionid;
    pmix_name_t pname;
    pmix_proc_t *proc;
    pmix_peer_t *peer;
    const char *data;
    size_t ndata;
    const char *key;
    pmix_info_t *info;
    size_t ninfo;
    pmix_info_t *directives;
    size_t ndirs;
    pmix_notification_fn_t evhdlr;
    pmix_iof_req_t *iofreq;
    pmix_kval_t *kv;
    pmix_value_t *vptr;
    pmix_server_caddy_t *cd;
    pmix_server_trkr_t *tracker;
    bool enviro;
    union {
        pmix_release_cbfunc_t relfn;
        pmix_hdlr_reg_cbfunc_t hdlrregcbfn;
        pmix_op_cbfunc_t opcbfn;
        pmix_modex_cbfunc_t modexcbfunc;
        pmix_info_cbfunc_t infocbfunc;
    } cbfunc;
    void *cbdata;
    size_t ref;
} pmix_shift_caddy_t;
PMIX_CLASS_DECLARATION(pmix_shift_caddy_t);

typedef struct {
    pmix_object_t super;
    pmix_proc_t p;
    bool pntrval;
    bool stval;
    bool optional;
    bool immediate;
    bool add_immediate;
    bool refresh_cache;
    pmix_scope_t scope;
    bool sessioninfo;
    bool sessiondirective;
    uint32_t sessionid;
    bool nodeinfo;
    bool nodedirective;
    char *hostname;
    uint32_t nodeid;
    bool appinfo;
    bool appdirective;
    uint32_t appnum;
} pmix_get_logic_t;
PMIX_CLASS_DECLARATION(pmix_get_logic_t);

/* struct for tracking ops */
typedef struct {
    pmix_list_item_t super;
    pmix_event_t ev;
    pmix_lock_t lock;
    bool checked;
    int status;
    pmix_status_t pstatus;
    pmix_scope_t scope;
    pmix_buffer_t data;
    union {
        pmix_ptl_cbfunc_t ptlfn;
        pmix_op_cbfunc_t opfn;
        pmix_value_cbfunc_t valuefn;
        pmix_lookup_cbfunc_t lookupfn;
        pmix_spawn_cbfunc_t spawnfn;
        pmix_hdlr_reg_cbfunc_t hdlrregfn;
        pmix_info_cbfunc_t infofn;
        pmix_device_dist_cbfunc_t distfn;
    } cbfunc;
    size_t errhandler_ref;
    void *cbdata;
    pmix_name_t pname;
    char *key;
    pmix_value_t *value;
    pmix_proc_t *proc;
    pmix_proc_t *procs;
    size_t nprocs;
    pmix_info_t *info;
    size_t ninfo;
    pmix_device_distance_t *dist;
    bool infocopy;
    size_t nvals;
    pmix_list_t kvs;
    bool copy;
    pmix_get_logic_t *lg;
    bool timer_running;
    pmix_fabric_t *fabric;
    pmix_topology_t *topo;
} pmix_cb_t;
PMIX_CLASS_DECLARATION(pmix_cb_t);

#define PMIX_THREADSHIFT(r, c)                                                      \
    do {                                                                            \
        pmix_event_assign(&((r)->ev), pmix_globals.evbase, -1, EV_WRITE, (c), (r)); \
        PMIX_POST_OBJECT((r));                                                      \
        pmix_event_active(&((r)->ev), EV_WRITE, 1);                                 \
    } while (0)

#define PMIX_THREADSHIFT_DELAY(r, c, t)                                  \
    do {                                                                 \
        struct timeval _tv = {0, 0};                                     \
        pmix_event_evtimer_set(pmix_globals.evbase, &(r)->ev, (c), (r)); \
        _tv.tv_sec = (int) (t);                                          \
        _tv.tv_usec = ((t) -_tv.tv_sec) * 1000000.0;                     \
        PMIX_POST_OBJECT((r));                                           \
        pmix_event_evtimer_add(&(r)->ev, &_tv);                          \
    } while (0)

typedef struct {
    pmix_object_t super;
    pmix_event_t ev;
    pmix_lock_t lock;
    /* timestamp receipt of the notification so we
     * can evict the oldest one if we get overwhelmed */
    time_t ts;
    /* what room of the hotel they are in */
    int room;
    pmix_status_t status;
    pmix_proc_t source;
    pmix_data_range_t range;
    /* For notification, we use the targets field to track
     * any custom range of procs that are to receive the
     * event.
     */
    pmix_proc_t *targets;
    size_t ntargets;
    size_t nleft; // number of targets left to be notified
    /* When generating a notification, the originator can
     * specify the range of procs affected by this event.
     * For example, when creating a JOB_TERMINATED event,
     * the RM can specify the nspace of the job that has
     * ended, thus allowing users to provide a different
     * callback object based on the nspace being monitored.
     * We use the "affected" field to track these values
     * when processing the event chain.
     */
    pmix_proc_t *affected;
    size_t naffected;
    /* track if the event generator stipulates that default
     * event handlers are/are not to be given the event */
    bool nondefault;
    /* carry along any other provided info so the individual
     * handlers can look at it */
    pmix_info_t *info;
    size_t ninfo;
    /* allow for a buffer to be carried across internal processing */
    pmix_buffer_t *buf;
    /* the final callback to be executed upon completion of the event */
    pmix_op_cbfunc_t cbfunc;
    void *cbdata;
} pmix_notify_caddy_t;
PMIX_CLASS_DECLARATION(pmix_notify_caddy_t);

typedef struct {
    pmix_object_t super;
    /** Points to key <--> index translation table. */
    pmix_pointer_array_t *table;
    /** Stores the next ID. */
    uint32_t next_id;
} pmix_keyindex_t;
PMIX_CLASS_DECLARATION(pmix_keyindex_t);

#define PMIX_KEYINDEX_STATIC_INIT                 \
{                                                 \
    .super = PMIX_OBJ_STATIC_INIT(pmix_object_t), \
    .table = NULL,                                \
    .next_id = PMIX_INDEX_BOUNDARY                \
}

/****    GLOBAL STORAGE    ****/
/* define a global construct that includes values that must be shared
 * between various parts of the code library. The client, tool,
 * and server libraries must instance this structure */
typedef struct {
    int init_cntr; // #times someone called Init - #times called Finalize
    pmix_proc_t myid;
    pmix_value_t myidval;
    pmix_value_t myrankval;
    pmix_peer_t *mypeer; // my own peer object
    uid_t realuid;       // real uid
    uid_t uid;           // my effective uid
    gid_t realgid;       // real gid
    gid_t gid;           // my effective gid
    char *hostname;      // my hostname
    char **aliases;      // aliases for my hostname
    uint32_t appnum;     // my appnum
    pid_t pid;           // my local pid
    uint32_t nodeid;     // my nodeid, if given
    uint32_t sessionid;  // my sessionid, if given
    int pindex;
    pmix_event_base_t *evbase;
    pmix_event_base_t *evauxbase;
    int debug_output;
    pmix_events_t events; // my event handler registrations.
    bool connected;
    bool commits_pending;
    struct timeval event_window;
    pmix_list_t cached_events;         // events waiting in the window prior to processing
    pmix_pointer_array_t iof_requests; // array of pmix_iof_req_t IOF requests
    int max_events;                    // size of the notifications hotel
    int event_eviction_time;           // max time to cache notifications
    pmix_hotel_t notifications;        // hotel of pending notifications
    /* IOF controls */
    bool pushstdin;
    pmix_list_t stdin_targets; // list of pmix_namelist_t
    bool tag_output;
    bool xml_output;
    bool timestamp_output;
    size_t output_limit;
    pmix_list_t nspaces;
    pmix_topology_t topology;
    pmix_cpuset_t cpuset;
    bool external_topology;
    bool external_progress;
    pmix_iof_flags_t iof_flags;
    pmix_keyindex_t keyindex;
} pmix_globals_t;

/* provide access to a function to cleanup epilogs */
PMIX_EXPORT void pmix_execute_epilog(pmix_epilog_t *ep);

PMIX_EXPORT pmix_status_t pmix_notify_event_cache(pmix_notify_caddy_t *cd);

PMIX_EXPORT extern pmix_globals_t pmix_globals;
PMIX_EXPORT extern pmix_lock_t pmix_global_lock;
PMIX_EXPORT extern const char* PMIX_PROXY_VERSION;
PMIX_EXPORT extern const char* PMIX_PROXY_BUGREPORT;

PMIX_EXPORT void pmix_log_local_op(int sd, short args, void *cbdata_);

static inline bool pmix_check_node_info(const char *key)
{
    char *keys[] = {
        PMIX_HOSTNAME,                  PMIX_HOSTNAME_ALIASES,
        PMIX_NODEID,                    PMIX_AVAIL_PHYS_MEMORY,
        PMIX_LOCAL_PEERS,               PMIX_LOCAL_PROCS,
        PMIX_LOCAL_CPUSETS,             PMIX_LOCAL_SIZE,
        PMIX_NODE_SIZE,                 PMIX_LOCALLDR,
        PMIX_NODE_OVERSUBSCRIBED,       PMIX_FABRIC_DEVICES,
        PMIX_FABRIC_COORDINATES,        PMIX_FABRIC_DEVICE,
        PMIX_FABRIC_DEVICE_INDEX,       PMIX_FABRIC_DEVICE_NAME,
        PMIX_FABRIC_DEVICE_VENDOR,      PMIX_FABRIC_DEVICE_BUS_TYPE,
        PMIX_FABRIC_DEVICE_VENDORID,    PMIX_FABRIC_DEVICE_DRIVER,
        PMIX_FABRIC_DEVICE_FIRMWARE,    PMIX_FABRIC_DEVICE_ADDRESS,
        PMIX_FABRIC_DEVICE_MTU,         PMIX_FABRIC_DEVICE_COORDINATES,
        PMIX_FABRIC_DEVICE_SPEED,       PMIX_FABRIC_DEVICE_STATE,
        PMIX_FABRIC_DEVICE_TYPE,        PMIX_FABRIC_DEVICE_PCI_DEVID,
        NULL
    };
    size_t n;

    for (n = 0; NULL != keys[n]; n++) {
        if (0 == strncmp(key, keys[n], PMIX_MAX_KEYLEN)) {
            return true;
        }
    }
    return false;
}

static inline bool pmix_check_app_info(const char *key)
{
    char *keys[] = {
        PMIX_APP_SIZE,  PMIX_APPLDR,       PMIX_APP_ARGV,      PMIX_WDIR,
        PMIX_PSET_NAME, PMIX_PSET_MEMBERS, PMIX_APP_MAP_TYPE,  PMIX_APP_MAP_REGEX,
        NULL
    };
    size_t n;

    for (n = 0; NULL != keys[n]; n++) {
        if (0 == strncmp(key, keys[n], PMIX_MAX_KEYLEN)) {
            return true;
        }
    }
    return false;
}

static inline bool pmix_check_session_info(const char *key)
{
    char *keys[] = {
        PMIX_SESSION_ID, PMIX_CLUSTER_ID,   PMIX_UNIV_SIZE,
        PMIX_TMPDIR,     PMIX_TDIR_RMCLEAN, PMIX_HOSTNAME_KEEP_FQDN,
        PMIX_RM_NAME,    PMIX_RM_VERSION,
        NULL
    };
    size_t n;

    for (n = 0; NULL != keys[n]; n++) {
        if (0 == strncmp(key, keys[n], PMIX_MAX_KEYLEN)) {
            return true;
        }
    }
    return false;
}

static inline bool pmix_check_special_key(const char *key)
{
    char *keys[] = {
        PMIX_GROUP_CONTEXT_ID,
        PMIX_GROUP_LOCAL_CID,
        NULL
    };
    size_t n;

    for (n = 0; NULL != keys[n]; n++) {
        if (0 == strncmp(key, keys[n], PMIX_MAX_KEYLEN)) {
            return true;
        }
    }
    return false;
}

#if PMIX_PICKY_COMPILERS
#define PMIX_HIDE_UNUSED_PARAMS(...)                \
    do {                                            \
        int __x = 3;                                \
        pmix_hide_unused_params(__x, __VA_ARGS__);  \
    } while(0)

PMIX_EXPORT void pmix_hide_unused_params(int x, ...);

#else
#define PMIX_HIDE_UNUSED_PARAMS(...)
#endif

#define PMIX_TRACE_KEY_ACTUAL(s, k, v)                  \
do {                                                    \
    if (0 == strcmp(s, k)) {                            \
        char *_v = PMIx_Value_string(v);                \
        pmix_output(0, "[%s:%s:%d] %s\n%s\n",           \
                    __FILE__, __func__, __LINE__,       \
                    PMIx_Get_attribute_name(k), _v);    \
        free(_v);                                       \
    }                                                   \
} while(0)

#define PMIX_TRACE_KEY(c, s, k, v)                          \
do {                                                        \
    if (0 == strcasecmp(c, "SERVER") &&                     \
        PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) {         \
        PMIX_TRACE_KEY_ACTUAL(s, k, v);                     \
    } else if (0 == strcasecmp(c, "CLIENT") &&              \
           !PMIX_PEER_IS_SERVER(pmix_globals.mypeer)) {     \
           PMIX_TRACE_KEY_ACTUAL(s, k, v);                  \
    }                                                       \
} while (0)

END_C_DECLS

#endif /* PMIX_GLOBALS_H */