+/***********************************************************************
+* _objc_atfork_prepare
+* _objc_atfork_parent
+* _objc_atfork_child
+* Allow ObjC to be used between fork() and exec().
+* libc requires this because it has fork-safe functions that use os_objects.
+*
+* _objc_atfork_prepare() acquires all locks.
+* _objc_atfork_parent() releases the locks again.
+* _objc_atfork_child() forcibly resets the locks.
+**********************************************************************/
+
+// Declare lock ordering.
+#if DEBUG
+__attribute__((constructor))
+static void defineLockOrder()
+{
+ // Every lock precedes crashlog_lock
+ // on the assumption that fatal errors could be anywhere.
+ lockdebug_lock_precedes_lock(&loadMethodLock, &crashlog_lock);
+ lockdebug_lock_precedes_lock(&classInitLock, &crashlog_lock);
+#if __OBJC2__
+ lockdebug_lock_precedes_lock(&runtimeLock, &crashlog_lock);
+ lockdebug_lock_precedes_lock(&DemangleCacheLock, &crashlog_lock);
+#else
+ lockdebug_lock_precedes_lock(&classLock, &crashlog_lock);
+ lockdebug_lock_precedes_lock(&methodListLock, &crashlog_lock);
+ lockdebug_lock_precedes_lock(&NXUniqueStringLock, &crashlog_lock);
+ lockdebug_lock_precedes_lock(&impLock, &crashlog_lock);
+#endif
+ lockdebug_lock_precedes_lock(&selLock, &crashlog_lock);
+ lockdebug_lock_precedes_lock(&cacheUpdateLock, &crashlog_lock);
+ lockdebug_lock_precedes_lock(&objcMsgLogLock, &crashlog_lock);
+ lockdebug_lock_precedes_lock(&AltHandlerDebugLock, &crashlog_lock);
+ lockdebug_lock_precedes_lock(&AssociationsManagerLock, &crashlog_lock);
+ SideTableLocksPrecedeLock(&crashlog_lock);
+ PropertyLocks.precedeLock(&crashlog_lock);
+ StructLocks.precedeLock(&crashlog_lock);
+ CppObjectLocks.precedeLock(&crashlog_lock);
+
+ // loadMethodLock precedes everything
+ // because it is held while +load methods run
+ lockdebug_lock_precedes_lock(&loadMethodLock, &classInitLock);
+#if __OBJC2__
+ lockdebug_lock_precedes_lock(&loadMethodLock, &runtimeLock);
+ lockdebug_lock_precedes_lock(&loadMethodLock, &DemangleCacheLock);
+#else
+ lockdebug_lock_precedes_lock(&loadMethodLock, &methodListLock);
+ lockdebug_lock_precedes_lock(&loadMethodLock, &classLock);
+ lockdebug_lock_precedes_lock(&loadMethodLock, &NXUniqueStringLock);
+ lockdebug_lock_precedes_lock(&loadMethodLock, &impLock);
+#endif
+ lockdebug_lock_precedes_lock(&loadMethodLock, &selLock);
+ lockdebug_lock_precedes_lock(&loadMethodLock, &cacheUpdateLock);
+ lockdebug_lock_precedes_lock(&loadMethodLock, &objcMsgLogLock);
+ lockdebug_lock_precedes_lock(&loadMethodLock, &AltHandlerDebugLock);
+ lockdebug_lock_precedes_lock(&loadMethodLock, &AssociationsManagerLock);
+ SideTableLocksSucceedLock(&loadMethodLock);
+ PropertyLocks.succeedLock(&loadMethodLock);
+ StructLocks.succeedLock(&loadMethodLock);
+ CppObjectLocks.succeedLock(&loadMethodLock);
+
+ // PropertyLocks and CppObjectLocks precede everything
+ // because they are held while objc_retain() or C++ copy are called.
+ // (StructLocks do not precede everything because it calls memmove only.)
+ PropertyLocks.precedeLock(&classInitLock);
+ CppObjectLocks.precedeLock(&classInitLock);
+#if __OBJC2__
+ PropertyLocks.precedeLock(&runtimeLock);
+ CppObjectLocks.precedeLock(&runtimeLock);
+ PropertyLocks.precedeLock(&DemangleCacheLock);
+ CppObjectLocks.precedeLock(&DemangleCacheLock);
+#else
+ PropertyLocks.precedeLock(&methodListLock);
+ CppObjectLocks.precedeLock(&methodListLock);
+ PropertyLocks.precedeLock(&classLock);
+ CppObjectLocks.precedeLock(&classLock);
+ PropertyLocks.precedeLock(&NXUniqueStringLock);
+ CppObjectLocks.precedeLock(&NXUniqueStringLock);
+ PropertyLocks.precedeLock(&impLock);
+ CppObjectLocks.precedeLock(&impLock);
+#endif
+ PropertyLocks.precedeLock(&selLock);
+ CppObjectLocks.precedeLock(&selLock);
+ PropertyLocks.precedeLock(&cacheUpdateLock);
+ CppObjectLocks.precedeLock(&cacheUpdateLock);
+ PropertyLocks.precedeLock(&objcMsgLogLock);
+ CppObjectLocks.precedeLock(&objcMsgLogLock);
+ PropertyLocks.precedeLock(&AltHandlerDebugLock);
+ CppObjectLocks.precedeLock(&AltHandlerDebugLock);
+ PropertyLocks.precedeLock(&AssociationsManagerLock);
+ CppObjectLocks.precedeLock(&AssociationsManagerLock);
+ // fixme side table
+
+#if __OBJC2__
+ lockdebug_lock_precedes_lock(&classInitLock, &runtimeLock);
+#endif
+
+#if __OBJC2__
+ // Runtime operations may occur inside SideTable locks
+ // (such as storeWeak calling getMethodImplementation)
+ SideTableLocksPrecedeLock(&runtimeLock);
+ // Some operations may occur inside runtimeLock.
+ lockdebug_lock_precedes_lock(&runtimeLock, &selLock);
+ lockdebug_lock_precedes_lock(&runtimeLock, &cacheUpdateLock);
+ lockdebug_lock_precedes_lock(&runtimeLock, &DemangleCacheLock);
+#else
+ // Runtime operations may occur inside SideTable locks
+ // (such as storeWeak calling getMethodImplementation)
+ SideTableLocksPrecedeLock(&methodListLock);
+ // Method lookup and fixup.
+ lockdebug_lock_precedes_lock(&methodListLock, &classLock);
+ lockdebug_lock_precedes_lock(&methodListLock, &selLock);
+ lockdebug_lock_precedes_lock(&methodListLock, &cacheUpdateLock);
+ lockdebug_lock_precedes_lock(&methodListLock, &impLock);
+ lockdebug_lock_precedes_lock(&classLock, &selLock);
+ lockdebug_lock_precedes_lock(&classLock, &cacheUpdateLock);
+#endif
+
+ // Striped locks use address order internally.
+ SideTableDefineLockOrder();
+ PropertyLocks.defineLockOrder();
+ StructLocks.defineLockOrder();
+ CppObjectLocks.defineLockOrder();
+}
+// DEBUG
+#endif
+
+void _objc_atfork_prepare()
+{
+ lockdebug_assert_no_locks_locked();
+ lockdebug_setInForkPrepare(true);
+
+ loadMethodLock.lock();
+ PropertyLocks.lockAll();
+ CppObjectLocks.lockAll();
+ classInitLock.enter();
+ SideTableLockAll();
+#if __OBJC2__
+ runtimeLock.write();
+ DemangleCacheLock.lock();
+#else
+ methodListLock.lock();
+ classLock.lock();
+ NXUniqueStringLock.lock();
+ impLock.lock();
+#endif
+ selLock.write();
+ cacheUpdateLock.lock();
+ objcMsgLogLock.lock();
+ AltHandlerDebugLock.lock();
+ AssociationsManagerLock.lock();
+ StructLocks.lockAll();
+ crashlog_lock.lock();
+
+ lockdebug_assert_all_locks_locked();
+ lockdebug_setInForkPrepare(false);
+}
+
+void _objc_atfork_parent()
+{
+ lockdebug_assert_all_locks_locked();
+
+ CppObjectLocks.unlockAll();
+ StructLocks.unlockAll();
+ PropertyLocks.unlockAll();
+ AssociationsManagerLock.unlock();
+ AltHandlerDebugLock.unlock();
+ objcMsgLogLock.unlock();
+ crashlog_lock.unlock();
+ loadMethodLock.unlock();
+ cacheUpdateLock.unlock();
+ selLock.unlockWrite();
+ SideTableUnlockAll();
+#if __OBJC2__
+ DemangleCacheLock.unlock();
+ runtimeLock.unlockWrite();
+#else
+ impLock.unlock();
+ NXUniqueStringLock.unlock();
+ methodListLock.unlock();
+ classLock.unlock();
+#endif
+ classInitLock.leave();
+
+ lockdebug_assert_no_locks_locked();
+}
+
+void _objc_atfork_child()
+{
+ lockdebug_assert_all_locks_locked();
+
+ CppObjectLocks.forceResetAll();
+ StructLocks.forceResetAll();
+ PropertyLocks.forceResetAll();
+ AssociationsManagerLock.forceReset();
+ AltHandlerDebugLock.forceReset();
+ objcMsgLogLock.forceReset();
+ crashlog_lock.forceReset();
+ loadMethodLock.forceReset();
+ cacheUpdateLock.forceReset();
+ selLock.forceReset();
+ SideTableForceResetAll();
+#if __OBJC2__
+ DemangleCacheLock.forceReset();
+ runtimeLock.forceReset();
+#else
+ impLock.forceReset();
+ NXUniqueStringLock.forceReset();
+ methodListLock.forceReset();
+ classLock.forceReset();
+#endif
+ classInitLock.forceReset();
+
+ lockdebug_assert_no_locks_locked();
+}
+
+