+/*
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
 /* Last update: cjk - 16 October 2000
  * To construct this list, I enabled the code in the search function which
  * is marked DUMP_SELECTORS, and launched a few apps with stdout redirected
 
  * @APPLE_LICENSE_HEADER_END@
  */
 //
-//  objc_sync.h
+//  objc_sync.m
 //
 //  Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
 //
 #include <stdlib.h>
 #include <sys/time.h>
 #include <pthread.h>
-#define PTHREAD_MUTEX_RECURSIVE          2
-#include <CoreFoundation/CFDictionary.h>
 #include <AssertMacros.h>
 
 #include "objc-sync.h"
 
 struct SyncData
 {
-       struct SyncData*        nextData;
-       id                      object;
-       unsigned int            lockCount;
+       struct SyncData*        nextData;       // only accessed while holding sTableLock
+       id                      object;         // only accessed while holding sTableLock
+       unsigned int            lockCount;      // only accessed while holding sTableLock
        pthread_mutex_t         mutex;
        pthread_cond_t          conditionVariable;
 };
 typedef struct SyncData SyncData;
 
+
 static pthread_mutex_t         sTableLock = PTHREAD_MUTEX_INITIALIZER;
 static SyncData*               sDataList = NULL;
 
-static SyncData* id2data(id object)
+enum usage { ACQUIRE, RELEASE, CHECK };
+
+static SyncData* id2data(id object, enum usage why)
 {
     SyncData* result = NULL;
     int err;
             firstUnused = p;
     }
     
-    // if no corresponding SyncData found, but an unused one was found, use it
+    // no SyncData currently associated with object
+    if ( (why == RELEASE) || (why == CHECK) )
+       goto done;
+    
+    // an unused one was found, use it
     if ( firstUnused != NULL ) {
         result = firstUnused;
         result->object = object;
     sDataList = result;
     
 done:
+    if ( result != NULL ) {
+        switch ( why ) {
+            case ACQUIRE:
+                result->lockCount++;
+                break;
+            case RELEASE:
+                result->lockCount--;
+                if ( result->lockCount == 0 )
+                    result->object = NULL;  // now recycled
+                break;
+            case CHECK:
+                // do nothing
+                break;
+        }
+    }
     pthread_mutex_unlock(&sTableLock);
     return result;
 }
 {
     int result = OBJC_SYNC_SUCCESS;
     
-    SyncData* data = id2data(obj);
+    SyncData* data = id2data(obj, ACQUIRE);
     require_action_string(data != NULL, done, result = OBJC_SYNC_NOT_INITIALIZED, "id2data failed");
        
     result = pthread_mutex_lock(&data->mutex);
     require_noerr_string(result, done, "pthread_mutex_lock failed");
-       
-    data->lockCount++; // note: lockCount is only modified when corresponding mutex is held
-       
+               
 done: 
     return result;
 }
 {
     int result = OBJC_SYNC_SUCCESS;
     
-    SyncData* data;
-    data = id2data(obj); // XXX should assert that we didn't create it
-    require_action_string(data != NULL, done, result = OBJC_SYNC_NOT_INITIALIZED, "id2data failed");
-
-    int oldLockCount = data->lockCount--;
-    if ( oldLockCount == 1 ) {
-        // XXX should move off the main chain to speed id2data searches
-        data->object = NULL;   // recycle data
-    }
+    SyncData* data = id2data(obj, RELEASE); 
+    require_action_string(data != NULL, done, result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR, "id2data failed");
     
     result = pthread_mutex_unlock(&data->mutex);
     require_noerr_string(result, done, "pthread_mutex_unlock failed");
 {
     int result = OBJC_SYNC_SUCCESS;
             
-    SyncData* data = id2data(obj);
-    require_action_string(data != NULL, done, result = OBJC_SYNC_NOT_INITIALIZED, "id2data failed");
+    SyncData* data = id2data(obj, CHECK);
+    require_action_string(data != NULL, done, result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR, "id2data failed");
     
     
     // XXX need to retry cond_wait under out-of-our-control failures
 {
     int result = OBJC_SYNC_SUCCESS;
         
-    SyncData* data = id2data(obj);
-    require_action_string(data != NULL, done, result = OBJC_SYNC_NOT_INITIALIZED, "id2data failed");
+    SyncData* data = id2data(obj, CHECK);
+    require_action_string(data != NULL, done, result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR, "id2data failed");
 
     result = pthread_cond_signal(&data->conditionVariable);
     require_noerr_string(result, done, "pthread_cond_signal failed");
 {
     int result = OBJC_SYNC_SUCCESS;
         
-    SyncData* data = id2data(obj);
-    require_action_string(data != NULL, done, result = OBJC_SYNC_NOT_INITIALIZED, "id2data failed");
+    SyncData* data = id2data(obj, CHECK);
+    require_action_string(data != NULL, done, result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR, "id2data failed");
 
     result = pthread_cond_broadcast(&data->conditionVariable);
     require_noerr_string(result, done, "pthread_cond_broadcast failed");