1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
4 * (C) 2008 by Argonne National Laboratory.
5 * See COPYRIGHT in top-level directory.
8 The MPI-2.2 specification makes it clear that attributes are called on
9 MPI_COMM_WORLD and MPI_COMM_SELF at the very beginning of MPI_Finalize in
10 LIFO order with respect to the order in which they are set. This is
11 useful for tools that want to perform the MPI equivalent of an "at_exit"
18 /* 20 ought to be enough attributes to ensure that hash-table based MPI
19 * implementations do not accidentally pass the test except by being extremely
20 * "lucky". There are (20!) possible permutations which means that there is
21 * about a 1 in 2.43e18 chance of getting LIFO ordering out of a hash table,
22 * assuming a decent hash function is used. */
23 #define NUM_TEST_ATTRS (20)
25 static __attribute__((unused)) int exit_keys[NUM_TEST_ATTRS]; /* init to MPI_KEYVAL_INVALID */
26 static __attribute__((unused)) int was_called[NUM_TEST_ATTRS];
28 int delete_fn (MPI_Comm, int, void *, void *);
30 int main(int argc, char **argv)
34 MTest_Init(&argc, &argv);
36 MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
38 #if MTEST_HAVE_MIN_MPI_VERSION(2,2)
41 for (i = 0; i < NUM_TEST_ATTRS; ++i) {
42 exit_keys[i] = MPI_KEYVAL_INVALID;
45 /* create the keyval for the exit handler */
46 MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, delete_fn, &exit_keys[i], NULL);
47 /* attach to comm_self */
48 MPI_Comm_set_attr(MPI_COMM_SELF, exit_keys[i], (void*)(long)i);
51 /* we can free the keys now */
52 for (i = 0; i < NUM_TEST_ATTRS; ++i) {
53 MPI_Comm_free_keyval(&exit_keys[i]);
59 /* check that the exit handlers were called in LIFO order, and without error */
61 /* In case more than one process exits MPI_Finalize */
62 for (i = 0; i < NUM_TEST_ATTRS; ++i) {
63 if (was_called[i] < 1) {
65 printf("Attribute delete function on MPI_COMM_SELF was not called for idx=%d\n", i);
67 else if (was_called[i] > 1) {
69 printf("Attribute delete function on MPI_COMM_SELF was called multiple times for idx=%d\n", i);
72 if (foundError != 0) {
74 printf("Found %d errors while executing delete function in MPI_COMM_SELF\n", foundError);
77 printf(" No Errors\n");
80 printf(" Found %d errors\n", errs);
84 #else /* this is a pre-MPI-2.2 implementation, ordering is not defined */
87 printf(" No Errors\n");
93 int delete_fn(MPI_Comm comm, int keyval, void *attribute_val, void *extra_state)
97 int my_idx = (int)(long)attribute_val;
99 if (my_idx < 0 || my_idx > NUM_TEST_ATTRS) {
100 printf("internal error, my_idx=%d is invalid!\n", my_idx);
104 was_called[my_idx]++;
106 MPI_Finalized(&flag);
108 printf("my_idx=%d, MPI_Finalized returned %d, should have been 0", my_idx, flag);
112 /* since attributes were added in 0..(NUM_TEST_ATTRS-1) order, they will be
113 * called in (NUM_TEST_ATTRS-1)..0 order */
114 for (i = 0; i < my_idx; ++i) {
115 if (was_called[i] != 0) {
116 printf("my_idx=%d, was_called[%d]=%d but should be 0\n", my_idx, i, was_called[i]);
120 for (i = my_idx; i < NUM_TEST_ATTRS; ++i) {
121 if (was_called[i] != 1) {
122 printf("my_idx=%d, was_called[%d]=%d but should be 1\n", my_idx, i, was_called[i]);