Actual source code: destroy.c

  1: /*
  2:      Provides utility routines for manulating any type of PETSc object.
  3: */
  4: #include <petsc/private/petscimpl.h>
  5: #include <petscviewer.h>

  7: static PetscErrorCode DestroyComposedData(void ***composed_star, PetscObjectState **state_star, PetscInt *count_star, void **composed, PetscObjectState **state)
  8: {
  9:   void **tmp_star = *composed_star;

 11:   PetscFunctionBegin;
 12:   for (PetscInt i = 0, imax = *count_star; i < imax; ++i) PetscCall(PetscFree(tmp_star[i]));
 13:   PetscCall(PetscFree2(*composed_star, *state_star));
 14:   PetscCall(PetscFree2(*composed, *state));
 15:   *count_star = 0;
 16:   PetscFunctionReturn(PETSC_SUCCESS);
 17: }

 19: PetscErrorCode PetscComposedQuantitiesDestroy(PetscObject obj)
 20: {
 21:   PetscFunctionBegin;
 23:   PetscCall(DestroyComposedData((void ***)&obj->intstarcomposeddata, &obj->intstarcomposedstate, &obj->intstar_idmax, (void **)&obj->intcomposeddata, &obj->intcomposedstate));
 24:   PetscCall(DestroyComposedData((void ***)&obj->realstarcomposeddata, &obj->realstarcomposedstate, &obj->realstar_idmax, (void **)&obj->realcomposeddata, &obj->realcomposedstate));
 25: #if PetscDefined(USE_COMPLEX)
 26:   PetscCall(DestroyComposedData((void ***)&obj->scalarstarcomposeddata, &obj->scalarstarcomposedstate, &obj->scalarstar_idmax, (void **)&obj->scalarcomposeddata, &obj->scalarcomposedstate));
 27: #endif
 28:   PetscFunctionReturn(PETSC_SUCCESS);
 29: }

 31: /*@
 32:   PetscObjectDestroy - Destroys a `PetscObject`, regardless of the class.

 34:   Collective

 36:   Input Parameter:
 37: . obj - any PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`\*), for example,
 38:         `PetscObjectDestroy`((`PetscObject`\*)&mat);

 40:   Level: beginner

 42: .seealso: `PetscObject`
 43: @*/
 44: PetscErrorCode PetscObjectDestroy(PetscObject *obj)
 45: {
 46:   PetscFunctionBegin;
 47:   if (!obj || !*obj) PetscFunctionReturn(PETSC_SUCCESS);
 49:   PetscCheck((*obj)->bops->destroy, PETSC_COMM_SELF, PETSC_ERR_PLIB, "This PETSc object of class %s does not have a generic destroy routine", (*obj)->class_name);
 50:   PetscCall((*(*obj)->bops->destroy)(obj));
 51:   PetscFunctionReturn(PETSC_SUCCESS);
 52: }

 54: /*@
 55:   PetscObjectView - Views, that is displays or stores information about a `PetscObject`.

 57:   Collective

 59:   Input Parameters:
 60: + obj    - any PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`), for example,
 61:            `PetscObjectView`((`PetscObject`)mat,`viewer`);
 62: - viewer - any PETSc viewer

 64:   Level: intermediate

 66: .seealso: `PetscObject`, `PetscObjectViewFromOptions()`, `PetscViewer`
 67: @*/
 68: PetscErrorCode PetscObjectView(PetscObject obj, PetscViewer viewer)
 69: {
 70:   PetscFunctionBegin;
 72:   PetscCheck(obj->bops->view, PETSC_COMM_SELF, PETSC_ERR_SUP, "This PETSc object does not have a generic viewer routine");
 73:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(obj->comm, &viewer));

 76:   PetscCall((*obj->bops->view)(obj, viewer));
 77:   PetscFunctionReturn(PETSC_SUCCESS);
 78: }

 80: /*@
 81:   PetscObjectViewFromOptions - Processes command line options to determine if/how a `PetscObject` is to be viewed.

 83:   Collective

 85:   Input Parameters:
 86: + obj  - the object
 87: . bobj - optional other object that provides prefix (if `NULL` then the prefix in `obj` is used)
 88: - name - option string that is used to activate viewing. It typically ends with _view.

 90:   Options Database Key:
 91: . -name [viewertype][:...] - option name and values. In actual usage the key might be something like `-vec_view`

 93:   Level: developer

 95:   Notes:
 96:   For a `viewertype` that represents files, including `ascii`, `binary`, `matlab`, `vu`, `vtk`, `glvis`, `cgns`, and `hdf5`, the argument has the following form
 97: .vb
 98:     viewertype[:filename[:format[:filemode]]]
 99: .ve
100:   where all parts are optional, but you need to include the colon to access the next part.
101:   `filename` is the name of the file where the object data will be stored. `format` is the string name
102:   of a `PetscViewerFormat`, for example, `default` or `ascii_info`. `filemode` can be `append` to indicate the file named `filename` should be appended
103:   to and not replaced, while `read` indicates the file is for reading.

105:   For example, to read from an HDF5 file, use
106: .vb
107:     hdf5:sol.h5::read
108: .ve

110:   For a `viewertype` of `draw` the argument is of the form
111: .vb
112:   draw[:drawtype[:filename]]
113: .ve
114:   where `drawtype` is, for example, `tikz` or `x` and `filename` indicates where the data is to be saved if it is not directly displayed.

116:   Other formats, such as
117: .vb
118:   socket[:port]
119:   saws[:communicatorname]
120: .ve
121:   that send the data to a Unix socket or publish the object to the Scientific Application Webserver (SAWs) exist.

123:   If no value is provided `ascii:stdout` is used

125:   This function is usually not called directly but is called by, for example, `MatViewFromOptions()`.

127: .seealso: `PetscObject`, `PetscObjectViewSynchronizedFromOptions()`, `PetscObjectView()`, `PetscOptionsCreateViewer()`
128: @*/
129: PetscErrorCode PetscObjectViewFromOptions(PetscObject obj, PetscObject bobj, const char name[])
130: {
131:   PetscViewer       viewer;
132:   PetscBool         flg;
133:   static PetscBool  incall = PETSC_FALSE;
134:   PetscViewerFormat format;
135:   const char       *prefix;

137:   PetscFunctionBegin;
140:   if (incall) PetscFunctionReturn(PETSC_SUCCESS);
141:   incall = PETSC_TRUE;
142:   prefix = bobj ? bobj->prefix : obj->prefix;
143:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm(obj), obj->options, prefix, name, &viewer, &format, &flg));
144:   if (flg) {
145:     PetscCall(PetscViewerPushFormat(viewer, format));
146:     PetscCall(PetscObjectView(obj, viewer));
147:     PetscCall(PetscViewerFlush(viewer));
148:     PetscCall(PetscViewerPopFormat(viewer));
149:     PetscCall(PetscViewerDestroy(&viewer));
150:   }
151:   incall = PETSC_FALSE;
152:   PetscFunctionReturn(PETSC_SUCCESS);
153: }

155: /*@
156:   PetscObjectViewSynchronizedFromOptions - Processes command line options to determine if/how a serial `PetscObject` is to be collectively viewed.

158:   Collective

160:   Input Parameters:
161: + obj  - the serial object
162: . sobj - synchronization object that provides the synchronizing communicator
163: - name - option string that is used to activate viewing. It typically ends with _view.

165:   Options Database Key:
166: . -name [viewertype][:...] - option name and values. In actual usage the key might be something like `-vec_view`

168:   Level: developer

170:   Notes:
171:   The objects will be viewed in sequence, following the MPI rank order.

173:   For a `viewertype` that represents files, including `ascii`, `binary`, `matlab`, `vu`, `vtk`, `glvis`, `cgns`, and `hdf5`, the argument has the following form
174: .vb
175:     viewertype[:filename[:format[:filemode]]]
176: .ve
177:   where all parts are optional, but you need to include the colon to access the next part.
178:   `filename` is the name of the file where the object data will be stored. `format` is the string name
179:   of a `PetscViewerFormat`, for example, `default` or `ascii_info`. `filemode` can be `append` to indicate the file named `filename` should be appended
180:   to and not replaced, while `read` indicates the file is for reading.

182:   For example, to read from an HDF5 file, use
183: .vb
184:     hdf5:sol.h5::read
185: .ve

187:   For a `viewertype` of `draw` the argument is of the form
188: .vb
189:   draw[:drawtype[:filename]]
190: .ve
191:   where `drawtype` is, for example, `tikz` or `x` and `filename` indicates where the data is to be saved if it is not directly displayed.

193:   Other formats, such as
194: .vb
195:   socket[:port]
196:   saws[:communicatorname]
197: .ve
198:   that send the data to a Unix socket or publish the object to the Scientific Application Webserver (SAWs) exist.

200:   If no value is provided `ascii:stdout` is used

202:   This function is usually not called directly but is called by, for example, `MatViewFromOptions()`.

204: .seealso: `PetscObject`, `PetscObjectViewFromOptions()`, `PetscObjectView()`, `PetscOptionsCreateViewer()`
205: @*/
206: PetscErrorCode PetscObjectViewSynchronizedFromOptions(PetscObject obj, PetscObject sobj, const char name[])
207: {
208:   PetscViewer       viewer;
209:   PetscBool         flg;
210:   static PetscBool  incall = PETSC_FALSE;
211:   PetscViewerFormat format;

213:   PetscFunctionBegin;
216:   if (incall) PetscFunctionReturn(PETSC_SUCCESS);
217:   incall = PETSC_TRUE;
218:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm(sobj), obj->options, obj->prefix, name, &viewer, &format, &flg));
219:   if (flg) {
220:     PetscViewer selfviewer;

222:     PetscCall(PetscViewerPushFormat(viewer, format));
223:     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
224:     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &selfviewer));
225:     PetscCall(PetscObjectView(obj, selfviewer));
226:     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &selfviewer));
227:     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
228:     PetscCall(PetscViewerFlush(viewer));
229:     PetscCall(PetscViewerPopFormat(viewer));
230:     PetscCall(PetscViewerDestroy(&viewer));
231:   }
232:   incall = PETSC_FALSE;
233:   PetscFunctionReturn(PETSC_SUCCESS);
234: }

236: /*@
237:   PetscObjectTypeCompare - Determines whether a PETSc object is of a particular type.

239:   Not Collective

241:   Input Parameters:
242: + obj       - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`), for example,
243:               `PetscObjectTypeCompare`((`PetscObject`)mat);
244: - type_name - string containing a type name

246:   Output Parameter:
247: . same - `PETSC_TRUE` if the type of `obj` and `type_name` are the same or both `NULL`, else `PETSC_FALSE`

249:   Level: intermediate

251: .seealso: `PetscObject`, `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`, `PetscObjectObjectTypeCompare()`
252: @*/
253: PetscErrorCode PetscObjectTypeCompare(PetscObject obj, const char type_name[], PetscBool *same)
254: {
255:   PetscFunctionBegin;
256:   PetscAssertPointer(same, 3);
257:   if (!obj) *same = (PetscBool)!type_name;
258:   else {
260:     if (!type_name || !obj->type_name) *same = (PetscBool)(!obj->type_name == !type_name);
261:     else {
262:       PetscAssertPointer(type_name, 2);
263:       PetscCall(PetscStrcmp(obj->type_name, type_name, same));
264:     }
265:   }
266:   PetscFunctionReturn(PETSC_SUCCESS);
267: }

269: /*@
270:   PetscObjectObjectTypeCompare - Determines whether two PETSc objects are of the same type

272:   Logically Collective

274:   Input Parameters:
275: + obj1 - any PETSc object, for example a `Vec`, `Mat` or `KSP`.
276: - obj2 - another PETSc object

278:   Output Parameter:
279: . same - `PETSC_TRUE` if they are the same or both unset, else `PETSC_FALSE`

281:   Level: intermediate

283:   Note:
284:   Both objects must be of the same class, for example both `Vec` objects.

286: .seealso: `PetscObjectTypeCompare()`, `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`
287: @*/
288: PetscErrorCode PetscObjectObjectTypeCompare(PetscObject obj1, PetscObject obj2, PetscBool *same)
289: {
290:   PetscFunctionBegin;
293:   PetscAssertPointer(same, 3);
294:   PetscCall(PetscStrcmp(obj1->type_name, obj2->type_name, same));
295:   PetscFunctionReturn(PETSC_SUCCESS);
296: }

298: /*@
299:   PetscObjectBaseTypeCompare - Determines whether a `PetscObject` is of a given base type. For example the base type of `MATSEQAIJPERM` is `MATSEQAIJ`

301:   Not Collective

303:   Input Parameters:
304: + obj       - the object
305: - type_name - string containing a type name

307:   Output Parameter:
308: . same - `PETSC_TRUE` if the object is of the same base type identified by `type_name` or both `NULL`, `PETSC_FALSE` otherwise

310:   Level: intermediate

312: .seealso: `PetscObject`, `PetscObjectTypeCompare()`, `PetscObjectTypeCompareAny()`, `PetscObjectBaseTypeCompareAny()`
313: @*/
314: PetscErrorCode PetscObjectBaseTypeCompare(PetscObject obj, const char type_name[], PetscBool *same)
315: {
316:   PetscFunctionBegin;
317:   PetscAssertPointer(same, 3);
318:   if (!obj) *same = (PetscBool)!type_name;
319:   else {
321:     if (!type_name || !obj->type_name) *same = (PetscBool)(!obj->type_name == !type_name);
322:     else {
323:       PetscAssertPointer(type_name, 2);
324:       PetscCall(PetscStrbeginswith(obj->type_name, type_name, same));
325:     }
326:   }
327:   PetscFunctionReturn(PETSC_SUCCESS);
328: }

330: /*@C
331:   PetscObjectTypeCompareAny - Determines whether a PETSc object is of any of a list of types.

333:   Not Collective

335:   Input Parameters:
336: + obj       - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`),
337:               for example, `PetscObjectTypeCompareAny`((`PetscObject`)mat,...);
338: - type_name - one or more string arguments containing type names, pass the empty string "" as the last argument

340:   Output Parameter:
341: . match - `PETSC_TRUE` if the type of `obj` matches any in the list, else `PETSC_FALSE`

343:   Level: intermediate

345: .seealso: `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectTypeCompare()`, `PetscObjectBaseTypeCompare()`
346: @*/
347: PetscErrorCode PetscObjectTypeCompareAny(PetscObject obj, PetscBool *match, const char type_name[], ...)
348: {
349:   va_list Argp;

351:   PetscFunctionBegin;
352:   PetscAssertPointer(match, 2);
353:   *match = PETSC_FALSE;
354:   if (!obj) PetscFunctionReturn(PETSC_SUCCESS);
355:   va_start(Argp, type_name);
356:   while (type_name && type_name[0]) {
357:     PetscBool found;
358:     PetscCall(PetscObjectTypeCompare(obj, type_name, &found));
359:     if (found) {
360:       *match = PETSC_TRUE;
361:       break;
362:     }
363:     type_name = va_arg(Argp, const char *);
364:   }
365:   va_end(Argp);
366:   PetscFunctionReturn(PETSC_SUCCESS);
367: }

369: /*@C
370:   PetscObjectBaseTypeCompareAny - Determines whether a PETSc object has the base type of any of a list of types.

372:   Not Collective

374:   Input Parameters:
375: + obj       - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`),
376:               for example, `PetscObjectBaseTypeCompareAny`((`PetscObject`)mat,...);
377: - type_name - one or more string arguments containing type names, pass the empty string "" as the last argument

379:   Output Parameter:
380: . match - `PETSC_TRUE` if the type of `obj` matches any in the list, else `PETSC_FALSE`

382:   Level: intermediate

384: .seealso: `VecGetType()`, `KSPGetType()`, `PCGetType()`, `SNESGetType()`, `PetscObjectTypeCompare()`, `PetscObjectBaseTypeCompare()`, `PetscObjectTypeCompareAny()`
385: @*/
386: PetscErrorCode PetscObjectBaseTypeCompareAny(PetscObject obj, PetscBool *match, const char type_name[], ...)
387: {
388:   va_list Argp;

390:   PetscFunctionBegin;
391:   PetscAssertPointer(match, 2);
392:   *match = PETSC_FALSE;
393:   va_start(Argp, type_name);
394:   while (type_name && type_name[0]) {
395:     PetscBool found;
396:     PetscCall(PetscObjectBaseTypeCompare(obj, type_name, &found));
397:     if (found) {
398:       *match = PETSC_TRUE;
399:       break;
400:     }
401:     type_name = va_arg(Argp, const char *);
402:   }
403:   va_end(Argp);
404:   PetscFunctionReturn(PETSC_SUCCESS);
405: }

407: typedef struct {
408:   PetscErrorCode (*func)(void);
409: } PetscFinalizeFunction;

411: typedef struct {
412:   PetscErrorCode (*func)(void *);
413:   PetscCtx ctx;
414: } PetscFinalizeFunctionWithCtx;

416: typedef enum {
417:   PETSC_FINALIZE_EMPTY,
418:   PETSC_FINALIZE_OBJECT,
419:   PETSC_FINALIZE_FUNC,
420:   PETSC_FINALIZE_FUNC_WITH_CTX
421: } PetscFinalizeType;

423: static const char *const PetscFinalizeTypes[] = {"PETSC_FINALIZE_EMPTY", "PETSC_FINALIZE_OBJECT", "PETSC_FINALIZE_FUNC", "PETSC_FINALIZE_FUNC_WITH_CTX", PETSC_NULLPTR};

425: typedef struct {
426:   union ThunkUnion
427:   {
428:     PetscObject                  obj;
429:     PetscFinalizeFunction        fn;
430:     PetscFinalizeFunctionWithCtx fnctx;
431:   } thunk;
432:   PetscFinalizeType type;
433: } PetscFinalizerContainer;

435: #define PETSC_MAX_REGISTERED_FINALIZERS 256
436: static int                     reg_count = 0;
437: static PetscFinalizerContainer regfin[PETSC_MAX_REGISTERED_FINALIZERS];

439: static PetscErrorCode PetscRunRegisteredFinalizers(void)
440: {
441:   PetscFunctionBegin;
442:   while (reg_count) {
443:     PetscFinalizerContainer top = regfin[--reg_count];

445:     regfin[reg_count].type = PETSC_FINALIZE_EMPTY;
446:     PetscCall(PetscArrayzero(&regfin[reg_count].thunk, 1));
447:     switch (top.type) {
448:     case PETSC_FINALIZE_OBJECT:
449:       PetscCall(PetscObjectDestroy(&top.thunk.obj));
450:       break;
451:     case PETSC_FINALIZE_FUNC:
452:       PetscCall((*top.thunk.fn.func)());
453:       break;
454:     case PETSC_FINALIZE_FUNC_WITH_CTX:
455:       PetscCall((*top.thunk.fnctx.func)(top.thunk.fnctx.ctx));
456:       break;
457:     case PETSC_FINALIZE_EMPTY:
458:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Finalizer at position %d is empty, yet registration count %d != 0", reg_count, reg_count);
459:       break;
460:     }
461:   }
462:   PetscFunctionReturn(PETSC_SUCCESS);
463: }

465: static int PetscFinalizerContainerEqual(const PetscFinalizerContainer *a, const PetscFinalizerContainer *b)
466: {
467:   if (a->type != b->type) return 0;
468:   switch (a->type) {
469:   case PETSC_FINALIZE_EMPTY:
470:     break;
471:   case PETSC_FINALIZE_OBJECT:
472:     return a->thunk.obj == b->thunk.obj;
473:   case PETSC_FINALIZE_FUNC:
474:     return a->thunk.fn.func == b->thunk.fn.func;
475:   case PETSC_FINALIZE_FUNC_WITH_CTX:
476:     return a->thunk.fnctx.func == b->thunk.fnctx.func && a->thunk.fnctx.ctx == b->thunk.fnctx.ctx;
477:   }
478:   return 1;
479: }

481: static PetscErrorCode RegisterFinalizer(PetscFinalizerContainer container)
482: {
483:   PetscFunctionBegin;
484:   PetscAssert(reg_count < (int)PETSC_STATIC_ARRAY_LENGTH(regfin), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "No more room in array, limit %zu, recompile %s with larger value for " PetscStringize(regfin), PETSC_STATIC_ARRAY_LENGTH(regfin), __FILE__);
485:   PetscAssert(regfin[reg_count].type == PETSC_FINALIZE_EMPTY, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Finalizer type (%s) at position %d is not PETSC_FINALIZE_EMPTY!", PetscFinalizeTypes[regfin[reg_count].type], reg_count);
486:   if (PetscDefined(USE_DEBUG)) {
487:     for (int i = 0; i < reg_count; ++i) PetscCheck(!PetscFinalizerContainerEqual(regfin + i, &container), PETSC_COMM_SELF, PETSC_ERR_ORDER, "Finalizer (of type %s) already registered!", PetscFinalizeTypes[container.type]);
488:   }
489:   regfin[reg_count++] = container;
490:   PetscFunctionReturn(PETSC_SUCCESS);
491: }

493: /*@
494:   PetscObjectRegisterDestroy - Registers a PETSc object to be destroyed when
495:   `PetscFinalize()` is called.

497:   Logically Collective

499:   Input Parameter:
500: . obj - a PETSc object, for example a `Vec`, `Mat` or `KSP`. It must be cast with a (`PetscObject`), for example,
501:         `PetscObjectRegisterDestroy`((`PetscObject`)mat);

503:   Level: developer

505:   Notes:
506:   This is used by, for example, `PETSC_VIEWER_XXX_()` routines to free the viewer
507:   when PETSc ends.

509:   This should be used only where there is no natural location in the code to put a call to the destructor of the object.

511: .seealso: `PetscObjectRegisterDestroyAll()`
512: @*/
513: PetscErrorCode PetscObjectRegisterDestroy(PetscObject obj)
514: {
515:   PetscFinalizerContainer container;

517:   PetscFunctionBegin;
519:   container.thunk.obj = obj;
520:   container.type      = PETSC_FINALIZE_OBJECT;
521:   PetscCall(RegisterFinalizer(container));
522:   PetscFunctionReturn(PETSC_SUCCESS);
523: }

525: /*@C
526:   PetscObjectRegisterDestroyAll - Frees all the PETSc objects that have been registered
527:   with `PetscObjectRegisterDestroy()`. Called by `PetscFinalize()`

529:   Logically Collective on the individual `PetscObject`s that are being processed

531:   Level: developer

533: .seealso: `PetscObjectRegisterDestroy()`
534: @*/
535: PetscErrorCode PetscObjectRegisterDestroyAll(void)
536: {
537:   PetscFunctionBegin;
538:   PetscCall(PetscRunRegisteredFinalizers());
539:   PetscFunctionReturn(PETSC_SUCCESS);
540: }

542: /*@C
543:   PetscRegisterFinalize - Registers a function that is to be called in `PetscFinalize()`

545:   Not Collective

547:   Input Parameter:
548: . f - function to be called

550:   Level: developer

552:   Notes:
553:   This is used by, for example, `DMInitializePackage()` to have `DMFinalizePackage()` called

555:   Use `PetscObjectRegisterDestroy()` to register the destruction of an object in `PetscFinalize()`

557: .seealso: `PetscRegisterFinalizeAll()`, `PetscObjectRegisterDestroy()`
558: @*/
559: PetscErrorCode PetscRegisterFinalize(PetscErrorCode (*f)(void))
560: {
561:   PetscFinalizerContainer container;

563:   PetscFunctionBegin;
565:   container.thunk.fn.func = f;
566:   container.type          = PETSC_FINALIZE_FUNC;
567:   PetscCall(RegisterFinalizer(container));
568:   PetscFunctionReturn(PETSC_SUCCESS);
569: }

571: /*@C
572:   PetscRegisterFinalizeAll - Runs all the finalize functions set with `PetscRegisterFinalize()`

574:   Not Collective except for registered functions that are collective

576:   Level: developer

578: .seealso: `PetscRegisterFinalize()`, `PetscObjectRegisterDestroyAll()`
579: @*/
580: PetscErrorCode PetscRegisterFinalizeAll(void)
581: {
582:   PetscFunctionBegin;
583:   PetscCall(PetscRunRegisteredFinalizers());
584:   PetscFunctionReturn(PETSC_SUCCESS);
585: }