Loading...
src/dyldLock.cpp dyld-210.2.3 dyld-45.3
--- dyld/dyld-210.2.3/src/dyldLock.cpp
+++ dyld/dyld-45.3/src/dyldLock.cpp
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -26,47 +26,262 @@
 
 #include "dyldLock.h"
 
-
-
-static pthread_mutex_t	sGlobalMutex;
-
-// <rdar://problem/6361143> Need a way to determine if a gdb call to dlopen() would block
-int	__attribute__((visibility("hidden")))			_dyld_global_lock_held = 0;
-
-
-//
-// This initializer can go away once the following is available:
-//     <rdar://problem/4927311> implement PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
-//
-void dyldGlobalLockInitialize()
-{
-	pthread_mutexattr_t recursiveMutexAttr;
-	pthread_mutexattr_init(&recursiveMutexAttr);
-	pthread_mutexattr_settype(&recursiveMutexAttr, PTHREAD_MUTEX_RECURSIVE);
-	pthread_mutex_init(&sGlobalMutex, &recursiveMutexAttr);
-}
-
-
-LockHelper::LockHelper() 
-{ 
-	dyldGlobalLockAcquire();
-}
-
-LockHelper::~LockHelper() 
-{ 
-	dyldGlobalLockRelease();
-}
-
-void dyldGlobalLockAcquire() 
-{
-	pthread_mutex_lock(&sGlobalMutex);
-	_dyld_global_lock_held = 1;
-}
-
-void dyldGlobalLockRelease() 
-{
-	_dyld_global_lock_held = 0;
-	pthread_mutex_unlock(&sGlobalMutex);
-}
-
-
+// until the reader/writer locks are fully tested, we just use a simple recursive mutex
+#define REAL_READER_WRITER_LOCK 0
+
+
+
+//
+// This class implements a recursive reader/writer lock.
+// Recursive means a thread that has already aquired the lock can re-acquire it.
+// The lock allows either:
+//      a) one "writer" thread to hold lock
+//		b) multiple "reader" threads to hold
+//
+// A thread with the writer can acquire a reader lock.
+// A thread with a reader lock can acquire a writer lock iff it is the only thread with a reader lock
+//
+class RecursiveReaderWriterLock 
+{
+public:
+			RecursiveReaderWriterLock() __attribute__((visibility("hidden")));
+	void	initIfNeeded();
+	
+	
+	void	lockForSingleWritingThread() __attribute__((visibility("hidden")));
+	void	unlockForSingleWritingThread() __attribute__((visibility("hidden")));
+	
+	void	lockForMultipleReadingThreads() __attribute__((visibility("hidden")));
+	void	unlockForMultipleReadingThreads() __attribute__((visibility("hidden")));
+
+private:
+#if REAL_READER_WRITER_LOCK
+	struct ThreadRecursionCount {
+		pthread_t	fThread;
+		uint32_t	fCount;
+	};
+	bool	writerThreadIsAnyThreadBut(pthread_t thread);
+	void	writerThreadRetain(pthread_t thread);
+	bool	writerThreadRelease(pthread_t thread);
+
+	enum { kMaxReaderThreads = 4 };
+	bool	readerThreadSetRetain(pthread_t thread);
+	bool	readerThreadSetRelease(pthread_t thread);
+	bool	readerThreadSetContainsAnotherThread(pthread_t thread);
+
+	ThreadRecursionCount	fWriterThread;
+	ThreadRecursionCount	fReaderThreads[kMaxReaderThreads];
+	pthread_cond_t			fLockFree;
+	pthread_mutex_t			fMutex;
+#else
+	pthread_mutex_t			fMutex;
+#endif
+	bool					fInitialized;	// assumes this is statically initialized to false because sLock is static
+};
+
+
+//
+// initIfNeeded() is a hack so that when libSystem_debug.dylb is useable.
+// The problem is that Objective-C +load methods are called before C++ initialziers are run
+// If +load method makes a call into dyld, sLock is not initialized.  
+//
+// The long term solution is for objc and dyld to work more closely together so that instead
+// of running all +load methods before all initializers, we run each image's +load then its
+// initializers all in bottom up order.
+//
+// This lazy initialization is not thread safe, but as long as someone does not create a 
+// new thread in a +load method, the C++ constructor for sLock will be called before main()
+// so there will only be one thead.
+//
+void RecursiveReaderWriterLock::initIfNeeded()
+{
+	if ( ! fInitialized ) {
+		pthread_mutexattr_t recursiveMutexAttr;
+		pthread_mutexattr_init(&recursiveMutexAttr);
+		pthread_mutexattr_settype(&recursiveMutexAttr, PTHREAD_MUTEX_RECURSIVE);
+		pthread_mutex_init(&fMutex, &recursiveMutexAttr);
+	#if REAL_READER_WRITER_LOCK
+		pthread_cond_init(&fLockFree, NULL);
+		fWriterThread.fThread = NULL;
+		fWriterThread.fCount = 0;
+		for (int i=0; i < kMaxReaderThreads; ++i) {
+			fReaderThreads[i].fThread = NULL;
+			fReaderThreads[i].fCount = 0;
+		}
+	#endif
+		fInitialized = true;
+	}
+}
+
+RecursiveReaderWriterLock::RecursiveReaderWriterLock()
+{
+	initIfNeeded();
+}
+
+void RecursiveReaderWriterLock::lockForSingleWritingThread()
+{
+	this->initIfNeeded();
+#if REAL_READER_WRITER_LOCK
+	pthread_mutex_lock(&fMutex);
+	pthread_t thisThread = pthread_self();
+	// wait as long as there is another writer or any readers on a different thread
+	while ( writerThreadIsAnyThreadBut(thisThread) || readerThreadSetContainsAnotherThread(thisThread) ) {
+		pthread_cond_wait(&fLockFree, &fMutex);
+	}
+	writerThreadRetain(thisThread);
+	pthread_mutex_unlock(&fMutex);
+#else
+	pthread_mutex_lock(&fMutex);
+#endif
+}
+
+void RecursiveReaderWriterLock::unlockForSingleWritingThread()
+{
+	this->initIfNeeded();
+#if REAL_READER_WRITER_LOCK
+	pthread_mutex_lock(&fMutex);
+	if ( writerThreadRelease(pthread_self()) ) {
+		pthread_cond_broadcast(&fLockFree);
+	}
+	pthread_mutex_unlock(&fMutex);
+#else
+	pthread_mutex_unlock(&fMutex);
+#endif
+}
+
+
+void RecursiveReaderWriterLock::lockForMultipleReadingThreads()
+{
+	this->initIfNeeded();
+#if REAL_READER_WRITER_LOCK
+	pthread_mutex_lock(&fMutex);
+	pthread_t thisThread = pthread_self();
+	// wait as long as there is a writer on another thread or too many readers already
+	while ( writerThreadIsAnyThreadBut(thisThread) || !readerThreadSetRetain(thisThread) ) {
+		pthread_cond_wait(&fLockFree, &fMutex);
+	}
+	pthread_mutex_unlock(&fMutex);
+#else
+	pthread_mutex_lock(&fMutex);
+#endif
+}
+
+
+void RecursiveReaderWriterLock::unlockForMultipleReadingThreads()
+{
+	this->initIfNeeded();
+#if REAL_READER_WRITER_LOCK
+	pthread_mutex_lock(&fMutex);
+	if ( readerThreadSetRelease(pthread_self()) ) {
+		pthread_cond_broadcast(&fLockFree);
+	}
+	pthread_mutex_unlock(&fMutex);
+#else
+	pthread_mutex_unlock(&fMutex);
+#endif
+}
+
+#if REAL_READER_WRITER_LOCK
+bool RecursiveReaderWriterLock::writerThreadIsAnyThreadBut(pthread_t thread)
+{
+	return ( (fWriterThread.fThread != NULL) && (fWriterThread.fThread != thread) );
+}
+
+void RecursiveReaderWriterLock::writerThreadRetain(pthread_t thread)
+{
+	++fWriterThread.fCount;
+}
+
+bool RecursiveReaderWriterLock::writerThreadRelease(pthread_t thread)
+{
+	return ( --fWriterThread.fCount == 0 );
+}
+
+
+bool RecursiveReaderWriterLock::readerThreadSetRetain(pthread_t thread)
+{
+	// if thread is already in set, bump its count
+	for (int i=0; i < kMaxReaderThreads; ++i) {
+		if ( fReaderThreads[i].fThread == thread ) {
+			++fReaderThreads[i].fCount;
+			return true;
+		}
+	}
+	// find empty slot in set
+	for (int i=0; i < kMaxReaderThreads; ++i) {
+		if ( fReaderThreads[i].fThread == NULL ) {
+			fReaderThreads[i].fThread = thread;
+			fReaderThreads[i].fCount = 1;
+			return true;
+		}
+	}
+
+	// all reader slots full
+	return false;
+}
+
+bool RecursiveReaderWriterLock::readerThreadSetRelease(pthread_t thread)
+{
+	for (int i=0; i < kMaxReaderThreads; ++i) {
+		if ( fReaderThreads[i].fThread == thread ) {
+			if ( --fReaderThreads[i].fCount == 0 ) {
+				fReaderThreads[i].fThread = NULL;
+				return true;
+			}
+			return false;
+		}
+	}
+	// should never get here
+	return false;
+}
+
+bool RecursiveReaderWriterLock::readerThreadSetContainsAnotherThread(pthread_t thread)
+{
+	for (int i=0; i < kMaxReaderThreads; ++i) {
+		if ( (fReaderThreads[i].fThread != NULL) && (fReaderThreads[i].fThread != thread) ) 
+			return true;
+	}
+	return false;
+}
+#endif
+
+
+// dyld's global reader/writer lock
+static RecursiveReaderWriterLock	sLock;
+
+
+LockReaderHelper::LockReaderHelper() 
+{ 
+	sLock.lockForMultipleReadingThreads();
+}
+
+LockReaderHelper::~LockReaderHelper() 
+{ 
+	sLock.unlockForMultipleReadingThreads();
+}
+
+
+LockWriterHelper::LockWriterHelper() 
+{ 
+	sLock.lockForSingleWritingThread();
+}
+
+LockWriterHelper::~LockWriterHelper() 
+{ 
+	sLock.unlockForSingleWritingThread();
+}
+
+
+// needed by lazy binding
+void lockForLazyBinding() 
+{
+	sLock.lockForMultipleReadingThreads();
+}
+
+void unlockForLazyBinding() 
+{
+	sLock.unlockForMultipleReadingThreads();
+}
+
+
+