xref: /petsc/src/sys/objects/tagm.c (revision 834855d6effb0d027771461c8e947ee1ce5a1e17)
1af0996ceSBarry Smith #include <petsc/private/petscimpl.h> /*I    "petscsys.h"   I*/
262e5d2d2SJDBetteridge #include <petsc/private/hashmapobj.h>
362e5d2d2SJDBetteridge #include <petsc/private/garbagecollector.h>
421532e8aSBarry Smith 
5e5c89e4eSSatish Balay /*
6e5c89e4eSSatish Balay    A simple way to manage tags inside a communicator.
7e5c89e4eSSatish Balay 
8e5c89e4eSSatish Balay    It uses the attributes to determine if a new communicator
9e5c89e4eSSatish Balay       is needed and to store the available tags.
10e5c89e4eSSatish Balay 
11e5c89e4eSSatish Balay */
12e5c89e4eSSatish Balay 
13ffeef943SBarry Smith /*@
14e5c89e4eSSatish Balay   PetscObjectGetNewTag - Gets a unique new tag from a PETSc object. All
15e5c89e4eSSatish Balay   processors that share the object MUST call this routine EXACTLY the same
16e5c89e4eSSatish Balay   number of times.  This tag should only be used with the current objects
17e5c89e4eSSatish Balay   communicator; do NOT use it with any other MPI communicator.
18e5c89e4eSSatish Balay 
19c3339decSBarry Smith   Collective
20e5c89e4eSSatish Balay 
21e5c89e4eSSatish Balay   Input Parameter:
22811af0c4SBarry Smith . obj - the PETSc object; this must be cast with a (`PetscObject`), for example,
23811af0c4SBarry Smith          `PetscObjectGetNewTag`((`PetscObject`)mat,&tag);
24e5c89e4eSSatish Balay 
25e5c89e4eSSatish Balay   Output Parameter:
26e5c89e4eSSatish Balay . tag - the new tag
27e5c89e4eSSatish Balay 
28e5c89e4eSSatish Balay   Level: developer
29e5c89e4eSSatish Balay 
30811af0c4SBarry Smith   Note:
31811af0c4SBarry Smith   This tag is needed if one is writing MPI communication code involving message passing and needs unique MPI tags to ensure the messages are connected to this specific
32811af0c4SBarry Smith   object.
33811af0c4SBarry Smith 
34db781477SPatrick Sanan .seealso: `PetscCommGetNewTag()`
35e5c89e4eSSatish Balay @*/
PetscObjectGetNewTag(PetscObject obj,PetscMPIInt * tag)36d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscObjectGetNewTag(PetscObject obj, PetscMPIInt *tag)
37d71ae5a4SJacob Faibussowitsch {
38e5c89e4eSSatish Balay   PetscFunctionBegin;
399566063dSJacob Faibussowitsch   PetscCall(PetscCommGetNewTag(obj->comm, tag));
403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
41e5c89e4eSSatish Balay }
42e5c89e4eSSatish Balay 
43e30d2299SSatish Balay /*@
4410450e9eSJacob Faibussowitsch   PetscCommGetNewTag - Gets a unique new tag from a PETSc communicator
45e5c89e4eSSatish Balay 
46d083f849SBarry Smith   Collective
47e5c89e4eSSatish Balay 
48e5c89e4eSSatish Balay   Input Parameter:
49655f41cfSBarry Smith . comm - the MPI communicator
50e5c89e4eSSatish Balay 
51e5c89e4eSSatish Balay   Output Parameter:
52e5c89e4eSSatish Balay . tag - the new tag
53e5c89e4eSSatish Balay 
54e5c89e4eSSatish Balay   Level: developer
55e5c89e4eSSatish Balay 
5610450e9eSJacob Faibussowitsch   Notes:
5710450e9eSJacob Faibussowitsch   All processors that share the communicator MUST call this routine EXACTLY the same number of
5810450e9eSJacob Faibussowitsch   times. This tag should only be used with the current objects communicator; do NOT use it
5910450e9eSJacob Faibussowitsch   with any other MPI communicator.
6010450e9eSJacob Faibussowitsch 
61db781477SPatrick Sanan .seealso: `PetscObjectGetNewTag()`, `PetscCommDuplicate()`
62e5c89e4eSSatish Balay @*/
PetscCommGetNewTag(MPI_Comm comm,PetscMPIInt * tag)63d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscCommGetNewTag(MPI_Comm comm, PetscMPIInt *tag)
64d71ae5a4SJacob Faibussowitsch {
65480cf27aSJed Brown   PetscCommCounter *counter;
66480cf27aSJed Brown   PetscMPIInt      *maxval, flg;
67e5c89e4eSSatish Balay 
68e5c89e4eSSatish Balay   PetscFunctionBegin;
694f572ea9SToby Isaac   PetscAssertPointer(tag, 2);
70e5c89e4eSSatish Balay 
719566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_Counter_keyval, &counter, &flg));
7228b400f6SJacob Faibussowitsch   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "Bad MPI communicator supplied; must be a PETSc communicator");
73e5c89e4eSSatish Balay 
74480cf27aSJed Brown   if (counter->tag < 1) {
759566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Out of tags for object, starting to recycle. Comm reference count %" PetscInt_FMT "\n", counter->refcount));
769566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_get_attr(MPI_COMM_WORLD, MPI_TAG_UB, &maxval, &flg));
7728b400f6SJacob Faibussowitsch     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_LIB, "MPI error: MPI_Comm_get_attr() is not returning a MPI_TAG_UB");
78480cf27aSJed Brown     counter->tag = *maxval - 128; /* hope that any still active tags were issued right at the beginning of the run */
79e5c89e4eSSatish Balay   }
80e5c89e4eSSatish Balay 
81480cf27aSJed Brown   *tag = counter->tag--;
8276bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
83655f41cfSBarry Smith     /*
847b32b6dcSBarry Smith      Hanging here means that some processes have called PetscCommGetNewTag() and others have not.
85655f41cfSBarry Smith      */
869566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(comm));
8776bd3646SJed Brown   }
883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8964260623SMatthew Knepley }
9064260623SMatthew Knepley 
91e5c89e4eSSatish Balay /*@C
92811af0c4SBarry Smith   PetscCommGetComm - get a new MPI communicator from a PETSc communicator that can be passed off to another package
9357f21012SBarry Smith 
9457f21012SBarry Smith   Collective
9557f21012SBarry Smith 
9657f21012SBarry Smith   Input Parameter:
9757f21012SBarry Smith . comm_in - Input communicator
9857f21012SBarry Smith 
992fe279fdSBarry Smith   Output Parameter:
10057f21012SBarry Smith . comm_out - Output communicator
10157f21012SBarry Smith 
10221532e8aSBarry Smith   Level: developer
10321532e8aSBarry Smith 
10457f21012SBarry Smith   Notes:
105811af0c4SBarry Smith   Use `PetscCommRestoreComm()` to return the communicator when the external package no longer needs it
10657f21012SBarry Smith 
107811af0c4SBarry Smith   Certain MPI implementations have `MPI_Comm_free()` that do not work, thus one can run out of available MPI communicators causing
10857f21012SBarry Smith   mysterious crashes in the code after running a long time. This routine allows reusing previously obtained MPI communicators that
10957f21012SBarry Smith   are no longer needed.
11057f21012SBarry Smith 
111db781477SPatrick Sanan .seealso: `PetscObjectGetNewTag()`, `PetscCommGetNewTag()`, `PetscCommDestroy()`, `PetscCommRestoreComm()`
11257f21012SBarry Smith @*/
PetscCommGetComm(MPI_Comm comm_in,MPI_Comm * comm_out)113d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscCommGetComm(MPI_Comm comm_in, MPI_Comm *comm_out)
114d71ae5a4SJacob Faibussowitsch {
11557f21012SBarry Smith   PetscCommCounter *counter;
11657f21012SBarry Smith   PetscMPIInt       flg;
11757f21012SBarry Smith 
11857f21012SBarry Smith   PetscFunctionBegin;
1199566063dSJacob Faibussowitsch   PetscCall(PetscSpinlockLock(&PetscCommSpinLock));
1209566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_get_attr(comm_in, Petsc_Counter_keyval, &counter, &flg));
12128b400f6SJacob Faibussowitsch   PetscCheck(flg, comm_in, PETSC_ERR_ARG_WRONGSTATE, "Requires a PETSc communicator as input, do not use something like MPI_COMM_WORLD");
12257f21012SBarry Smith 
12357f21012SBarry Smith   if (counter->comms) {
12457f21012SBarry Smith     struct PetscCommStash *pcomms = counter->comms;
12557f21012SBarry Smith 
12657f21012SBarry Smith     *comm_out      = pcomms->comm;
12757f21012SBarry Smith     counter->comms = pcomms->next;
1289566063dSJacob Faibussowitsch     PetscCall(PetscFree(pcomms));
1299566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Reusing a communicator %ld %ld\n", (long)comm_in, (long)*comm_out));
13057f21012SBarry Smith   } else {
1319566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_dup(comm_in, comm_out));
13257f21012SBarry Smith   }
1339566063dSJacob Faibussowitsch   PetscCall(PetscSpinlockUnlock(&PetscCommSpinLock));
1343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13557f21012SBarry Smith }
13657f21012SBarry Smith 
13757f21012SBarry Smith /*@C
138811af0c4SBarry Smith   PetscCommRestoreComm - restores an MPI communicator that was obtained with `PetscCommGetComm()`
13957f21012SBarry Smith 
14057f21012SBarry Smith   Collective
14157f21012SBarry Smith 
14257f21012SBarry Smith   Input Parameters:
14357f21012SBarry Smith + comm_in  - Input communicator
14457f21012SBarry Smith - comm_out - returned communicator
14557f21012SBarry Smith 
14657f21012SBarry Smith   Level: developer
14757f21012SBarry Smith 
14842747ad1SJacob Faibussowitsch .seealso: `PetscObjectGetNewTag()`, `PetscCommGetNewTag()`, `PetscCommDestroy()`
14957f21012SBarry Smith @*/
PetscCommRestoreComm(MPI_Comm comm_in,MPI_Comm * comm_out)150d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscCommRestoreComm(MPI_Comm comm_in, MPI_Comm *comm_out)
151d71ae5a4SJacob Faibussowitsch {
15257f21012SBarry Smith   PetscCommCounter      *counter;
15357f21012SBarry Smith   PetscMPIInt            flg;
15457f21012SBarry Smith   struct PetscCommStash *pcomms, *ncomm;
15557f21012SBarry Smith 
15657f21012SBarry Smith   PetscFunctionBegin;
1579566063dSJacob Faibussowitsch   PetscCall(PetscSpinlockLock(&PetscCommSpinLock));
1589566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_get_attr(comm_in, Petsc_Counter_keyval, &counter, &flg));
15928b400f6SJacob Faibussowitsch   PetscCheck(flg, comm_in, PETSC_ERR_ARG_WRONGSTATE, "Requires a PETSc communicator as input, do not use something like MPI_COMM_WORLD");
16057f21012SBarry Smith 
1619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc(sizeof(struct PetscCommStash), &ncomm));
16257f21012SBarry Smith   ncomm->comm = *comm_out;
16357f21012SBarry Smith   ncomm->next = NULL;
16457f21012SBarry Smith   pcomms      = counter->comms;
16557f21012SBarry Smith   while (pcomms && pcomms->next) pcomms = pcomms->next;
16657f21012SBarry Smith   if (pcomms) {
16757f21012SBarry Smith     pcomms->next = ncomm;
16857f21012SBarry Smith   } else {
16957f21012SBarry Smith     counter->comms = ncomm;
17057f21012SBarry Smith   }
17157f21012SBarry Smith   *comm_out = 0;
1729566063dSJacob Faibussowitsch   PetscCall(PetscSpinlockUnlock(&PetscCommSpinLock));
1733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17457f21012SBarry Smith }
17557f21012SBarry Smith 
17657f21012SBarry Smith /*@C
1777b32b6dcSBarry Smith   PetscCommDuplicate - Duplicates the communicator only if it is not already a PETSc communicator.
178e5c89e4eSSatish Balay 
179d083f849SBarry Smith   Collective
180e5c89e4eSSatish Balay 
181f899ff85SJose E. Roman   Input Parameter:
182e5c89e4eSSatish Balay . comm_in - Input communicator
183e5c89e4eSSatish Balay 
184e5c89e4eSSatish Balay   Output Parameters:
18521532e8aSBarry Smith + comm_out  - Output communicator.  May be `comm_in`.
18621532e8aSBarry Smith - first_tag - Tag available that has not already been used with this communicator (you may pass in `NULL` if you do not need a tag)
187e5c89e4eSSatish Balay 
1882fe279fdSBarry Smith   Level: developer
1892fe279fdSBarry Smith 
190811af0c4SBarry Smith   Note:
191e5c89e4eSSatish Balay   PETSc communicators are just regular MPI communicators that keep track of which
192e5c89e4eSSatish Balay   tags have been used to prevent tag conflict. If you pass a non-PETSc communicator into
193a98fc643SBarry Smith   a PETSc creation routine it will attach a private communicator for use in the objects communications.
194811af0c4SBarry Smith   The internal `MPI_Comm` is used to perform all the MPI calls for PETSc, the outer `MPI_Comm` is a user
195648c30bcSBarry Smith   and is not used by PETSc.
196e5c89e4eSSatish Balay 
197db781477SPatrick Sanan .seealso: `PetscObjectGetNewTag()`, `PetscCommGetNewTag()`, `PetscCommDestroy()`
198e5c89e4eSSatish Balay @*/
PetscCommDuplicate(MPI_Comm comm_in,MPI_Comm * comm_out,PetscMPIInt * first_tag)199d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscCommDuplicate(MPI_Comm comm_in, MPI_Comm *comm_out, PetscMPIInt *first_tag)
200d71ae5a4SJacob Faibussowitsch {
20162e5d2d2SJDBetteridge   PetscInt64       *cidx;
202480cf27aSJed Brown   PetscCommCounter *counter;
203480cf27aSJed Brown   PetscMPIInt      *maxval, flg;
204e5c89e4eSSatish Balay 
205e5c89e4eSSatish Balay   PetscFunctionBegin;
2069566063dSJacob Faibussowitsch   PetscCall(PetscSpinlockLock(&PetscCommSpinLock));
2079566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_get_attr(comm_in, Petsc_Counter_keyval, &counter, &flg));
208e5c89e4eSSatish Balay 
2097b32b6dcSBarry Smith   if (!flg) { /* this is NOT a PETSc comm */
2109371c9d4SSatish Balay     union
2119371c9d4SSatish Balay     {
2129371c9d4SSatish Balay       MPI_Comm comm;
2139371c9d4SSatish Balay       void    *ptr;
2149371c9d4SSatish Balay     } ucomm;
2156aad120cSJose E. Roman     /* check if this communicator has a PETSc communicator embedded in it */
2169566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_get_attr(comm_in, Petsc_InnerComm_keyval, &ucomm, &flg));
217e5c89e4eSSatish Balay     if (!flg) {
2187b32b6dcSBarry Smith       /* This communicator is not yet known to this system, so we duplicate it and make an internal communicator */
2199566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_dup(comm_in, comm_out));
2209566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_get_attr(MPI_COMM_WORLD, MPI_TAG_UB, &maxval, &flg));
22128b400f6SJacob Faibussowitsch       PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_LIB, "MPI error: MPI_Comm_get_attr() is not returning a MPI_TAG_UB");
2229566063dSJacob Faibussowitsch       PetscCall(PetscNew(&counter)); /* all fields of counter are zero'ed */
223480cf27aSJed Brown       counter->tag = *maxval;
2249566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_set_attr(*comm_out, Petsc_Counter_keyval, counter));
22562e5d2d2SJDBetteridge       /* Add an object creation index to the communicator */
22662e5d2d2SJDBetteridge       PetscCall(PetscNew(&cidx));
22762e5d2d2SJDBetteridge       PetscCallMPI(MPI_Comm_set_attr(*comm_out, Petsc_CreationIdx_keyval, cidx));
2289566063dSJacob Faibussowitsch       PetscCall(PetscInfo(NULL, "Duplicating a communicator %ld %ld max tags = %d\n", (long)comm_in, (long)*comm_out, *maxval));
229e5c89e4eSSatish Balay 
230e5c89e4eSSatish Balay       /* save PETSc communicator inside user communicator, so we can get it next time */
231265f3f35SJed Brown       ucomm.comm = *comm_out; /* ONLY the comm part of the union is significant. */
2329566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_set_attr(comm_in, Petsc_InnerComm_keyval, ucomm.ptr));
233265f3f35SJed Brown       ucomm.comm = comm_in;
2349566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_set_attr(*comm_out, Petsc_OuterComm_keyval, ucomm.ptr));
235e5c89e4eSSatish Balay     } else {
236265f3f35SJed Brown       *comm_out = ucomm.comm;
2377b32b6dcSBarry Smith       /* pull out the inner MPI_Comm and hand it back to the caller */
2389566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_get_attr(*comm_out, Petsc_Counter_keyval, &counter, &flg));
23928b400f6SJacob Faibussowitsch       PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inner PETSc communicator does not have its tag/name counter attribute set");
2409566063dSJacob Faibussowitsch       PetscCall(PetscInfo(NULL, "Using internal PETSc communicator %ld %ld\n", (long)comm_in, (long)*comm_out));
241e5c89e4eSSatish Balay     }
242a297a907SKarl Rupp   } else *comm_out = comm_in;
2433f34d28cSBarry Smith 
24476bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
2453f34d28cSBarry Smith     /*
2463f34d28cSBarry Smith      Hanging here means that some processes have called PetscCommDuplicate() and others have not.
2476aad120cSJose E. Roman      This likely means that a subset of processes in a MPI_Comm have attempted to create a PetscObject!
2483f34d28cSBarry Smith      ALL processes that share a communicator MUST shared objects created from that communicator.
2493f34d28cSBarry Smith      */
2509566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(comm_in));
25176bd3646SJed Brown   }
252e5c89e4eSSatish Balay 
253480cf27aSJed Brown   if (counter->tag < 1) {
2549566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Out of tags for object, starting to recycle. Comm reference count %" PetscInt_FMT "\n", counter->refcount));
2559566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_get_attr(MPI_COMM_WORLD, MPI_TAG_UB, &maxval, &flg));
25628b400f6SJacob Faibussowitsch     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_LIB, "MPI error: MPI_Comm_get_attr() is not returning a MPI_TAG_UB");
257480cf27aSJed Brown     counter->tag = *maxval - 128; /* hope that any still active tags were issued right at the beginning of the run */
258e5c89e4eSSatish Balay   }
259e5c89e4eSSatish Balay 
260a297a907SKarl Rupp   if (first_tag) *first_tag = counter->tag--;
2615ef7c072SBarry Smith 
2625c25fcd7SBarry Smith   counter->refcount++; /* number of references to this comm */
2639566063dSJacob Faibussowitsch   PetscCall(PetscSpinlockUnlock(&PetscCommSpinLock));
2643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
265e5c89e4eSSatish Balay }
266e5c89e4eSSatish Balay 
267e5c89e4eSSatish Balay /*@C
268811af0c4SBarry Smith   PetscCommDestroy - Frees communicator obtained with `PetscCommDuplicate()`.
269e5c89e4eSSatish Balay 
270d083f849SBarry Smith   Collective
271e5c89e4eSSatish Balay 
272e5c89e4eSSatish Balay   Input Parameter:
273e5c89e4eSSatish Balay . comm - the communicator to free
274e5c89e4eSSatish Balay 
275e5c89e4eSSatish Balay   Level: developer
276e5c89e4eSSatish Balay 
277648c30bcSBarry Smith   Notes:
278648c30bcSBarry Smith   Sets `comm` to `NULL`
279648c30bcSBarry Smith 
280648c30bcSBarry Smith   The communicator is reference counted so it is only truly removed from the system when its reference count drops to zero
281648c30bcSBarry Smith 
282db781477SPatrick Sanan .seealso: `PetscCommDuplicate()`
283e5c89e4eSSatish Balay @*/
PetscCommDestroy(MPI_Comm * comm)284d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscCommDestroy(MPI_Comm *comm)
285d71ae5a4SJacob Faibussowitsch {
28662e5d2d2SJDBetteridge   PetscInt64       *cidx;
287480cf27aSJed Brown   PetscCommCounter *counter;
288480cf27aSJed Brown   PetscMPIInt       flg;
28962e5d2d2SJDBetteridge   PetscGarbage      garbage;
290e5c89e4eSSatish Balay   MPI_Comm          icomm = *comm, ocomm;
2919371c9d4SSatish Balay   union
2929371c9d4SSatish Balay   {
2939371c9d4SSatish Balay     MPI_Comm comm;
2949371c9d4SSatish Balay     void    *ptr;
2959371c9d4SSatish Balay   } ucomm;
296e5c89e4eSSatish Balay 
297e5c89e4eSSatish Balay   PetscFunctionBegin;
2983ba16761SJacob Faibussowitsch   if (*comm == MPI_COMM_NULL) PetscFunctionReturn(PETSC_SUCCESS);
2999566063dSJacob Faibussowitsch   PetscCall(PetscSpinlockLock(&PetscCommSpinLock));
3009566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_get_attr(icomm, Petsc_Counter_keyval, &counter, &flg));
3017b32b6dcSBarry Smith   if (!flg) { /* not a PETSc comm, check if it has an inner comm */
3029566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_get_attr(icomm, Petsc_InnerComm_keyval, &ucomm, &flg));
30328b400f6SJacob Faibussowitsch     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "MPI_Comm does not have tag/name counter nor does it have inner MPI_Comm");
304265f3f35SJed Brown     icomm = ucomm.comm;
3059566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_get_attr(icomm, Petsc_Counter_keyval, &counter, &flg));
30628b400f6SJacob Faibussowitsch     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "Inner MPI_Comm does not have expected tag/name counter, problem with corrupted memory");
307e5c89e4eSSatish Balay   }
3085c25fcd7SBarry Smith   counter->refcount--;
309e93c322dSShri Abhyankar   if (!counter->refcount) {
310b3ef52cdSBarry Smith     /* if MPI_Comm has outer comm then remove reference to inner MPI_Comm from outer MPI_Comm */
3119566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_get_attr(icomm, Petsc_OuterComm_keyval, &ucomm, &flg));
312dbc8283eSBarry Smith     if (flg) {
313265f3f35SJed Brown       ocomm = ucomm.comm;
3149566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_get_attr(ocomm, Petsc_InnerComm_keyval, &ucomm, &flg));
3150e6b6b59SJacob Faibussowitsch       PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "Outer MPI_Comm %ld does not have expected reference to inner comm %ld, problem with corrupted memory", (long int)ocomm, (long int)icomm);
3169566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_delete_attr(ocomm, Petsc_InnerComm_keyval));
317e5c89e4eSSatish Balay     }
318e5c89e4eSSatish Balay 
31962e5d2d2SJDBetteridge     /* Remove the object creation index on the communicator */
32062e5d2d2SJDBetteridge     PetscCallMPI(MPI_Comm_get_attr(icomm, Petsc_CreationIdx_keyval, &cidx, &flg));
321*966bd95aSPierre Jolivet     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "MPI_Comm does not have object creation index");
32262e5d2d2SJDBetteridge     PetscCall(PetscFree(cidx));
32362e5d2d2SJDBetteridge 
32462e5d2d2SJDBetteridge     /* Remove garbage hashmap set up by garbage collection */
32562e5d2d2SJDBetteridge     PetscCallMPI(MPI_Comm_get_attr(icomm, Petsc_Garbage_HMap_keyval, &garbage, &flg));
32662e5d2d2SJDBetteridge     if (flg) {
32762e5d2d2SJDBetteridge       PetscInt entries = 0;
32862e5d2d2SJDBetteridge       PetscCall(PetscHMapObjGetSize(garbage.map, &entries));
32962e5d2d2SJDBetteridge       if (entries > 0) PetscCall(PetscGarbageCleanup(icomm));
330f4f49eeaSPierre Jolivet       PetscCall(PetscHMapObjDestroy(&garbage.map));
33162e5d2d2SJDBetteridge     }
33262e5d2d2SJDBetteridge 
3339566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Deleting PETSc MPI_Comm %ld\n", (long)icomm));
3349566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_free(&icomm));
335e5c89e4eSSatish Balay   }
336542323b1SJed Brown   *comm = MPI_COMM_NULL;
3379566063dSJacob Faibussowitsch   PetscCall(PetscSpinlockUnlock(&PetscCommSpinLock));
3383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
339e5c89e4eSSatish Balay }
340e5c89e4eSSatish Balay 
34176270f95SDmitry Karpeev /*@C
3429abe469cSDmitry Karpeev   PetscObjectsListGetGlobalNumbering - computes a global numbering
343811af0c4SBarry Smith   of `PetscObject`s living on subcommunicators of a given communicator.
34476270f95SDmitry Karpeev 
345d083f849SBarry Smith   Collective.
34676270f95SDmitry Karpeev 
34776270f95SDmitry Karpeev   Input Parameters:
348811af0c4SBarry Smith + comm    - the `MPI_Comm`
34921532e8aSBarry Smith . len     - local length of `objlist`
3509abe469cSDmitry Karpeev - objlist - a list of PETSc objects living on subcomms of comm and containing this comm rank
3519abe469cSDmitry Karpeev               (subcomm ordering is assumed to be deadlock-free)
35276270f95SDmitry Karpeev 
35376270f95SDmitry Karpeev   Output Parameters:
35426a11704SBarry Smith + count     - global number of distinct subcommunicators on objlist (may be > `len`)
3559abe469cSDmitry Karpeev - numbering - global numbers of objlist entries (allocated by user)
35676270f95SDmitry Karpeev 
35776270f95SDmitry Karpeev   Level: developer
35876270f95SDmitry Karpeev 
359811af0c4SBarry Smith   Note:
360811af0c4SBarry Smith   This is needed when PETSc is used with certain languages that do garbage collection to manage object life cycles.
361811af0c4SBarry Smith 
36210450e9eSJacob Faibussowitsch .seealso: `PetscCommDuplicate()`, `PetscObjectDestroy()`
36376270f95SDmitry Karpeev @*/
PetscObjectsListGetGlobalNumbering(MPI_Comm comm,PetscInt len,PetscObject objlist[],PetscInt * count,PetscInt * numbering)3649c9354e5SBarry Smith PetscErrorCode PetscObjectsListGetGlobalNumbering(MPI_Comm comm, PetscInt len, PetscObject objlist[], PetscInt *count, PetscInt *numbering)
365d71ae5a4SJacob Faibussowitsch {
36676270f95SDmitry Karpeev   PetscInt    i, roots, offset;
3674924a606SDmitry Karpeev   PetscMPIInt size, rank;
3685fd66863SKarl Rupp 
36976270f95SDmitry Karpeev   PetscFunctionBegin;
3704f572ea9SToby Isaac   PetscAssertPointer(objlist, 3);
3713ba16761SJacob Faibussowitsch   if (!count && !numbering) PetscFunctionReturn(PETSC_SUCCESS);
3729abe469cSDmitry Karpeev 
3739566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
3749566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
37576270f95SDmitry Karpeev   roots = 0;
37676270f95SDmitry Karpeev   for (i = 0; i < len; ++i) {
3774924a606SDmitry Karpeev     PetscMPIInt srank;
3789566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(objlist[i]->comm, &srank));
37976270f95SDmitry Karpeev     /* Am I the root of the i-th subcomm? */
3804924a606SDmitry Karpeev     if (!srank) ++roots;
38176270f95SDmitry Karpeev   }
3829abe469cSDmitry Karpeev   if (count) {
38376270f95SDmitry Karpeev     /* Obtain the sum of all roots -- the global number of distinct subcomms. */
384462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&roots, count, 1, MPIU_INT, MPI_SUM, comm));
3859abe469cSDmitry Karpeev   }
3869abe469cSDmitry Karpeev   if (numbering) {
3879abe469cSDmitry Karpeev     /* Introduce a global numbering for subcomms, initially known only by subcomm roots. */
38876270f95SDmitry Karpeev     /*
3896e4e7d8dSDmitry Karpeev       At each subcomm root number all of the subcomms it owns locally
3906e4e7d8dSDmitry Karpeev       and make it global by calculating the shift among all of the roots.
3916e4e7d8dSDmitry Karpeev       The roots are ordered using the comm ordering.
39276270f95SDmitry Karpeev     */
3939566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&roots, &offset, 1, MPIU_INT, MPI_SUM, comm));
39476270f95SDmitry Karpeev     offset -= roots;
3954924a606SDmitry Karpeev     /* Now we are ready to broadcast global subcomm numbers within each subcomm.*/
3966a4f0f73SDmitry Karpeev     /*
3974924a606SDmitry Karpeev       This is where the assumption of a deadlock-free ordering of the subcomms is assumed:
3984924a606SDmitry Karpeev       broadcast is collective on the subcomm.
3996a4f0f73SDmitry Karpeev     */
4004bde246dSDmitry Karpeev     roots = 0;
40176270f95SDmitry Karpeev     for (i = 0; i < len; ++i) {
4024924a606SDmitry Karpeev       PetscMPIInt srank;
4034924a606SDmitry Karpeev       numbering[i] = offset + roots; /* only meaningful if !srank. */
404a297a907SKarl Rupp 
4059566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(objlist[i]->comm, &srank));
4069566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Bcast(numbering + i, 1, MPIU_INT, 0, objlist[i]->comm));
4074924a606SDmitry Karpeev       if (!srank) ++roots;
4086a4f0f73SDmitry Karpeev     }
4099abe469cSDmitry Karpeev   }
4103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
41176270f95SDmitry Karpeev }
412