! Also called in gmt_init.c and prototyped in gmt_internals.h: */
| 8085 | |
| 8086 | /*! Also called in gmt_init.c and prototyped in gmt_internals.h: */ |
| 8087 | void gmtlib_garbage_collection (struct GMTAPI_CTRL *API, int level) { |
| 8088 | /* gmtlib_garbage_collection frees all registered memory associated with the |
| 8089 | * current module level or for the entire session if level == GMT_NOTSET (-1). */ |
| 8090 | |
| 8091 | unsigned int i, j, n_free = 0, u_level = 0; |
| 8092 | int error = GMT_NOERROR; |
| 8093 | void *address = NULL; |
| 8094 | struct GMTAPI_DATA_OBJECT *S_obj = NULL; |
| 8095 | |
| 8096 | if (API->n_objects == 0) return; /* Nothing to do */ |
| 8097 | |
| 8098 | #ifdef DEBUG |
| 8099 | gmtapi_list_objects (API, "GMTAPI_Garbage_Collection entry"); |
| 8100 | #endif |
| 8101 | /* Free memory allocated during data registration (e.g., via GMT_Get|Put_Data). |
| 8102 | * Because gmtlib_unregister_io will delete an object and shuffle |
| 8103 | * the API->object array, reducing API->n_objects by one we must |
| 8104 | * be aware that API->n_objects changes in the loop below, hence the while loop */ |
| 8105 | |
| 8106 | i = n_free = 0; |
| 8107 | if (level != GMT_NOTSET) u_level = level; |
| 8108 | while (i < API->n_objects) { /* While there are more objects to consider */ |
| 8109 | S_obj = API->object[i]; /* Shorthand for the current object */ |
| 8110 | if (!S_obj) { /* Skip empty object [NOTE: Should not happen?] */ |
| 8111 | GMT_Report (API, GMT_MSG_WARNING, "gmtlib_garbage_collection found empty object number %d [Bug?]\n", i++); |
| 8112 | continue; |
| 8113 | } |
| 8114 | if (!(level == GMT_NOTSET || S_obj->alloc_level == u_level)) { /* Not the right module level (or not end of session yet) */ |
| 8115 | if (S_obj->reset_pad && S_obj->no_longer_owner == false) { /* Temporarily changed pad to access a sub-region of a memory grid - now reset this if still the owner */ |
| 8116 | address = S_obj->resource; /* Try to get the data object */ |
| 8117 | gmtapi_contract_pad (API->GMT, address, S_obj->actual_family, S_obj->orig_pad, S_obj->orig_wesn); |
| 8118 | S_obj->reset_pad = 0; |
| 8119 | } |
| 8120 | i++; continue; |
| 8121 | } |
| 8122 | if (S_obj->resource == NULL) { /* No memory to free (probably freed earlier); handle trashing of empty object after this loop */ |
| 8123 | i++; continue; |
| 8124 | } |
| 8125 | if (level != GMT_NOTSET && S_obj->no_longer_owner) { /* No memory to free since we passed it on; just NULL the pointers */ |
| 8126 | S_obj->resource = NULL; /* Since other objects own the data now */ |
| 8127 | S_obj->alloc_level = u_level; /* To ensure it will be Unregistered below */ |
| 8128 | S_obj->alloc_mode = GMT_ALLOC_INTERNALLY; /* To ensure it will be Unregistered below */ |
| 8129 | i++; continue; |
| 8130 | } |
| 8131 | /* Here we will try to free the memory pointed to by S_obj->resource|data */ |
| 8132 | GMT_Report (API, GMT_MSG_DEBUG, "gmtlib_garbage_collection: Destroying object: C=%d A=%d ID=%d W=%s F=%s M=%s S=%s P=%" PRIxS " N=%s\n", |
| 8133 | S_obj->close_file, S_obj->alloc_mode, S_obj->ID, GMT_direction[S_obj->direction], |
| 8134 | GMT_family[S_obj->family], gmtapi_method (S_obj->method), GMT_status[S_obj->status&2], |
| 8135 | (size_t)S_obj->resource, S_obj->filename); |
| 8136 | if (S_obj->resource) { |
| 8137 | address = S_obj->resource; /* Keep a record of what the address was (since S_obj->resource will be set to NULL when freed) */ |
| 8138 | error = gmtapi_destroy_data_ptr (API, S_obj->actual_family, API->object[i]->resource); /* Do the dirty deed */ |
| 8139 | } |
| 8140 | |
| 8141 | if (error < 0) { /* Failed to destroy this memory; that cannot be a good thing... */ |
| 8142 | GMT_Report (API, GMT_MSG_WARNING, "gmtlib_garbage_collection failed to destroy memory for object % d [Bug?]\n", i++); |
| 8143 | /* Skip it for now; but this is possibly a fatal error [Bug]? */ |
| 8144 | } |
no test coverage detected