void terminate_program(void) { image_t **termList; ssize_t count, i; count = get_sorted_image_list(NULL, &termList, RFLAG_TERMINATED); if (count < B_OK) return; if (gInvalidImageIDs) { // After fork, we lazily rebuild the image IDs of all loaded images update_image_ids(); } TRACE(("%ld: terminate dependencies\n", find_thread(NULL))); for (i = count; i-- > 0;) { image_t *image = termList[i]; TRACE(("%ld: term: %s\n", find_thread(NULL), image->name)); image_event(image, IMAGE_EVENT_UNINITIALIZING); if (image->term_routine) ((init_term_function)image->term_routine)(image->id); image_event(image, IMAGE_EVENT_UNLOADING); } TRACE(("%ld: term done.\n", find_thread(NULL))); free(termList); }
image_t* find_loaded_image_by_id(image_id id, bool ignoreDisposable) { if (gInvalidImageIDs) { // After fork, we lazily rebuild the image IDs of all loaded images update_image_ids(); } for (image_t* image = sLoadedImages.head; image; image = image->next) { if (image->id == id) return image; } if (ignoreDisposable) return NULL; for (image_t* image = sDisposableImages.head; image; image = image->next) { if (image->id == id) return image; } return NULL; }
status_t unload_library(void* handle, image_id imageID, bool addOn) { image_t *image; image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE; if (handle == NULL && imageID < 0) return B_BAD_IMAGE_ID; if (handle == RLD_GLOBAL_SCOPE) return B_OK; rld_lock(); // for now, just do stupid simple global locking if (gInvalidImageIDs) { // After fork, we lazily rebuild the image IDs of all loaded images update_image_ids(); } // we only check images that have been already initialized status_t status = B_BAD_IMAGE_ID; if (handle != NULL) { image = (image_t*)handle; put_image(image); status = B_OK; } else { image = find_loaded_image_by_id(imageID, true); if (image != NULL) { // unload image if (type == image->type) { put_image(image); status = B_OK; } else status = B_BAD_VALUE; } } if (status == B_OK) { while ((image = get_disposable_images().head) != NULL) { // Call the exit hooks that live in this image. // Note: With the Itanium ABI this shouldn't really be done this // way anymore, since global destructors are registered via // __cxa_atexit() (the ones that are registered dynamically) and the // termination routine should call __cxa_finalize() for the image. // The reason why we still do it is that hooks registered with // atexit() aren't associated with the image. We could find out // there which image the hooks lives in and register it // respectively, but since that would be done always, that's // probably more expensive than calling // call_atexit_hooks_for_range() only here, which happens only when // libraries are unloaded dynamically. if (gRuntimeLoader.call_atexit_hooks_for_range) { gRuntimeLoader.call_atexit_hooks_for_range( image->regions[0].vmstart, image->regions[0].vmsize); } image_event(image, IMAGE_EVENT_UNINITIALIZING); if (image->term_routine) ((init_term_function)image->term_routine)(image->id); dequeue_disposable_image(image); unmap_image(image); image_event(image, IMAGE_EVENT_UNLOADING); delete_image(image); } } rld_unlock(); return status; }