- if (p->fns[n].fn_type == ATEXIT_FN_EMPTY)
- continue; /* already been called */
- if (dso != NULL && dso != p->fns[n].fn_dso)
- continue; /* wrong DSO */
- fn = p->fns[n];
- /*
- Mark entry to indicate that this particular handler
- has already been called.
- */
- p->fns[n].fn_type = ATEXIT_FN_EMPTY;
- _MUTEX_UNLOCK(&atexit_mutex);
-
- /* Call the function of correct type. */
- if (fn.fn_type == ATEXIT_FN_CXA)
- fn.fn_ptr.cxa_func(fn.fn_arg);
- else if (fn.fn_type == ATEXIT_FN_STD)
- fn.fn_ptr.std_func();
+ fn = &p->fns[n];
+
+ if (fn->fn_type == ATEXIT_FN_EMPTY) {
+ continue; // already been called
+ }
+
+ // Verify that the entry is within the range being unloaded.
+ if (count > 0) {
+ if (fn->fn_type == ATEXIT_FN_CXA) {
+ // for __cxa_atexit(), call if *dso* is in range be unloaded
+ if (!__cxa_in_range(ranges, count, fn->fn_dso)) {
+ continue; // not being unloaded yet
+ }
+ } else if (fn->fn_type == ATEXIT_FN_STD) {
+ // for atexit, call if *function* is in range be unloaded
+ if (!__cxa_in_range(ranges, count, fn->fn_ptr.std_func)) {
+ continue; // not being unloaded yet
+ }
+#ifdef __BLOCKS__
+ } else if (fn->fn_type == ATEXIT_FN_BLK) {
+ // for atexit_b, call if block code is in range be unloaded
+ void *a = ((struct Block_layout *)fn->fn_ptr.block)->invoke;
+ if (!__cxa_in_range(ranges, count, a)) {
+ continue; // not being unloaded yet
+ }
+#endif // __BLOCKS__
+ }
+ }
+
+ // Clear the entry to indicate that this handler has been called.
+ int fn_type = fn->fn_type;
+ fn->fn_type = ATEXIT_FN_EMPTY;
+
+ // Detect recursive registrations.
+ __atexit_new_registration = 0;
+ _MUTEX_UNLOCK(&atexit_mutex);
+
+ // Call the handler.
+ if (fn_type == ATEXIT_FN_CXA) {
+ fn->fn_ptr.cxa_func(fn->fn_arg);
+ } else if (fn_type == ATEXIT_FN_STD) {
+ fn->fn_ptr.std_func();
+#ifdef __BLOCKS__
+ } else if (fn_type == ATEXIT_FN_BLK) {
+ fn->fn_ptr.block();
+#endif // __BLOCKS__
+ }
+
+ // Call any recursively registered handlers.