File: attrlangc.c

package info (click to toggle)
mpich 4.3.0%2Breally4.2.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, trixie
  • size: 419,120 kB
  • sloc: ansic: 1,215,557; cpp: 74,755; javascript: 40,763; f90: 20,649; sh: 18,463; xml: 14,418; python: 14,397; perl: 13,772; makefile: 9,279; fortran: 8,063; java: 4,553; asm: 324; ruby: 176; lisp: 19; php: 8; sed: 4
file content (647 lines) | stat: -rw-r--r-- 22,992 bytes parent folder | download | duplicates (3)
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
/*
 * Copyright (C) by Argonne National Laboratory
 *     See COPYRIGHT in top-level directory
 */

#include <stdio.h>
#include "mpi.h"
#include <stdlib.h>
#include <string.h>
#include "../../include/mpitestconf.h"

/* Used to convert Fortran strings (which may not be null terminated) to
   C strings */
#define MAX_ATTRTEST_MSG 256

/*
 * FIXME: This code assumes that character strings are passed from Fortran
 * by placing the string length, as an int, at the end of the argument list
 * This is common but not universal.
 */

/*
   Name mapping.  All routines are created with names that are lower case
   with a single trailing underscore.  This matches many compilers.
   We use #define to change the name for Fortran compilers that do
   not use the lowercase/underscore pattern
*/

#ifdef F77_NAME_UPPER
#define cattrinit_   CATTRINIT
#define cgetenvbool_ CGETENVBOOL
#define cgetsizes_   CGETSIZES
#define ccreatekeys_ CCREATEKEYS
#define cfreekeys_   CFREEKEYS
#define ctoctest_    CTOCTEST
#define cmpif1read_  CMPIF1READ
#define cmpif2read_  CMPIF2READ
#define cmpif2readtype_  CMPIF2READTYPE
#define cmpif2readwin_   CMPIF2READWIN
#define csetmpi_     CSETMPI
#define csetmpi2_    CSETMPI2
#define csetmpitype_ CSETMPITYPE
#define csetmpiwin_  CSETMPIWIN

#elif defined(F77_NAME_LOWER) || defined(F77_NAME_MIXED)
/* Mixed is ok because we use lowercase in all uses */
#define cattrinit_   cattrinit
#define cgetenvbool_ cgetenvbool
#define cgetsizes_   cgetsizes
#define ccreatekeys_ ccreatekeys
#define cfreekeys_   cfreekeys
#define ctoctest_    ctoctest
#define cmpif1read_  cmpif1read
#define cmpif2read_  cmpif2read
#define cmpif2readtype_  cmpif2readtype
#define cmpif2readwin_   cmpif2readwin
#define csetmpi_     csetmpi
#define csetmpi2_    csetmpi2
#define csetmpitype_ csetmpitype
#define csetmpiwin_  csetmpiwin

#elif defined(F77_NAME_LOWER_2USCORE) || defined(F77_NAME_LOWER_USCORE) || \
      defined(F77_NAME_MIXED_USCORE)
/* Else leave name alone (routines have no underscore, so both
   of these map to a lowercase, single underscore) */
#else
#error 'Unrecognized Fortran name mapping'
#endif

/* */
static int ccomm1Key, ccomm2Key, ctype2Key, cwin2Key;
static int ccomm1Extra, ccomm2Extra, ctype2Extra, cwin2Extra;
static int verbose = 0;

/* Forward references */
int cmpi1read(MPI_Comm comm, int key, void *expected, const char *msg);
int cmpi2read(MPI_Comm comm, int key, void *expected, const char *msg);
int cmpi2readtype(MPI_Datatype dtype, int key, void *expected, const char *msg);

void ccompareint2aint_(MPI_Fint * in1, MPI_Aint * in2, MPI_Fint * result);
void ccompareint2void_(MPI_Fint * in1, void *in2, MPI_Fint * result);
void ccompareaint2void_(MPI_Aint * in1, void *in2, MPI_Fint * result);

void cgetenvbool_(const char str[], MPI_Fint * val, int d);
void cattrinit_(MPI_Fint * fverbose);
void cgetsizes_(MPI_Fint * ptrSize, MPI_Fint * intSize, MPI_Fint * aintSize);
void ccreatekeys_(MPI_Fint * ccomm1_key, MPI_Fint * ccomm2_key,
                  MPI_Fint * ctype2_key, MPI_Fint * cwin2_key);
void cfreekeys_(void);
void ctoctest_(MPI_Fint * errs);
int cmpi1read(MPI_Comm comm, int key, void *expected, const char *msg);
int cmpi2read(MPI_Comm comm, int key, void *expected, const char *msg);
int cmpi2readtype(MPI_Datatype dtype, int key, void *expected, const char *msg);
int cmpi2readwin(MPI_Win win, int key, void *expected, const char *msg);
void cmpif1read_(MPI_Fint * fcomm, MPI_Fint * fkey, MPI_Fint * expected,
                 MPI_Fint * errs, const char *msg, int msglen);
void cmpif2read_(MPI_Fint * fcomm, MPI_Fint * fkey, MPI_Aint * expected,
                 MPI_Fint * errs, const char *msg, int msglen);
void cmpif2readtype_(MPI_Fint * ftype, MPI_Fint * fkey, MPI_Aint * expected,
                     MPI_Fint * errs, const char *msg, int msglen);
void cmpif2readwin_(MPI_Fint * fwin, MPI_Fint * fkey, MPI_Aint * expected,
                    MPI_Fint * errs, const char *msg, int msglen);
void csetmpi_(MPI_Fint * fcomm, MPI_Fint * fkey, MPI_Fint * val, MPI_Fint * errs);
void csetmpi2_(MPI_Fint * fcomm, MPI_Fint * fkey, MPI_Aint * val, MPI_Fint * errs);
void csetmpitype_(MPI_Fint * ftype, MPI_Fint * fkey, MPI_Aint * val, MPI_Fint * errs);
void csetmpiwin_(MPI_Fint * fwin, MPI_Fint * fkey, MPI_Aint * val, MPI_Fint * errs);
void ccompareint2aint_(MPI_Fint * in1, MPI_Aint * in2, MPI_Fint * result);
void ccompareint2void_(MPI_Fint * in1, void *in2, MPI_Fint * result);
void ccompareaint2void_(MPI_Aint * in1, void *in2, MPI_Fint * result);

/* ----------------------------------------------------------------------- */
/* Initialization functions                                                */
/* ----------------------------------------------------------------------- */
void cgetenvbool_(const char str[], MPI_Fint * val, int d)
{
    const char *envval;
    char envname[1024];
    /* Note that the Fortran string may not be null terminated; thus
     * we copy d characters and add a null just in case */
    if (d > sizeof(envname) - 1) {
        fprintf(stderr, "Environment variable name too long (%d)\n", d);
        MPI_Abort(MPI_COMM_WORLD, 1);
    }
    strncpy(envname, str, d);
    envname[d] = 0;

    envval = getenv(envname);
    *val = 0;
    if (envval) {
        printf(" envval = %s\n", envval);
        if (strcmp(envval, "yes") == 0 || strcmp(envval, "YES") == 0 ||
            strcmp(envval, "true") == 0 || strcmp(envval, "TRUE") == 0)
            *val = 1;
    }
}

/* Keep our own copy of the "is verbose" state */
void cattrinit_(MPI_Fint * fverbose)
{
    verbose = (int) *fverbose;
}

/* Provide attribute sizes (C, Fortran 1, Fortran 2) */
void cgetsizes_(MPI_Fint * ptrSize, MPI_Fint * intSize, MPI_Fint * aintSize)
{
    *ptrSize = (MPI_Fint) sizeof(void *);
    *intSize = (MPI_Fint) sizeof(MPI_Fint);
    *aintSize = (MPI_Fint) sizeof(MPI_Aint);
}

/* ----------------------------------------------------------------------- */
/* Copy and delete functions attached to keyvals                           */
/* ----------------------------------------------------------------------- */
static int CMPI1_COPY_FN(MPI_Comm comm, int keyval, void *extra,
                         void *inval, void *outval, int *flag)
{
    int inValue = *(int *) inval;

    if (verbose)
        printf(" In C MPI-1 copy function: inval = %p, extra = %p\n", inval, extra);
    *flag = 1;
    /* We don't change the attribute */
    *(void **) outval = inval;
    /* But we do change what it points at */
    *(int *) inval = inValue + 1;
    return MPI_SUCCESS;
}

static int CMPI1_DELETE_FN(MPI_Comm comm, int keyval, void *outval, void *extra)
{
    if (verbose)
        printf(" In C MPI-1 delete function, extra = %p\n", extra);
    *(int *) outval = *(int *) outval - 1;
    return MPI_SUCCESS;
}

static int TYPE_COPY_FN(MPI_Datatype dtype, int keyval, void *extra,
                        void *inval, void *outval, int *flag)
{
    int inValue = *(int *) inval;

    if (verbose)
        printf(" In C MPI type copy function, inval = %p, extra = %p\n", inval, extra);
    *flag = 1;
    /* We don't change the attribute */
    *(void **) outval = inval;
    /* But we do change what it points at */
    *(int *) inval = inValue + 1;
    return MPI_SUCCESS;
}

static int TYPE_DELETE_FN(MPI_Datatype dtype, int keyval, void *outval, void *extra)
{
    if (verbose)
        printf(" In C MPI type delete function, extra = %p\n", extra);
    /* We reverse the increment used in copy (checked after free of the type) */
    *(int *) outval = *(int *) outval - 1;
    return MPI_SUCCESS;
}

/* Note that this function cannot be called in MPI since there is no
   win_dup function */
static int WIN_COPY_FN(MPI_Win win, int keyval, void *extra, void *inval, void *outval, int *flag)
{
    if (verbose)
        printf("PANIC: In C MPI win copy function (should never happen)\n");
    *flag = 1;
    return MPI_SUCCESS;
}

static int WIN_DELETE_FN(MPI_Win win, int keyval, void *outval, void *extra)
{
    if (verbose)
        printf(" In C MPI win delete function, extra = %p\n", extra);
    *(int *) outval = *(int *) outval - 1;
    return MPI_SUCCESS;
}

/* ----------------------------------------------------------------------- */
/* Routines to create keyvals in C (with C copy and delete functions       */
/* ----------------------------------------------------------------------- */

void ccreatekeys_(MPI_Fint * ccomm1_key, MPI_Fint * ccomm2_key,
                  MPI_Fint * ctype2_key, MPI_Fint * cwin2_key)
{
    MPI_Keyval_create(CMPI1_COPY_FN, CMPI1_DELETE_FN, &ccomm1Key, &ccomm1Extra);
    *ccomm1_key = (MPI_Fint) ccomm1Key;

    MPI_Comm_create_keyval(CMPI1_COPY_FN, CMPI1_DELETE_FN, &ccomm2Key, &ccomm2Extra);
    *ccomm2_key = (MPI_Fint) ccomm2Key;

    MPI_Type_create_keyval(TYPE_COPY_FN, TYPE_DELETE_FN, &ctype2Key, &ctype2Extra);
    *ctype2_key = (MPI_Fint) ctype2Key;

    MPI_Win_create_keyval(WIN_COPY_FN, WIN_DELETE_FN, &cwin2Key, &cwin2Extra);
    *cwin2_key = (MPI_Fint) cwin2Key;
}

void cfreekeys_(void)
{
    MPI_Keyval_free(&ccomm1Key);
    MPI_Comm_free_keyval(&ccomm2Key);
    MPI_Type_free_keyval(&ctype2Key);
    MPI_Win_free_keyval(&cwin2Key);
}

/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */

/* Test c-to-c attributes */
static int ccomm1Attr, ccomm2Attr, ctype2Attr, cwin2Attr;

void ctoctest_(MPI_Fint * errs)
{
    int errcnt = *errs;
    int baseattrval = (1 << (sizeof(int) * 8 - 2)) - 3;
    MPI_Datatype cduptype;
    MPI_Comm cdup;

    /* MPI-1 function */
    ccomm1Attr = baseattrval;
    MPI_Attr_put(MPI_COMM_SELF, ccomm1Key, &ccomm1Attr);
    /* Test that we have the same value */
    errcnt += cmpi1read(MPI_COMM_SELF, ccomm1Key, &ccomm1Attr, "C to C");

    /* Dup, check that the copy routine does what is expected */
    MPI_Comm_dup(MPI_COMM_SELF, &cdup);
    errcnt += cmpi1read(cdup, ccomm1Key, &ccomm1Attr, "C to C dup");
    if (ccomm1Attr != baseattrval + 1) {
        printf(" Did not increment int in C to C dup: %d %d\n", ccomm1Attr, baseattrval + 1);
        errcnt++;
    }

    MPI_Comm_free(&cdup);
    if (ccomm1Attr != baseattrval) {
        printf(" Did not increment int in C to C delete: %d %d\n", ccomm1Attr, baseattrval);
        errcnt++;
    }

    /* MPI-2 functions */
    ccomm1Attr = 0;
    ccomm2Attr = baseattrval;
    MPI_Comm_set_attr(MPI_COMM_SELF, ccomm2Key, &ccomm2Attr);
    /* Test that we have the same value */
    errcnt += cmpi2read(MPI_COMM_SELF, ccomm2Key, &ccomm2Attr, "C to C (2)");

    /* Dup, check that the copy routine does what is expected */
    MPI_Comm_dup(MPI_COMM_SELF, &cdup);
    errcnt += cmpi2read(cdup, ccomm2Key, &ccomm2Attr, "C to C dup (2)");
    if (ccomm2Attr != baseattrval + 1) {
        printf(" Did not increment int in C to C dup: %d %d\n", ccomm2Attr, baseattrval + 1);
        errcnt++;
    }

    MPI_Comm_free(&cdup);
    if (ccomm2Attr != baseattrval) {
        printf(" Did not increment int in C to C delete (2): %d %d\n", ccomm2Attr, baseattrval);
        errcnt++;
    }

    /* MPI-2 functions */
    ctype2Attr = baseattrval;
    MPI_Type_set_attr(MPI_INTEGER, ctype2Key, &ctype2Attr);
    /* Test that we have the same value */
    errcnt += cmpi2readtype(MPI_INTEGER, ctype2Key, &ctype2Attr, "C to C type (2)");

    /* Dup, check that the copy routine does what is expected */
    MPI_Type_dup(MPI_INTEGER, &cduptype);
    errcnt += cmpi2readtype(cduptype, ctype2Key, &ctype2Attr, "C to C typedup (2)");
    if (ctype2Attr != baseattrval + 1) {
        printf(" Did not increment int in C to C typedup: %d %d\n", ctype2Attr, baseattrval + 1);
        errcnt++;
    }
    ccomm1Attr = 0;

    MPI_Type_free(&cduptype);
    if (ctype2Attr != baseattrval) {
        printf(" Did not increment int in C to C typedelete (2): %d %d\n", ctype2Attr, baseattrval);
        errcnt++;
    }


    *errs = errcnt;
}

/* ----------------------------------------------------------------------- */
/* Routines to get and check an attribute value.  Returns the number       */
/*   of errors found                                                       */
/* ----------------------------------------------------------------------- */

int cmpi1read(MPI_Comm comm, int key, void *expected, const char *msg)
{
    void *attrval;
    int flag;
    MPI_Attr_get(comm, key, &attrval, &flag);
    if (!flag) {
        printf(" Error: flag false for Attr_get: %s\n", msg);
        return 1;
    }
    if (attrval != expected) {
        printf(" Error: expected %p but saw %p: %s\n", expected, attrval, msg);
        return 1;
    }
    return 0;
}

int cmpi2read(MPI_Comm comm, int key, void *expected, const char *msg)
{
    void *attrval;
    int flag;
    MPI_Comm_get_attr(comm, key, &attrval, &flag);
    if (!flag) {
        printf(" Error: flag false for Comm_get_attr: %s\n", msg);
        return 1;
    }
    if (attrval != expected) {
        printf(" Error: expected %p but saw %p: %s\n", expected, attrval, msg);
        return 1;
    }
    return 0;
}

int cmpi2readtype(MPI_Datatype dtype, int key, void *expected, const char *msg)
{
    void *attrval;
    int flag;
    MPI_Type_get_attr(dtype, key, &attrval, &flag);
    if (!flag) {
        printf(" Error: flag false for Type_get_attr: %s\n", msg);
        return 1;
    }
    if (attrval != expected) {
        printf(" Error: expected %p but saw %p: %s\n", expected, attrval, msg);
        return 1;
    }
    return 0;
}

int cmpi2readwin(MPI_Win win, int key, void *expected, const char *msg)
{
    void *attrval;
    int flag;
    MPI_Win_get_attr(win, key, &attrval, &flag);
    if (!flag) {
        printf(" Error: flag false for Win_get_attr: %s\n", msg);
        return 1;
    }
    if (attrval != expected) {
        printf(" Error: expected %p but saw %p: %s\n", expected, attrval, msg);
        return 1;
    }
    return 0;
}

/* Set in Fortran (MPI-1), read in C */
void cmpif1read_(MPI_Fint * fcomm, MPI_Fint * fkey, MPI_Fint * expected,
                 MPI_Fint * errs, const char *msg, int msglen)
{
    void *attrval;
    int flag, result;
    MPI_Comm comm = MPI_Comm_f2c(*fcomm);
    char lmsg[MAX_ATTRTEST_MSG];

    if (msglen > sizeof(lmsg) - 1) {
        fprintf(stderr, "Message too long for buffer (%d)\n", msglen);
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    MPI_Attr_get(comm, *fkey, &attrval, &flag);
    if (!flag) {
        *errs = *errs + 1;
        strncpy(lmsg, msg, msglen);
        lmsg[msglen] = 0;
        printf(" Error: flag false for Attr_get (set in F1): %s\n", lmsg);
        return;
    }
    /* Must be careful to compare as required in the MPI specification */
    ccompareint2void_(expected, attrval, &result);
    if (!result) {
        *errs = *errs + 1;
        strncpy(lmsg, msg, msglen);
        lmsg[msglen] = 0;
        printf(" Error: (set in F1) expected %d but saw %d: %s\n",
               *expected, *(MPI_Fint *) attrval, lmsg);
        return;
    }
    return;
}

/* Set in Fortran (MPI-2), read in C */
void cmpif2read_(MPI_Fint * fcomm, MPI_Fint * fkey, MPI_Aint * expected,
                 MPI_Fint * errs, const char *msg, int msglen)
{
    void *attrval;
    int flag, result;
    MPI_Comm comm = MPI_Comm_f2c(*fcomm);
    char lmsg[MAX_ATTRTEST_MSG];

    if (msglen > sizeof(lmsg) - 1) {
        fprintf(stderr, "Message too long for buffer (%d)\n", msglen);
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    MPI_Comm_get_attr(comm, *fkey, &attrval, &flag);
    if (!flag) {
        *errs = *errs + 1;
        strncpy(lmsg, msg, msglen);
        lmsg[msglen] = 0;
        printf(" Error: flag false for Comm_get_attr (set in F2): %s\n", lmsg);
        return;
    }
    ccompareaint2void_(expected, attrval, &result);
    if (!result) {
        *errs = *errs + 1;
        strncpy(lmsg, msg, msglen);
        lmsg[msglen] = 0;
        printf(" Error: (set in F2) expected %ld but saw %ld: %s\n",
               (long) *expected, (long) *(MPI_Aint *) attrval, lmsg);
        return;
    }
    return;
}

void cmpif2readtype_(MPI_Fint * ftype, MPI_Fint * fkey, MPI_Aint * expected,
                     MPI_Fint * errs, const char *msg, int msglen)
{
    void *attrval;
    int flag, result;
    MPI_Datatype dtype = MPI_Type_f2c(*ftype);
    char lmsg[MAX_ATTRTEST_MSG];

    if (msglen > sizeof(lmsg) - 1) {
        fprintf(stderr, "Message too long for buffer (%d)\n", msglen);
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    MPI_Type_get_attr(dtype, *fkey, &attrval, &flag);
    if (!flag) {
        *errs = *errs + 1;
        strncpy(lmsg, msg, msglen);
        lmsg[msglen] = 0;
        printf(" Error: flag false for Type_get_attr (set in F2): %s\n", lmsg);
        return;
    }
    ccompareaint2void_(expected, attrval, &result);
    if (!result) {
        *errs = *errs + 1;
        strncpy(lmsg, msg, msglen);
        lmsg[msglen] = 0;
        printf(" Error: (set in F2/Type) expected %ld but saw %ld: %s\n",
               (long) *expected, (long) *(MPI_Aint *) attrval, lmsg);
        return;
    }
    return;
}

void cmpif2readwin_(MPI_Fint * fwin, MPI_Fint * fkey, MPI_Aint * expected,
                    MPI_Fint * errs, const char *msg, int msglen)
{
    void *attrval;
    int flag, result;
    MPI_Win win = MPI_Win_f2c(*fwin);
    char lmsg[MAX_ATTRTEST_MSG];

    if (msglen > sizeof(lmsg) - 1) {
        fprintf(stderr, "Message too long for buffer (%d)\n", msglen);
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    MPI_Win_get_attr(win, *fkey, &attrval, &flag);
    if (!flag) {
        *errs = *errs + 1;
        strncpy(lmsg, msg, msglen);
        lmsg[msglen] = 0;
        printf(" Error: flag false for Win_get_attr (set in F2): %s\n", lmsg);
        return;
    }
    ccompareaint2void_(expected, attrval, &result);
    if (!result) {
        *errs = *errs + 1;
        strncpy(lmsg, msg, msglen);
        lmsg[msglen] = 0;
        printf(" Error: (set in F2/Win) expected %ld but saw %ld: %s\n",
               (long) *expected, (long) *(MPI_Aint *) attrval, lmsg);
        return;
    }
    return;
}

/* ----------------------------------------------------------------------- */
/* Given a Fortran attribute (pointer to the value to store), set it using */
/* the C attribute functions                                               */
/* ----------------------------------------------------------------------- */

void csetmpi_(MPI_Fint * fcomm, MPI_Fint * fkey, MPI_Fint * val, MPI_Fint * errs)
{
    MPI_Comm comm = MPI_Comm_f2c(*fcomm);

    MPI_Comm_set_attr(comm, *fkey, (void *) (MPI_Aint) * val);
}

void csetmpi2_(MPI_Fint * fcomm, MPI_Fint * fkey, MPI_Aint * val, MPI_Fint * errs)
{
    MPI_Comm comm = MPI_Comm_f2c(*fcomm);

    MPI_Comm_set_attr(comm, *fkey, (void *) *val);
}

void csetmpitype_(MPI_Fint * ftype, MPI_Fint * fkey, MPI_Aint * val, MPI_Fint * errs)
{
    MPI_Datatype dtype = MPI_Type_f2c(*ftype);

    MPI_Type_set_attr(dtype, *fkey, (void *) *val);
}

void csetmpiwin_(MPI_Fint * fwin, MPI_Fint * fkey, MPI_Aint * val, MPI_Fint * errs)
{
    MPI_Win win = MPI_Win_f2c(*fwin);

    MPI_Win_set_attr(win, *fkey, (void *) *val);
}

/* ----------------------------------------------------------------------- */
/* Comparisons                                                             */
/*    int with aint                                                        */
/*    int with void*                                                       */
/*    aint with void*                                                      */
/* All routines use similar interfaces, though the routines that involve   */
/* void * must be called from C                                            */
/* Defined to be callable from either C or Fortran                         */
/* Here is the rule, defined in the MPI standard:                          */
/*    If one item is shorter than the other, take the low bytes.           */
/*    If one item is longer than the other, sign extend                    */
/* ----------------------------------------------------------------------- */
void ccompareint2aint_(MPI_Fint * in1, MPI_Aint * in2, MPI_Fint * result)
{
    static int idx = -1;
    if (sizeof(MPI_Fint) == sizeof(MPI_Aint)) {
        *result = *in1 == *in2;
    } else if (sizeof(MPI_Fint) < sizeof(MPI_Aint)) {
        /* Assume Aint no smaller than Fint, and that size of aint
         * is a multiple of the size of fint) */
        MPI_Fint *v2 = (MPI_Fint *) in2;
        if (idx < 0) {
            MPI_Aint av = 1;
            MPI_Fint *fa = (MPI_Fint *) & av;
            if ((sizeof(MPI_Aint) % sizeof(MPI_Fint)) != 0) {
                fprintf(stderr,
                        "PANIC: size of MPI_Aint = %d not a multiple of MPI_Fint = %d\n",
                        (int) sizeof(MPI_Aint), (int) sizeof(MPI_Fint));
                MPI_Abort(MPI_COMM_WORLD, 1);
            }
            for (idx = sizeof(MPI_Aint) / sizeof(MPI_Fint); idx >= 0; idx--)
                if (fa[idx])
                    break;
            if (idx < 0) {
                fprintf(stderr, "Unable to determine low word of Fint in Aint\n");
                MPI_Abort(MPI_COMM_WORLD, 1);
            }
            *result = *in1 == v2[idx];
        }
    } else {
        fprintf(stderr, "PANIC: sizeof(MPI_Fint) = %d > sizeof(MPI_Aint) %d\n",
                (int) sizeof(MPI_Fint), (int) sizeof(MPI_Aint));
        MPI_Abort(MPI_COMM_WORLD, 1);
    }
}

void ccompareint2void_(MPI_Fint * in1, void *in2, MPI_Fint * result)
{
    static int idx = -1;
    if (sizeof(MPI_Fint) == sizeof(void *)) {
        *result = *in1 == *(MPI_Fint *) in2;
    } else if (sizeof(MPI_Fint) < sizeof(void *)) {
        /* Assume void* no smaller than Fint, and that size of aint
         * is a multiple of the size of fint) */
        MPI_Fint *v2 = (MPI_Fint *) in2;
        if (idx < 0) {
            void *av = (void *) 1;
            MPI_Fint *fa = (MPI_Fint *) & av;
            if ((sizeof(void *) % sizeof(MPI_Fint)) != 0) {
                fprintf(stderr,
                        "PANIC: size of void * = %d not a multiple of MPI_Fint = %d\n",
                        (int) sizeof(void *), (int) sizeof(MPI_Fint));
                MPI_Abort(MPI_COMM_WORLD, 1);
            }
            for (idx = sizeof(void *) / sizeof(MPI_Fint); idx >= 0; idx--)
                if (fa[idx])
                    break;
            if (idx < 0) {
                fprintf(stderr, "Unable to determine low word of Fint in void*\n");
                MPI_Abort(MPI_COMM_WORLD, 1);
            }
            *result = *in1 == v2[idx];
        }
    } else {
        fprintf(stderr, "PANIC: sizeof(MPI_Fint) = %d > sizeof(void*) %d\n",
                (int) sizeof(MPI_Fint), (int) sizeof(void *));
        MPI_Abort(MPI_COMM_WORLD, 1);
    }
}

void ccompareaint2void_(MPI_Aint * in1, void *in2, MPI_Fint * result)
{
    /* Note that an aint must be >= void * by definition */
    *result = *in1 == *(MPI_Aint *) in2;
}