]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-lockdebug.m
014518c11b6933e78f4c610847c508e0c76311fa
[apple/objc4.git] / runtime / objc-lockdebug.m
1 /*
2 * Copyright (c) 2007 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 * objc-lock.m
26 * Error-checking locks for debugging.
27 **********************************************************************/
28
29 #import "objc-private.h"
30
31 typedef struct _objc_lock_list {
32 int allocated;
33 int used;
34 mutex_t list[0]; // variable-size
35 } _objc_lock_list;
36
37 static struct _objc_lock_list *
38 getLocks(BOOL create)
39 {
40 _objc_pthread_data *data;
41 _objc_lock_list *locks;
42
43 data = _objc_fetch_pthread_data(create);
44 if (!data && !create) return NULL;
45
46 locks = data->lockList;
47 if (!locks) {
48 if (!create) {
49 return NULL;
50 } else {
51 locks = _calloc_internal(1, sizeof(_objc_lock_list) + sizeof(mutex_t) * 4);
52 locks->allocated = 4;
53 locks->used = 0;
54 data->lockList = locks;
55 }
56 }
57
58 if (locks->allocated == locks->used) {
59 if (!create) {
60 return locks;
61 } else {
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;
68 }
69 }
70
71 return locks;
72 }
73
74
75 static BOOL
76 hasLock(_objc_lock_list *locks, mutex_t lock)
77 {
78 int i;
79 if (!locks) return NO;
80
81 for (i = 0; i < locks->used; i++) {
82 if (locks->list[i] == lock) return YES;
83 }
84 return NO;
85 }
86
87
88 static void
89 setLock(_objc_lock_list *locks, mutex_t lock)
90 {
91 locks->list[locks->used++] = lock;
92 }
93
94 static void
95 clearLock(_objc_lock_list *locks, mutex_t lock)
96 {
97 int i;
98 for (i = 0; i < locks->used; i++) {
99 if (locks->list[i] == lock) {
100 locks->list[i] = locks->list[--locks->used];
101 return;
102 }
103 }
104 }
105
106
107 __private_extern__ void
108 _lock_debug(mutex_t lock, const char *name)
109 {
110 _objc_lock_list *locks = getLocks(YES);
111 if (hasLock(locks, lock)) _objc_fatal("deadlock: relocking %s\n", name+1);
112 setLock(locks, lock);
113 mutex_lock(lock);
114 }
115
116
117 __private_extern__ void
118 _checklock_debug(mutex_t lock, const char *name)
119 {
120 _objc_lock_list *locks = getLocks(NO);
121 if (!hasLock(locks, lock)) _objc_fatal("%s incorrectly not held\n",name+1);
122 }
123
124
125 __private_extern__ void
126 _checkunlock_debug(mutex_t lock, const char *name)
127 {
128 _objc_lock_list *locks = getLocks(NO);
129 if (hasLock(locks, lock)) _objc_fatal("%s incorrectly held\n", name+1);
130 }
131
132
133 __private_extern__ void
134 _unlock_debug(mutex_t lock, const char *name)
135 {
136 _objc_lock_list *locks = getLocks(NO);
137 if (!hasLock(locks, lock)) _objc_fatal("unlocking unowned %s\n", name+1);
138 clearLock(locks, lock);
139 mutex_unlock(lock);
140 }
141
142
143 __private_extern__ void
144 _destroyLockList(struct _objc_lock_list *locks)
145 {
146 // fixme complain about any still-held locks?
147 if (locks) _free_internal(locks);
148 }