+/*
+ * 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");