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
 ss_pers_t *
 saf_allgather_handles(ss_pers_t *_pers, /* A Pointer to the handle to be exchanged.  Every participant must supply a valid
                                          * handle of the same type and in the same scope as every other participant. */
                       int *commsize,    /* [OUT] A pointer to optional caller supplied memory which is to receive the integer
                                          * number of handles returned by this function.  This is the number of participants or
                                          * the size of the communicator associated with the given database. */
                       ss_pers_t *result /* [OUT] An optional pointer to an array that will will be initialized with a handle
                                          * from each MPI task in task rank order. If this buffer is supplied then it should be
                                          * at least as large as the communicator associated with the DB argument. If not
                                          * supplied (i.e., null) then a buffer will be allocated for the return value. */
                       )
 {
     SAF_ENTER(saf_allgather_handles, NULL);
     ss_scope_t          scope=SS_SCOPE_NULL;
     ss_file_t           file=SS_FILE_NULL;
     int                 self, ntasks=0;
     size_t              encoded_nused=0, encoded_nalloc=0, consumed;
     char                *encoded=NULL, *all_encoded=NULL;
     MPI_Comm            comm=SS_COMM_NULL;

     /* It might be possible that the ss_pers_t pointer _PERS is a pointer into some object. If that object is a new object
      * then the ss_file_synchronize() call below may clobber that memory. Therefore we copy the link onto the stack first. */
     ss_pers_t           pers=*_pers;

     SAF_REQUIRE(ss_pers_deref(&pers), SAF_LOW_CHK_COST, NULL, _saf_errmsg("_PERS must be a valid object link"));

     /* Obtain communicator info. */
     ss_pers_scope(&pers, &scope);
     ss_scope_comm(&scope, &comm, &self, &ntasks);
     if (commsize) *commsize = ntasks;

     /* Synchronize the table, thus turning the _PERS arguments into global objects. */
     ss_pers_file(&pers, &file);
     if (ss_file_synchronize(&file, NULL)<0)
         SAF_ERROR(NULL, _saf_errmsg("file synchronization failed"));

     /* Each task encodes its _PERS argument. They should all be the same size when encoded. */
     encoded = ss_pers_encode_cb(&pers, NULL, &encoded_nused, &encoded_nalloc, sizeof(pers), 1);

     /* Gather all the encoded object links */
     all_encoded = malloc(ntasks*encoded_nused);
     memcpy(all_encoded+self*encoded_nused, encoded, encoded_nused);
     ss_mpi_allgather(all_encoded, encoded_nused, MPI_BYTE, comm);

     /* Decode the object links into the result buffer. */
     if (!result) result = malloc(ntasks*sizeof(*result));
     consumed = ss_pers_decode_cb(result, all_encoded, sizeof(*result), (size_t)ntasks);
     assert(consumed==ntasks*encoded_nused);

     /* Free temporary resources */
     encoded = SS_FREE(encoded);
     all_encoded = SS_FREE(all_encoded);

     SAF_LEAVE(result);
 }