2 * Copyright (c) 2007 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 /***********************************************************************
26 * Error-checking locks for debugging.
27 **********************************************************************/
29 #import "objc-private.h"
31 typedef struct _objc_lock_list {
34 mutex_t list[0]; // variable-size
37 static struct _objc_lock_list *
40 _objc_pthread_data *data;
41 _objc_lock_list *locks;
43 data = _objc_fetch_pthread_data(create);
44 if (!data && !create) return NULL;
46 locks = data->lockList;
51 locks = _calloc_internal(1, sizeof(_objc_lock_list) + sizeof(mutex_t) * 4);
54 data->lockList = locks;
58 if (locks->allocated == locks->used) {
62 data->lockList = _calloc_internal(1, sizeof(_objc_lock_list) + 2 * locks->used * sizeof(mutex_t));
63 data->lockList->used = locks->used;
64 data->lockList->allocated = locks->used * 2;
65 memcpy(data->lockList->list, locks->list, locks->used * sizeof(mutex_t));
66 _free_internal(locks);
67 locks = data->lockList;
76 hasLock(_objc_lock_list *locks, mutex_t lock)
79 if (!locks) return NO;
81 for (i = 0; i < locks->used; i++) {
82 if (locks->list[i] == lock) return YES;
89 setLock(_objc_lock_list *locks, mutex_t lock)
91 locks->list[locks->used++] = lock;
95 clearLock(_objc_lock_list *locks, mutex_t lock)
98 for (i = 0; i < locks->used; i++) {
99 if (locks->list[i] == lock) {
100 locks->list[i] = locks->list[--locks->used];
107 __private_extern__ void
108 _lock_debug(mutex_t lock, const char *name)
110 _objc_lock_list *locks = getLocks(YES);
111 if (hasLock(locks, lock)) _objc_fatal("deadlock: relocking %s\n", name+1);
112 setLock(locks, lock);
117 __private_extern__ void
118 _checklock_debug(mutex_t lock, const char *name)
120 _objc_lock_list *locks = getLocks(NO);
121 if (!hasLock(locks, lock)) _objc_fatal("%s incorrectly not held\n",name+1);
125 __private_extern__ void
126 _checkunlock_debug(mutex_t lock, const char *name)
128 _objc_lock_list *locks = getLocks(NO);
129 if (hasLock(locks, lock)) _objc_fatal("%s incorrectly held\n", name+1);
133 __private_extern__ void
134 _unlock_debug(mutex_t lock, const char *name)
136 _objc_lock_list *locks = getLocks(NO);
137 if (!hasLock(locks, lock)) _objc_fatal("unlocking unowned %s\n", name+1);
138 clearLock(locks, lock);
143 __private_extern__ void
144 _destroyLockList(struct _objc_lock_list *locks)
146 // fixme complain about any still-held locks?
147 if (locks) _free_internal(locks);