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(®fin[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: }