/ OSX / libsecurity_utilities / lib / threading.cpp
threading.cpp
  1  /*
  2   * Copyright (c) 2000-2004,2011-2012,2014 Apple Inc. All Rights Reserved.
  3   * 
  4   * @APPLE_LICENSE_HEADER_START@
  5   * 
  6   * This file contains Original Code and/or Modifications of Original Code
  7   * as defined in and that are subject to the Apple Public Source License
  8   * Version 2.0 (the 'License'). You may not use this file except in
  9   * compliance with the License. Please obtain a copy of the License at
 10   * http://www.opensource.apple.com/apsl/ and read it before using this
 11   * file.
 12   * 
 13   * The Original Code and all software distributed under the License are
 14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 18   * Please see the License for the specific language governing rights and
 19   * limitations under the License.
 20   * 
 21   * @APPLE_LICENSE_HEADER_END@
 22   */
 23  
 24  
 25  //
 26  // threading - generic thread support
 27  //
 28  #include <security_utilities/threading.h>
 29  #include <security_utilities/globalizer.h>
 30  #include <security_utilities/memutils.h>
 31  #include <utilities/debugging.h>
 32  
 33  #include <unistd.h>     // WWDC 2007 thread-crash workaround
 34  #include <syslog.h>     // WWDC 2007 thread-crash workaround
 35  
 36  //
 37  // Thread-local storage primitive
 38  //
 39  ThreadStoreSlot::ThreadStoreSlot(Destructor *destructor)
 40  {
 41      if (int err = pthread_key_create(&mKey, destructor))
 42          UnixError::throwMe(err);
 43  }
 44  
 45  ThreadStoreSlot::~ThreadStoreSlot()
 46  {
 47      //@@@ if we wanted to dispose of pending task objects, we'd have
 48      //@@@ to keep a set of them and delete them explicitly here
 49      pthread_key_delete(mKey);
 50  }
 51  
 52  
 53  //
 54  // Mutex implementation
 55  //
 56  struct MutexAttributes {
 57  	pthread_mutexattr_t recursive;
 58  	pthread_mutexattr_t checking;
 59  	
 60  	MutexAttributes()
 61  	{
 62  		pthread_mutexattr_init(&recursive);
 63  		pthread_mutexattr_settype(&recursive, PTHREAD_MUTEX_RECURSIVE);
 64  #if !defined(NDEBUG)
 65  		pthread_mutexattr_init(&checking);
 66  		pthread_mutexattr_settype(&checking, PTHREAD_MUTEX_ERRORCHECK);
 67  #endif //NDEBUG
 68  	}
 69  };
 70  
 71  static ModuleNexus<MutexAttributes> mutexAttrs;
 72  
 73  
 74  Mutex::Mutex()
 75  {
 76  	check(pthread_mutex_init(&me, NULL));
 77  }
 78  
 79  Mutex::Mutex(Type type)
 80  {
 81  	switch (type) {
 82  	case normal:
 83  		check(pthread_mutex_init(&me, IFELSEDEBUG(&mutexAttrs().checking, NULL)));
 84  		break;
 85  	case recursive:		// requested recursive (is also checking, always)
 86  		check(pthread_mutex_init(&me, &mutexAttrs().recursive));
 87  		break;
 88  	};
 89  }
 90  
 91  
 92  Mutex::~Mutex()
 93  {
 94      int result = pthread_mutex_destroy(&me);
 95      if(result) {
 96          secerror("Probable bug: error destroying Mutex: %d", result);
 97      }
 98  	check(result);
 99  }
100  
101  
102  void Mutex::lock()
103  {
104  	check(pthread_mutex_lock(&me));
105  }
106  
107  
108  bool Mutex::tryLock()
109  {
110  	if (int err = pthread_mutex_trylock(&me)) {
111  		if (err != EBUSY)
112  			UnixError::throwMe(err);
113  		return false;
114  	}
115  
116  	return true;
117  }
118  
119  
120  void Mutex::unlock()
121  {
122      int result = pthread_mutex_unlock(&me);
123  	check(result);
124  }
125  
126  
127  //
128  // Condition variables
129  //
130  Condition::Condition(Mutex &lock) : mutex(lock)
131  {
132      check(pthread_cond_init(&me, NULL));
133  }
134  
135  Condition::~Condition()
136  {
137  	check(pthread_cond_destroy(&me));
138  }
139  
140  void Condition::wait()
141  {
142      check(pthread_cond_wait(&me, &mutex.me));
143  }
144  
145  void Condition::signal()
146  {
147      check(pthread_cond_signal(&me));
148  }
149  
150  void Condition::broadcast()
151  {
152      check(pthread_cond_broadcast(&me));
153  }
154  
155  
156  //
157  // CountingMutex implementation.
158  //
159  void CountingMutex::enter()
160  {
161      lock();
162      mCount++;
163      unlock();
164  }
165  
166  bool CountingMutex::tryEnter()		
167  {
168      if (!tryLock())
169          return false;
170      mCount++;
171      unlock();
172      return true;
173  }
174  
175  void CountingMutex::exit()
176  {
177      lock();
178      assert(mCount > 0);
179      mCount--;
180      unlock();
181  }
182  
183  void CountingMutex::finishEnter()
184  {
185      mCount++;
186      unlock();
187  }
188  
189  void CountingMutex::finishExit()
190  {
191      assert(mCount > 0);
192      mCount--; 
193      unlock();
194  }
195  
196  //
197  // ReadWriteLock implementation
198  //
199  ReadWriteLock::ReadWriteLock() {
200      check(pthread_rwlock_init(&mLock, NULL));
201  }
202  
203  bool ReadWriteLock::lock() {
204      check(pthread_rwlock_rdlock(&mLock));
205      return true;
206  }
207  
208  bool ReadWriteLock::tryLock() {
209      return (pthread_rwlock_tryrdlock(&mLock) == 0);
210  }
211  
212  bool ReadWriteLock::writeLock() {
213      check(pthread_rwlock_wrlock(&mLock));
214      return true;
215  }
216  
217  bool ReadWriteLock::tryWriteLock() {
218      return (pthread_rwlock_trywrlock(&mLock) == 0);
219  }
220  
221  void ReadWriteLock::unlock() {
222      check(pthread_rwlock_unlock(&mLock));
223  }
224  
225  //
226  // StReadWriteLock implementation
227  //
228  bool StReadWriteLock::lock() {
229      switch(mType) {
230          case Read:     mIsLocked = mRWLock.lock(); break;
231          case TryRead:  mIsLocked = mRWLock.tryLock(); break;
232          case Write:    mIsLocked = mRWLock.writeLock(); break;
233          case TryWrite: mIsLocked = mRWLock.tryWriteLock(); break;
234      }
235      return mIsLocked;
236  }
237  
238  void StReadWriteLock::unlock() {
239      mRWLock.unlock();
240      mIsLocked = false;
241  }
242  
243  bool StReadWriteLock::isLocked() {
244      return mIsLocked;
245  }
246  
247  
248  
249  //
250  // Threads implementation
251  //
252  Thread::~Thread()
253  {
254  }
255  
256  void Thread::threadRun()
257  {
258      pthread_t pt;
259      pthread_attr_t ptattrs;
260      int err, ntries = 10;       // 10 is arbitrary
261  
262      if ((err = pthread_attr_init(&ptattrs)) ||
263          (err = pthread_attr_setdetachstate(&ptattrs, PTHREAD_CREATE_DETACHED)))
264      {
265          syslog(LOG_ERR, "error %d setting thread detach state", err);
266      }
267      while ((err = pthread_create(&pt, &ptattrs, runner, this) &&
268             --ntries))
269      {
270          syslog(LOG_ERR, "pthread_create() error %d", err);
271          usleep(50000);          // 50 ms is arbitrary
272      }
273      if (err)
274      {
275          syslog(LOG_ERR, "too many failed pthread_create() attempts");
276      }
277      else
278          secinfo("thread", "%p created", pt);
279  }
280  
281  void *Thread::runner(void *arg)
282  {
283      try // the top level of any running thread of execution must have a try/catch around it,
284          // otherwise it will crash if something underneath throws.
285      {
286          Thread *me = static_cast<Thread *>(arg);
287          pthread_setname_np(me->threadName);
288          secinfo("thread", "%p: %s starting", pthread_self(), me->threadName);
289          me->threadAction();
290          secinfo("thread", "%p: %s terminating", pthread_self(), me->threadName);
291          return NULL;
292      }
293      catch (...)
294      {
295          return NULL;
296      }
297  }
298  
299  void Thread::threadYield()
300  {
301  	::sched_yield();
302  }