1 /*
2 * Copyright (c) 1998-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <IOKit/system.h>
30
31 #include <IOKit/IOReturn.h>
32 #include <IOKit/IOLib.h>
33 #include <IOKit/assert.h>
34
35 #include <IOKit/IOLocksPrivate.h>
36
37 extern "C" {
38 #include <kern/locks.h>
39
40 #if defined(__x86_64__)
41 /* Synthetic event if none is specified, for backwards compatibility only. */
42 static bool IOLockSleep_NO_EVENT __attribute__((used)) = 0;
43 #endif
44
45 void
IOLockInitWithState(IOLock * lock,IOLockState state)46 IOLockInitWithState( IOLock * lock, IOLockState state)
47 {
48 if (state == kIOLockStateLocked) {
49 lck_mtx_lock( lock);
50 }
51 }
52
53 IOLock *
IOLockAlloc(void)54 IOLockAlloc( void )
55 {
56 return lck_mtx_alloc_init(IOLockGroup, LCK_ATTR_NULL);
57 }
58
59 void
IOLockInlineInit(IOLock * lock)60 IOLockInlineInit( IOLock *lock )
61 {
62 lck_mtx_init(lock, IOLockGroup, LCK_ATTR_NULL);
63 }
64
65 void
IOLockInlineDestroy(IOLock * lock)66 IOLockInlineDestroy( IOLock * lock)
67 {
68 lck_mtx_destroy( lock, IOLockGroup);
69 }
70
71 void
IOLockFree(IOLock * lock)72 IOLockFree( IOLock * lock)
73 {
74 lck_mtx_free( lock, IOLockGroup);
75 }
76
77 lck_mtx_t *
IOLockGetMachLock(IOLock * lock)78 IOLockGetMachLock( IOLock * lock)
79 {
80 return (lck_mtx_t *)lock;
81 }
82
83 int
IOLockSleep(IOLock * lock,void * event,UInt32 interType)84 IOLockSleep( IOLock * lock, void *event, UInt32 interType)
85 {
86 return (int) lck_mtx_sleep(lock, LCK_SLEEP_PROMOTED_PRI, (event_t) event, (wait_interrupt_t) interType);
87 }
88
89 int
IOLockSleepDeadline(IOLock * lock,void * event,AbsoluteTime deadline,UInt32 interType)90 IOLockSleepDeadline( IOLock * lock, void *event,
91 AbsoluteTime deadline, UInt32 interType)
92 {
93 return (int) lck_mtx_sleep_deadline(lock, LCK_SLEEP_PROMOTED_PRI, (event_t) event,
94 (wait_interrupt_t) interType, __OSAbsoluteTime(deadline));
95 }
96
97 int
IOLockSleepWithInheritor(IOLock * lock,UInt32 lck_sleep_action,void * event,thread_t inheritor,UInt32 interType,uint64_t deadline)98 IOLockSleepWithInheritor( IOLock *lock, UInt32 lck_sleep_action,
99 void *event, thread_t inheritor, UInt32 interType, uint64_t deadline)
100 {
101 return (int) lck_mtx_sleep_with_inheritor(lock, (lck_sleep_action_t) lck_sleep_action, (event_t) event, inheritor,
102 (wait_interrupt_t) interType, deadline);
103 }
104
105 void
IOLockWakeup(IOLock * lock,void * event,bool oneThread)106 IOLockWakeup(IOLock * lock, void *event, bool oneThread)
107 {
108 thread_wakeup_prim((event_t) event, oneThread, THREAD_AWAKENED);
109 }
110
111 void
IOLockWakeupAllWithInheritor(IOLock * lock,void * event)112 IOLockWakeupAllWithInheritor(IOLock * lock, void *event)
113 {
114 wakeup_all_with_inheritor((event_t) event, THREAD_AWAKENED);
115 }
116
117
118 #if defined(__x86_64__)
119 /*
120 * For backwards compatibility, kexts built against pre-Darwin 14 headers will bind at runtime to this function,
121 * which supports a NULL event,
122 */
123 int IOLockSleep_legacy_x86_64( IOLock * lock, void *event, UInt32 interType) __asm("_IOLockSleep");
124 int IOLockSleepDeadline_legacy_x86_64( IOLock * lock, void *event,
125 AbsoluteTime deadline, UInt32 interType) __asm("_IOLockSleepDeadline");
126 void IOLockWakeup_legacy_x86_64(IOLock * lock, void *event, bool oneThread) __asm("_IOLockWakeup");
127
128 int
IOLockSleep_legacy_x86_64(IOLock * lock,void * event,UInt32 interType)129 IOLockSleep_legacy_x86_64( IOLock * lock, void *event, UInt32 interType)
130 {
131 if (event == NULL) {
132 event = (void *)&IOLockSleep_NO_EVENT;
133 }
134
135 return IOLockSleep(lock, event, interType);
136 }
137
138 int
IOLockSleepDeadline_legacy_x86_64(IOLock * lock,void * event,AbsoluteTime deadline,UInt32 interType)139 IOLockSleepDeadline_legacy_x86_64( IOLock * lock, void *event,
140 AbsoluteTime deadline, UInt32 interType)
141 {
142 if (event == NULL) {
143 event = (void *)&IOLockSleep_NO_EVENT;
144 }
145
146 return IOLockSleepDeadline(lock, event, deadline, interType);
147 }
148
149 void
IOLockWakeup_legacy_x86_64(IOLock * lock,void * event,bool oneThread)150 IOLockWakeup_legacy_x86_64(IOLock * lock, void *event, bool oneThread)
151 {
152 if (event == NULL) {
153 event = (void *)&IOLockSleep_NO_EVENT;
154 }
155
156 IOLockWakeup(lock, event, oneThread);
157 }
158 #endif /* defined(__x86_64__) */
159
160
161 struct _IORecursiveLock {
162 lck_mtx_t mutex;
163 lck_grp_t *group;
164 thread_t thread;
165 UInt32 count;
166 };
167
168 IORecursiveLock *
IORecursiveLockAllocWithLockGroup(lck_grp_t * lockGroup)169 IORecursiveLockAllocWithLockGroup( lck_grp_t * lockGroup )
170 {
171 _IORecursiveLock * lock;
172
173 if (lockGroup == NULL) {
174 return NULL;
175 }
176
177 lock = IOMallocType( _IORecursiveLock );
178 if (!lock) {
179 return NULL;
180 }
181
182 lck_mtx_init( &lock->mutex, lockGroup, LCK_ATTR_NULL );
183 lock->group = lockGroup;
184 lock->thread = NULL;
185 lock->count = 0;
186
187 return (IORecursiveLock *) lock;
188 }
189
190
191 IORecursiveLock *
IORecursiveLockAlloc(void)192 IORecursiveLockAlloc( void )
193 {
194 return IORecursiveLockAllocWithLockGroup( IOLockGroup );
195 }
196
197 void
IORecursiveLockFree(IORecursiveLock * _lock)198 IORecursiveLockFree( IORecursiveLock * _lock )
199 {
200 _IORecursiveLock * lock = (_IORecursiveLock *)_lock;
201
202 lck_mtx_destroy(&lock->mutex, lock->group);
203 IOFreeType( lock, _IORecursiveLock );
204 }
205
206 lck_mtx_t *
IORecursiveLockGetMachLock(IORecursiveLock * lock)207 IORecursiveLockGetMachLock( IORecursiveLock * lock )
208 {
209 return &lock->mutex;
210 }
211
212 void
IORecursiveLockLock(IORecursiveLock * _lock)213 IORecursiveLockLock( IORecursiveLock * _lock)
214 {
215 _IORecursiveLock * lock = (_IORecursiveLock *)_lock;
216
217 if (lock->thread == IOThreadSelf()) {
218 lock->count++;
219 } else {
220 lck_mtx_lock( &lock->mutex );
221 assert( lock->thread == NULL );
222 assert( lock->count == 0 );
223 lock->thread = IOThreadSelf();
224 lock->count = 1;
225 }
226 }
227
228 boolean_t
IORecursiveLockTryLock(IORecursiveLock * _lock)229 IORecursiveLockTryLock( IORecursiveLock * _lock)
230 {
231 _IORecursiveLock * lock = (_IORecursiveLock *)_lock;
232
233 if (lock->thread == IOThreadSelf()) {
234 lock->count++;
235 return true;
236 } else {
237 if (lck_mtx_try_lock( &lock->mutex )) {
238 assert( lock->thread == NULL );
239 assert( lock->count == 0 );
240 lock->thread = IOThreadSelf();
241 lock->count = 1;
242 return true;
243 }
244 }
245 return false;
246 }
247
248 void
IORecursiveLockUnlock(IORecursiveLock * _lock)249 IORecursiveLockUnlock( IORecursiveLock * _lock)
250 {
251 _IORecursiveLock * lock = (_IORecursiveLock *)_lock;
252
253 assert( lock->thread == IOThreadSelf());
254
255 if (0 == (--lock->count)) {
256 lock->thread = NULL;
257 lck_mtx_unlock( &lock->mutex );
258 }
259 }
260
261 boolean_t
IORecursiveLockHaveLock(const IORecursiveLock * _lock)262 IORecursiveLockHaveLock( const IORecursiveLock * _lock)
263 {
264 _IORecursiveLock * lock = (_IORecursiveLock *)_lock;
265
266 return lock->thread == IOThreadSelf();
267 }
268
269 int
IORecursiveLockSleep(IORecursiveLock * _lock,void * event,UInt32 interType)270 IORecursiveLockSleep(IORecursiveLock *_lock, void *event, UInt32 interType)
271 {
272 _IORecursiveLock * lock = (_IORecursiveLock *)_lock;
273 UInt32 count = lock->count;
274 int res;
275
276 assert(lock->thread == IOThreadSelf());
277
278 lock->count = 0;
279 lock->thread = NULL;
280 res = lck_mtx_sleep(&lock->mutex, LCK_SLEEP_PROMOTED_PRI, (event_t) event, (wait_interrupt_t) interType);
281
282 // Must re-establish the recursive lock no matter why we woke up
283 // otherwise we would potentially leave the return path corrupted.
284 assert(lock->thread == NULL);
285 assert(lock->count == 0);
286 lock->thread = IOThreadSelf();
287 lock->count = count;
288 return res;
289 }
290
291 int
IORecursiveLockSleepDeadline(IORecursiveLock * _lock,void * event,AbsoluteTime deadline,UInt32 interType)292 IORecursiveLockSleepDeadline( IORecursiveLock * _lock, void *event,
293 AbsoluteTime deadline, UInt32 interType)
294 {
295 _IORecursiveLock * lock = (_IORecursiveLock *)_lock;
296 UInt32 count = lock->count;
297 int res;
298
299 assert(lock->thread == IOThreadSelf());
300
301 lock->count = 0;
302 lock->thread = NULL;
303 res = lck_mtx_sleep_deadline(&lock->mutex, LCK_SLEEP_PROMOTED_PRI, (event_t) event,
304 (wait_interrupt_t) interType, __OSAbsoluteTime(deadline));
305
306 // Must re-establish the recursive lock no matter why we woke up
307 // otherwise we would potentially leave the return path corrupted.
308 assert(lock->thread == NULL);
309 assert(lock->count == 0);
310 lock->thread = IOThreadSelf();
311 lock->count = count;
312 return res;
313 }
314
315 void
IORecursiveLockWakeup(IORecursiveLock *,void * event,bool oneThread)316 IORecursiveLockWakeup(IORecursiveLock *, void *event, bool oneThread)
317 {
318 thread_wakeup_prim((event_t) event, oneThread, THREAD_AWAKENED);
319 }
320
321 /*
322 * Complex (read/write) lock operations
323 */
324
325 IORWLock *
IORWLockAlloc(void)326 IORWLockAlloc( void )
327 {
328 return lck_rw_alloc_init(IOLockGroup, LCK_ATTR_NULL);
329 }
330
331 void
IORWLockInlineInit(IORWLock * lock)332 IORWLockInlineInit( IORWLock *lock )
333 {
334 lck_rw_init(lock, IOLockGroup, LCK_ATTR_NULL);
335 }
336
337 void
IORWLockInlineDestroy(IORWLock * lock)338 IORWLockInlineDestroy( IORWLock * lock)
339 {
340 lck_rw_destroy( lock, IOLockGroup);
341 }
342
343 void
IORWLockFree(IORWLock * lock)344 IORWLockFree( IORWLock * lock)
345 {
346 lck_rw_free( lock, IOLockGroup);
347 }
348
349 lck_rw_t *
IORWLockGetMachLock(IORWLock * lock)350 IORWLockGetMachLock( IORWLock * lock)
351 {
352 return (lck_rw_t *)lock;
353 }
354
355
356 /*
357 * Spin locks
358 */
359
360 IOSimpleLock *
IOSimpleLockAlloc(void)361 IOSimpleLockAlloc( void )
362 {
363 return lck_spin_alloc_init( IOLockGroup, LCK_ATTR_NULL);
364 }
365
366 void
IOSimpleLockInit(IOSimpleLock * lock)367 IOSimpleLockInit( IOSimpleLock * lock)
368 {
369 lck_spin_init( lock, IOLockGroup, LCK_ATTR_NULL);
370 }
371
372 void
IOSimpleLockDestroy(IOSimpleLock * lock)373 IOSimpleLockDestroy( IOSimpleLock * lock )
374 {
375 lck_spin_destroy(lock, IOLockGroup);
376 }
377
378 void
IOSimpleLockFree(IOSimpleLock * lock)379 IOSimpleLockFree( IOSimpleLock * lock )
380 {
381 lck_spin_free( lock, IOLockGroup);
382 }
383
384 lck_spin_t *
IOSimpleLockGetMachLock(IOSimpleLock * lock)385 IOSimpleLockGetMachLock( IOSimpleLock * lock)
386 {
387 return (lck_spin_t *)lock;
388 }
389
390 #ifndef IOLOCKS_INLINE
391 /*
392 * Lock assertions
393 */
394
395 void
IOLockAssert(IOLock * lock,IOLockAssertState type)396 IOLockAssert(IOLock * lock, IOLockAssertState type)
397 {
398 LCK_MTX_ASSERT(lock, type);
399 }
400
401 void
IORWLockAssert(IORWLock * lock,IORWLockAssertState type)402 IORWLockAssert(IORWLock * lock, IORWLockAssertState type)
403 {
404 LCK_RW_ASSERT(lock, type);
405 }
406
407 void
IOSimpleLockAssert(IOSimpleLock * lock,IOSimpleLockAssertState type)408 IOSimpleLockAssert(IOSimpleLock *lock, IOSimpleLockAssertState type)
409 {
410 LCK_SPIN_ASSERT(l, type);
411 }
412 #endif /* !IOLOCKS_INLINE */
413 } /* extern "C" */
414