]> git.saurik.com Git - apple/dyld.git/blame - src/dyldLock.cpp
dyld-46.12.tar.gz
[apple/dyld.git] / src / dyldLock.cpp
CommitLineData
0959b6d4
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include <pthread.h>
26
27#include "dyldLock.h"
28
29// until the reader/writer locks are fully tested, we just use a simple recursive mutex
30#define REAL_READER_WRITER_LOCK 0
31
32
33
34//
35// This class implements a recursive reader/writer lock.
36// Recursive means a thread that has already aquired the lock can re-acquire it.
37// The lock allows either:
38// a) one "writer" thread to hold lock
39// b) multiple "reader" threads to hold
40//
41// A thread with the writer can acquire a reader lock.
42// A thread with a reader lock can acquire a writer lock iff it is the only thread with a reader lock
43//
44class RecursiveReaderWriterLock
45{
46public:
47 RecursiveReaderWriterLock() __attribute__((visibility("hidden")));
48 void initIfNeeded();
49
50
51 void lockForSingleWritingThread() __attribute__((visibility("hidden")));
52 void unlockForSingleWritingThread() __attribute__((visibility("hidden")));
53
54 void lockForMultipleReadingThreads() __attribute__((visibility("hidden")));
55 void unlockForMultipleReadingThreads() __attribute__((visibility("hidden")));
56
57private:
58#if REAL_READER_WRITER_LOCK
59 struct ThreadRecursionCount {
60 pthread_t fThread;
61 uint32_t fCount;
62 };
63 bool writerThreadIsAnyThreadBut(pthread_t thread);
64 void writerThreadRetain(pthread_t thread);
65 bool writerThreadRelease(pthread_t thread);
66
67 enum { kMaxReaderThreads = 4 };
68 bool readerThreadSetRetain(pthread_t thread);
69 bool readerThreadSetRelease(pthread_t thread);
70 bool readerThreadSetContainsAnotherThread(pthread_t thread);
71
72 ThreadRecursionCount fWriterThread;
73 ThreadRecursionCount fReaderThreads[kMaxReaderThreads];
74 pthread_cond_t fLockFree;
75 pthread_mutex_t fMutex;
76#else
77 pthread_mutex_t fMutex;
78#endif
79 bool fInitialized; // assumes this is statically initialized to false because sLock is static
80};
81
82
83//
84// initIfNeeded() is a hack so that when libSystem_debug.dylb is useable.
85// The problem is that Objective-C +load methods are called before C++ initialziers are run
86// If +load method makes a call into dyld, sLock is not initialized.
87//
88// The long term solution is for objc and dyld to work more closely together so that instead
89// of running all +load methods before all initializers, we run each image's +load then its
90// initializers all in bottom up order.
91//
92// This lazy initialization is not thread safe, but as long as someone does not create a
93// new thread in a +load method, the C++ constructor for sLock will be called before main()
94// so there will only be one thead.
95//
96void RecursiveReaderWriterLock::initIfNeeded()
97{
98 if ( ! fInitialized ) {
99 pthread_mutexattr_t recursiveMutexAttr;
100 pthread_mutexattr_init(&recursiveMutexAttr);
101 pthread_mutexattr_settype(&recursiveMutexAttr, PTHREAD_MUTEX_RECURSIVE);
102 pthread_mutex_init(&fMutex, &recursiveMutexAttr);
103 #if REAL_READER_WRITER_LOCK
104 pthread_cond_init(&fLockFree, NULL);
105 fWriterThread.fThread = NULL;
106 fWriterThread.fCount = 0;
107 for (int i=0; i < kMaxReaderThreads; ++i) {
108 fReaderThreads[i].fThread = NULL;
109 fReaderThreads[i].fCount = 0;
110 }
111 #endif
112 fInitialized = true;
113 }
114}
115
116RecursiveReaderWriterLock::RecursiveReaderWriterLock()
117{
118 initIfNeeded();
119}
120
121void RecursiveReaderWriterLock::lockForSingleWritingThread()
122{
123 this->initIfNeeded();
124#if REAL_READER_WRITER_LOCK
125 pthread_mutex_lock(&fMutex);
126 pthread_t thisThread = pthread_self();
127 // wait as long as there is another writer or any readers on a different thread
128 while ( writerThreadIsAnyThreadBut(thisThread) || readerThreadSetContainsAnotherThread(thisThread) ) {
129 pthread_cond_wait(&fLockFree, &fMutex);
130 }
131 writerThreadRetain(thisThread);
132 pthread_mutex_unlock(&fMutex);
133#else
134 pthread_mutex_lock(&fMutex);
135#endif
136}
137
138void RecursiveReaderWriterLock::unlockForSingleWritingThread()
139{
140 this->initIfNeeded();
141#if REAL_READER_WRITER_LOCK
142 pthread_mutex_lock(&fMutex);
143 if ( writerThreadRelease(pthread_self()) ) {
144 pthread_cond_broadcast(&fLockFree);
145 }
146 pthread_mutex_unlock(&fMutex);
147#else
148 pthread_mutex_unlock(&fMutex);
149#endif
150}
151
152
153void RecursiveReaderWriterLock::lockForMultipleReadingThreads()
154{
155 this->initIfNeeded();
156#if REAL_READER_WRITER_LOCK
157 pthread_mutex_lock(&fMutex);
158 pthread_t thisThread = pthread_self();
159 // wait as long as there is a writer on another thread or too many readers already
160 while ( writerThreadIsAnyThreadBut(thisThread) || !readerThreadSetRetain(thisThread) ) {
161 pthread_cond_wait(&fLockFree, &fMutex);
162 }
163 pthread_mutex_unlock(&fMutex);
164#else
165 pthread_mutex_lock(&fMutex);
166#endif
167}
168
169
170void RecursiveReaderWriterLock::unlockForMultipleReadingThreads()
171{
172 this->initIfNeeded();
173#if REAL_READER_WRITER_LOCK
174 pthread_mutex_lock(&fMutex);
175 if ( readerThreadSetRelease(pthread_self()) ) {
176 pthread_cond_broadcast(&fLockFree);
177 }
178 pthread_mutex_unlock(&fMutex);
179#else
180 pthread_mutex_unlock(&fMutex);
181#endif
182}
183
184#if REAL_READER_WRITER_LOCK
185bool RecursiveReaderWriterLock::writerThreadIsAnyThreadBut(pthread_t thread)
186{
187 return ( (fWriterThread.fThread != NULL) && (fWriterThread.fThread != thread) );
188}
189
190void RecursiveReaderWriterLock::writerThreadRetain(pthread_t thread)
191{
192 ++fWriterThread.fCount;
193}
194
195bool RecursiveReaderWriterLock::writerThreadRelease(pthread_t thread)
196{
197 return ( --fWriterThread.fCount == 0 );
198}
199
200
201bool RecursiveReaderWriterLock::readerThreadSetRetain(pthread_t thread)
202{
203 // if thread is already in set, bump its count
204 for (int i=0; i < kMaxReaderThreads; ++i) {
205 if ( fReaderThreads[i].fThread == thread ) {
206 ++fReaderThreads[i].fCount;
207 return true;
208 }
209 }
210 // find empty slot in set
211 for (int i=0; i < kMaxReaderThreads; ++i) {
212 if ( fReaderThreads[i].fThread == NULL ) {
213 fReaderThreads[i].fThread = thread;
214 fReaderThreads[i].fCount = 1;
215 return true;
216 }
217 }
218
219 // all reader slots full
220 return false;
221}
222
223bool RecursiveReaderWriterLock::readerThreadSetRelease(pthread_t thread)
224{
225 for (int i=0; i < kMaxReaderThreads; ++i) {
226 if ( fReaderThreads[i].fThread == thread ) {
227 if ( --fReaderThreads[i].fCount == 0 ) {
228 fReaderThreads[i].fThread = NULL;
229 return true;
230 }
231 return false;
232 }
233 }
234 // should never get here
235 return false;
236}
237
238bool RecursiveReaderWriterLock::readerThreadSetContainsAnotherThread(pthread_t thread)
239{
240 for (int i=0; i < kMaxReaderThreads; ++i) {
241 if ( (fReaderThreads[i].fThread != NULL) && (fReaderThreads[i].fThread != thread) )
242 return true;
243 }
244 return false;
245}
246#endif
247
248
249// dyld's global reader/writer lock
250static RecursiveReaderWriterLock sLock;
251
252
253LockReaderHelper::LockReaderHelper()
254{
255 sLock.lockForMultipleReadingThreads();
256}
257
258LockReaderHelper::~LockReaderHelper()
259{
260 sLock.unlockForMultipleReadingThreads();
261}
262
263
264LockWriterHelper::LockWriterHelper()
265{
266 sLock.lockForSingleWritingThread();
267}
268
269LockWriterHelper::~LockWriterHelper()
270{
271 sLock.unlockForSingleWritingThread();
272}
273
274
275// needed by lazy binding
276void lockForLazyBinding()
277{
278 sLock.lockForMultipleReadingThreads();
279}
280
281void unlockForLazyBinding()
282{
283 sLock.unlockForMultipleReadingThreads();
284}
285
286
287