]>
Commit | Line | Data |
---|---|---|
9385eb3d | 1 | /* |
b5d655f7 | 2 | * Copyright (c) 2000-2003, 2007, 2008 Apple Inc. All rights reserved. |
9385eb3d A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
9385eb3d A |
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 | */ | |
e9ce8d39 A |
23 | /* |
24 | * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991 | |
25 | * All Rights Reserved | |
26 | * | |
27 | * Permission to use, copy, modify, and distribute this software and | |
28 | * its documentation for any purpose and without fee is hereby granted, | |
29 | * provided that the above copyright notice appears in all copies and | |
30 | * that both the copyright notice and this permission notice appear in | |
31 | * supporting documentation. | |
32 | * | |
33 | * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE | |
34 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
35 | * FOR A PARTICULAR PURPOSE. | |
36 | * | |
37 | * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR | |
38 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | |
39 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, | |
40 | * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION | |
41 | * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
42 | * | |
43 | */ | |
44 | /* | |
45 | * MkLinux | |
46 | */ | |
47 | ||
48 | /* | |
49 | * POSIX Pthread Library | |
50 | * -- Mutex variable support | |
51 | */ | |
52 | ||
53 | #include "pthread_internals.h" | |
54 | ||
b5d655f7 | 55 | #ifdef PLOCKSTAT |
224c7076 | 56 | #include "plockstat.h" |
b5d655f7 A |
57 | #else /* !PLOCKSTAT */ |
58 | #define PLOCKSTAT_MUTEX_SPIN(x) | |
59 | #define PLOCKSTAT_MUTEX_SPUN(x, y, z) | |
60 | #define PLOCKSTAT_MUTEX_ERROR(x, y) | |
61 | #define PLOCKSTAT_MUTEX_BLOCK(x) | |
62 | #define PLOCKSTAT_MUTEX_BLOCKED(x, y) | |
63 | #define PLOCKSTAT_MUTEX_ACQUIRE(x, y, z) | |
64 | #define PLOCKSTAT_MUTEX_RELEASE(x, y) | |
65 | #endif /* PLOCKSTAT */ | |
224c7076 A |
66 | |
67 | extern int __unix_conforming; | |
34e8f829 | 68 | extern int __unix_conforming; |
34e8f829 | 69 | |
1f2f436a A |
70 | #ifndef BUILDING_VARIANT |
71 | __private_extern__ int usenew_mtximpl = 1; | |
72 | static void __pthread_mutex_set_signature(npthread_mutex_t * mutex); | |
73 | int __mtx_markprepost(npthread_mutex_t *mutex, uint32_t oupdateval, int firstfit); | |
74 | static int _pthread_mutex_destroy_locked(pthread_mutex_t *omutex); | |
75 | #else /* BUILDING_VARIANT */ | |
76 | extern int usenew_mtximpl; | |
77 | #endif /* BUILDING_VARIANT */ | |
78 | ||
79 | ||
80 | #ifdef NOTNEEDED | |
34e8f829 | 81 | #define USE_COMPAGE 1 |
1f2f436a A |
82 | extern int _commpage_pthread_mutex_lock(uint32_t * lvalp, int flags, uint64_t mtid, uint32_t mask, uint64_t * tidp, int *sysret); |
83 | #endif | |
34e8f829 A |
84 | |
85 | #include <machine/cpu_capabilities.h> | |
86 | ||
1f2f436a | 87 | int _pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr, uint32_t static_type); |
34e8f829 | 88 | |
34e8f829 A |
89 | |
90 | #if defined(__LP64__) | |
91 | #define MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr) \ | |
92 | { \ | |
93 | if (mutex->mtxopts.options.misalign != 0) { \ | |
94 | lseqaddr = &mutex->m_seq[0]; \ | |
95 | useqaddr = &mutex->m_seq[1]; \ | |
96 | } else { \ | |
97 | lseqaddr = &mutex->m_seq[1]; \ | |
98 | useqaddr = &mutex->m_seq[2]; \ | |
99 | } \ | |
100 | } | |
101 | #else /* __LP64__ */ | |
102 | #define MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr) \ | |
103 | { \ | |
104 | if (mutex->mtxopts.options.misalign != 0) { \ | |
105 | lseqaddr = &mutex->m_seq[1]; \ | |
106 | useqaddr = &mutex->m_seq[2]; \ | |
107 | }else { \ | |
108 | lseqaddr = &mutex->m_seq[0]; \ | |
109 | useqaddr = &mutex->m_seq[1]; \ | |
110 | } \ | |
111 | } | |
112 | #endif /* __LP64__ */ | |
113 | ||
114 | #define _KSYN_TRACE_ 0 | |
115 | ||
116 | #if _KSYN_TRACE_ | |
117 | /* The Function qualifiers */ | |
118 | #define DBG_FUNC_START 1 | |
119 | #define DBG_FUNC_END 2 | |
120 | #define DBG_FUNC_NONE 0 | |
121 | ||
122 | int __kdebug_trace(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); | |
123 | ||
124 | #define _KSYN_TRACE_UM_LOCK 0x9000060 | |
125 | #define _KSYN_TRACE_UM_UNLOCK 0x9000064 | |
126 | #define _KSYN_TRACE_UM_MHOLD 0x9000068 | |
127 | #define _KSYN_TRACE_UM_MDROP 0x900006c | |
128 | #define _KSYN_TRACE_UM_MUBITS 0x900007c | |
1f2f436a | 129 | #define _KSYN_TRACE_UM_MARKPP 0x90000a8 |
34e8f829 A |
130 | |
131 | #endif /* _KSYN_TRACE_ */ | |
132 | ||
224c7076 A |
133 | #ifndef BUILDING_VARIANT /* [ */ |
134 | ||
135 | #define BLOCK_FAIL_PLOCKSTAT 0 | |
136 | #define BLOCK_SUCCESS_PLOCKSTAT 1 | |
137 | ||
34e8f829 A |
138 | #ifdef PR_5243343 |
139 | /* 5243343 - temporary hack to detect if we are running the conformance test */ | |
140 | extern int PR_5243343_flag; | |
141 | #endif /* PR_5243343 */ | |
142 | ||
224c7076 A |
143 | /* This function is never called and exists to provide never-fired dtrace |
144 | * probes so that user d scripts don't get errors. | |
145 | */ | |
146 | __private_extern__ void _plockstat_never_fired(void) | |
147 | { | |
148 | PLOCKSTAT_MUTEX_SPIN(NULL); | |
149 | PLOCKSTAT_MUTEX_SPUN(NULL, 0, 0); | |
150 | } | |
151 | ||
e9ce8d39 A |
152 | |
153 | /* | |
154 | * Initialize a mutex variable, possibly with additional attributes. | |
9385eb3d | 155 | * Public interface - so don't trust the lock - initialize it first. |
e9ce8d39 A |
156 | */ |
157 | int | |
158 | pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) | |
159 | { | |
224c7076 A |
160 | #if 0 |
161 | /* conformance tests depend on not having this behavior */ | |
162 | /* The test for this behavior is optional */ | |
163 | if (mutex->sig == _PTHREAD_MUTEX_SIG) | |
164 | return EBUSY; | |
165 | #endif | |
9385eb3d | 166 | LOCK_INIT(mutex->lock); |
1f2f436a | 167 | return (_pthread_mutex_init(mutex, attr, 0x7)); |
e9ce8d39 A |
168 | } |
169 | ||
170 | /* | |
171 | * Fetch the priority ceiling value from a mutex variable. | |
172 | * Note: written as a 'helper' function to hide implementation details. | |
173 | */ | |
174 | int | |
175 | pthread_mutex_getprioceiling(const pthread_mutex_t *mutex, | |
176 | int *prioceiling) | |
177 | { | |
9385eb3d A |
178 | int res; |
179 | ||
180 | LOCK(mutex->lock); | |
e9ce8d39 A |
181 | if (mutex->sig == _PTHREAD_MUTEX_SIG) |
182 | { | |
183 | *prioceiling = mutex->prioceiling; | |
224c7076 | 184 | res = 0; |
e9ce8d39 | 185 | } else |
9385eb3d A |
186 | res = EINVAL; /* Not an initialized 'attribute' structure */ |
187 | UNLOCK(mutex->lock); | |
188 | return (res); | |
e9ce8d39 A |
189 | } |
190 | ||
191 | /* | |
192 | * Set the priority ceiling for a mutex. | |
193 | * Note: written as a 'helper' function to hide implementation details. | |
194 | */ | |
195 | int | |
196 | pthread_mutex_setprioceiling(pthread_mutex_t *mutex, | |
197 | int prioceiling, | |
198 | int *old_prioceiling) | |
199 | { | |
9385eb3d A |
200 | int res; |
201 | ||
202 | LOCK(mutex->lock); | |
e9ce8d39 A |
203 | if (mutex->sig == _PTHREAD_MUTEX_SIG) |
204 | { | |
205 | if ((prioceiling >= -999) || | |
206 | (prioceiling <= 999)) | |
207 | { | |
208 | *old_prioceiling = mutex->prioceiling; | |
209 | mutex->prioceiling = prioceiling; | |
224c7076 | 210 | res = 0; |
e9ce8d39 | 211 | } else |
9385eb3d | 212 | res = EINVAL; /* Invalid parameter */ |
e9ce8d39 | 213 | } else |
9385eb3d A |
214 | res = EINVAL; /* Not an initialized 'attribute' structure */ |
215 | UNLOCK(mutex->lock); | |
216 | return (res); | |
e9ce8d39 A |
217 | } |
218 | ||
e9ce8d39 A |
219 | /* |
220 | * Get the priority ceiling value from a mutex attribute structure. | |
221 | * Note: written as a 'helper' function to hide implementation details. | |
222 | */ | |
223 | int | |
224 | pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, | |
225 | int *prioceiling) | |
226 | { | |
227 | if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) | |
228 | { | |
229 | *prioceiling = attr->prioceiling; | |
224c7076 | 230 | return (0); |
e9ce8d39 A |
231 | } else |
232 | { | |
233 | return (EINVAL); /* Not an initialized 'attribute' structure */ | |
234 | } | |
235 | } | |
236 | ||
237 | /* | |
238 | * Get the mutex 'protocol' value from a mutex attribute structure. | |
239 | * Note: written as a 'helper' function to hide implementation details. | |
240 | */ | |
241 | int | |
242 | pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, | |
243 | int *protocol) | |
244 | { | |
245 | if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) | |
246 | { | |
247 | *protocol = attr->protocol; | |
224c7076 | 248 | return (0); |
e9ce8d39 A |
249 | } else |
250 | { | |
251 | return (EINVAL); /* Not an initialized 'attribute' structure */ | |
252 | } | |
253 | } | |
5b2abdfb A |
254 | /* |
255 | * Get the mutex 'type' value from a mutex attribute structure. | |
256 | * Note: written as a 'helper' function to hide implementation details. | |
257 | */ | |
258 | int | |
259 | pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, | |
260 | int *type) | |
261 | { | |
262 | if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) | |
263 | { | |
264 | *type = attr->type; | |
224c7076 | 265 | return (0); |
5b2abdfb A |
266 | } else |
267 | { | |
268 | return (EINVAL); /* Not an initialized 'attribute' structure */ | |
269 | } | |
270 | } | |
271 | ||
272 | /* | |
273 | * | |
274 | */ | |
275 | int | |
276 | pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared) | |
277 | { | |
278 | if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) | |
279 | { | |
224c7076 A |
280 | *pshared = (int)attr->pshared; |
281 | return (0); | |
5b2abdfb A |
282 | } else |
283 | { | |
284 | return (EINVAL); /* Not an initialized 'attribute' structure */ | |
285 | } | |
286 | } | |
e9ce8d39 A |
287 | |
288 | /* | |
289 | * Initialize a mutex attribute structure to system defaults. | |
290 | */ | |
291 | int | |
292 | pthread_mutexattr_init(pthread_mutexattr_t *attr) | |
293 | { | |
294 | attr->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING; | |
295 | attr->protocol = _PTHREAD_DEFAULT_PROTOCOL; | |
34e8f829 | 296 | attr->policy = _PTHREAD_MUTEX_POLICY_FAIRSHARE; |
5b2abdfb | 297 | attr->type = PTHREAD_MUTEX_DEFAULT; |
e9ce8d39 | 298 | attr->sig = _PTHREAD_MUTEX_ATTR_SIG; |
224c7076 A |
299 | attr->pshared = _PTHREAD_DEFAULT_PSHARED; |
300 | return (0); | |
e9ce8d39 A |
301 | } |
302 | ||
303 | /* | |
304 | * Set the priority ceiling value in a mutex attribute structure. | |
305 | * Note: written as a 'helper' function to hide implementation details. | |
306 | */ | |
307 | int | |
308 | pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, | |
309 | int prioceiling) | |
310 | { | |
311 | if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) | |
312 | { | |
313 | if ((prioceiling >= -999) || | |
314 | (prioceiling <= 999)) | |
315 | { | |
316 | attr->prioceiling = prioceiling; | |
224c7076 | 317 | return (0); |
e9ce8d39 A |
318 | } else |
319 | { | |
320 | return (EINVAL); /* Invalid parameter */ | |
321 | } | |
322 | } else | |
323 | { | |
324 | return (EINVAL); /* Not an initialized 'attribute' structure */ | |
325 | } | |
326 | } | |
327 | ||
328 | /* | |
329 | * Set the mutex 'protocol' value in a mutex attribute structure. | |
330 | * Note: written as a 'helper' function to hide implementation details. | |
331 | */ | |
332 | int | |
333 | pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, | |
334 | int protocol) | |
335 | { | |
336 | if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) | |
337 | { | |
338 | if ((protocol == PTHREAD_PRIO_NONE) || | |
339 | (protocol == PTHREAD_PRIO_INHERIT) || | |
340 | (protocol == PTHREAD_PRIO_PROTECT)) | |
341 | { | |
342 | attr->protocol = protocol; | |
224c7076 | 343 | return (0); |
e9ce8d39 A |
344 | } else |
345 | { | |
346 | return (EINVAL); /* Invalid parameter */ | |
347 | } | |
348 | } else | |
349 | { | |
350 | return (EINVAL); /* Not an initialized 'attribute' structure */ | |
351 | } | |
352 | } | |
34e8f829 | 353 | |
34e8f829 A |
354 | int |
355 | pthread_mutexattr_setpolicy_np(pthread_mutexattr_t *attr, | |
356 | int policy) | |
357 | { | |
358 | if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) | |
359 | { | |
1f2f436a A |
360 | if ( |
361 | (policy == _PTHREAD_MUTEX_POLICY_FAIRSHARE) || | |
362 | (policy == _PTHREAD_MUTEX_POLICY_FIRSTFIT) | |
363 | #if NOTYET | |
364 | || | |
34e8f829 A |
365 | (policy == _PTHREAD_MUTEX_POLICY_REALTIME) || |
366 | (policy == _PTHREAD_MUTEX_POLICY_ADAPTIVE) || | |
367 | (policy == _PTHREAD_MUTEX_POLICY_PRIPROTECT) || | |
1f2f436a A |
368 | (policy == _PTHREAD_MUTEX_POLICY_PRIINHERIT) |
369 | #endif /* NOTYET */ | |
370 | ) | |
34e8f829 A |
371 | { |
372 | attr->policy = policy; | |
373 | return (0); | |
374 | } else | |
375 | { | |
376 | return (EINVAL); /* Invalid parameter */ | |
377 | } | |
378 | } else | |
379 | { | |
380 | return (EINVAL); /* Not an initialized 'attribute' structure */ | |
381 | } | |
382 | } | |
34e8f829 | 383 | |
5b2abdfb A |
384 | /* |
385 | * Set the mutex 'type' value in a mutex attribute structure. | |
386 | * Note: written as a 'helper' function to hide implementation details. | |
387 | */ | |
388 | int | |
389 | pthread_mutexattr_settype(pthread_mutexattr_t *attr, | |
390 | int type) | |
391 | { | |
392 | if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) | |
393 | { | |
394 | if ((type == PTHREAD_MUTEX_NORMAL) || | |
395 | (type == PTHREAD_MUTEX_ERRORCHECK) || | |
396 | (type == PTHREAD_MUTEX_RECURSIVE) || | |
397 | (type == PTHREAD_MUTEX_DEFAULT)) | |
398 | { | |
399 | attr->type = type; | |
224c7076 | 400 | return (0); |
5b2abdfb A |
401 | } else |
402 | { | |
403 | return (EINVAL); /* Invalid parameter */ | |
404 | } | |
405 | } else | |
406 | { | |
407 | return (EINVAL); /* Not an initialized 'attribute' structure */ | |
408 | } | |
409 | } | |
410 | ||
e9ce8d39 A |
411 | |
412 | int mutex_try_lock(int *x) { | |
413 | return _spin_lock_try((pthread_lock_t *)x); | |
414 | } | |
415 | ||
416 | void mutex_wait_lock(int *x) { | |
417 | for (;;) { | |
418 | if( _spin_lock_try((pthread_lock_t *)x)) { | |
419 | return; | |
420 | } | |
421 | swtch_pri(0); | |
422 | } | |
423 | } | |
424 | ||
5b2abdfb A |
425 | void |
426 | cthread_yield(void) | |
427 | { | |
428 | sched_yield(); | |
429 | } | |
430 | ||
431 | void | |
432 | pthread_yield_np (void) | |
433 | { | |
e9ce8d39 A |
434 | sched_yield(); |
435 | } | |
436 | ||
224c7076 A |
437 | |
438 | /* | |
439 | * Temp: till pshared is fixed correctly | |
440 | */ | |
441 | int | |
442 | pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) | |
443 | { | |
444 | #if __DARWIN_UNIX03 | |
445 | if (__unix_conforming == 0) | |
446 | __unix_conforming = 1; | |
447 | #endif /* __DARWIN_UNIX03 */ | |
448 | ||
449 | if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) | |
450 | { | |
451 | #if __DARWIN_UNIX03 | |
224c7076 | 452 | if (( pshared == PTHREAD_PROCESS_PRIVATE) || (pshared == PTHREAD_PROCESS_SHARED)) |
224c7076 A |
453 | #else /* __DARWIN_UNIX03 */ |
454 | if ( pshared == PTHREAD_PROCESS_PRIVATE) | |
455 | #endif /* __DARWIN_UNIX03 */ | |
1f2f436a | 456 | { |
224c7076 A |
457 | attr->pshared = pshared; |
458 | return (0); | |
1f2f436a | 459 | } else { |
224c7076 A |
460 | return (EINVAL); /* Invalid parameter */ |
461 | } | |
462 | } else | |
463 | { | |
464 | return (EINVAL); /* Not an initialized 'attribute' structure */ | |
465 | } | |
466 | } | |
467 | ||
34e8f829 A |
468 | /* |
469 | * Drop the mutex unlock references(from cond wait or mutex_unlock(). | |
34e8f829 A |
470 | * |
471 | */ | |
472 | __private_extern__ int | |
1f2f436a | 473 | __mtx_droplock(npthread_mutex_t * mutex, uint32_t diffgen, uint32_t * flagsp, uint32_t ** pmtxp, uint32_t * mgenp, uint32_t * ugenp) |
34e8f829 | 474 | { |
1f2f436a A |
475 | pthread_t self; |
476 | uint64_t selfid, resettid; | |
34e8f829 | 477 | int firstfit = (mutex->mtxopts.options.policy == _PTHREAD_MUTEX_POLICY_FIRSTFIT); |
1f2f436a A |
478 | uint32_t lgenval, ugenval, nlval, ulval, morewaiters=0, flags; |
479 | volatile uint32_t * lseqaddr, *useqaddr; | |
480 | uint64_t oldval64, newval64; | |
481 | int numwaiters=0, clearprepost = 0; | |
34e8f829 A |
482 | |
483 | #if _KSYN_TRACE_ | |
1f2f436a | 484 | (void)__kdebug_trace(_KSYN_TRACE_UM_MDROP | DBG_FUNC_START, (uint32_t)mutex, diffgen, 0, 0, 0); |
34e8f829 | 485 | #endif |
1f2f436a | 486 | MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr); |
34e8f829 | 487 | |
1f2f436a A |
488 | |
489 | flags = mutex->mtxopts.value; | |
490 | flags &= ~_PTHREAD_MTX_OPT_NOTIFY; /* no notification by default */ | |
491 | ||
492 | ||
34e8f829 A |
493 | if (mutex->mtxopts.options.type != PTHREAD_MUTEX_NORMAL) |
494 | { | |
1f2f436a A |
495 | self = pthread_self(); |
496 | (void) pthread_threadid_np(self, &selfid); | |
497 | ||
498 | if (mutex->m_tid != selfid) | |
34e8f829 | 499 | { |
1f2f436a | 500 | //LIBC_ABORT("dropping recur or error mutex not owned by the thread\n"); |
34e8f829 A |
501 | PLOCKSTAT_MUTEX_ERROR((pthread_mutex_t *)mutex, EPERM); |
502 | return(EPERM); | |
503 | } else if (mutex->mtxopts.options.type == PTHREAD_MUTEX_RECURSIVE && | |
504 | --mutex->mtxopts.options.lock_count) | |
505 | { | |
506 | PLOCKSTAT_MUTEX_RELEASE((pthread_mutex_t *)mutex, 1); | |
507 | goto out; | |
508 | } | |
509 | } | |
510 | ||
511 | ||
1f2f436a A |
512 | retry: |
513 | lgenval = *lseqaddr; | |
514 | ugenval = *useqaddr; | |
515 | ||
516 | numwaiters = diff_genseq((lgenval & PTHRW_COUNT_MASK),(ugenval & PTHRW_COUNT_MASK)); /* pendig waiters */ | |
517 | ||
518 | if (numwaiters == 0) { | |
519 | /* spurious unlocks, do not touch tid */ | |
520 | oldval64 = (((uint64_t)ugenval) << 32); | |
521 | oldval64 |= lgenval; | |
522 | if ((firstfit != 0) && ((lgenval & PTH_RWL_PBIT) != 0)) { | |
523 | clearprepost = 1; | |
524 | lgenval &= ~PTH_RWL_PBIT; | |
525 | newval64 = (((uint64_t)ugenval) << 32); | |
526 | newval64 |= lgenval; | |
527 | } else | |
528 | newval64 = oldval64; | |
529 | if (OSAtomicCompareAndSwap64(oldval64, newval64, (volatile int64_t *)lseqaddr) != TRUE) | |
530 | goto retry; | |
531 | /* validated L & U to be same, this is spurious unlock */ | |
532 | flags &= ~_PTHREAD_MTX_OPT_NOTIFY; | |
533 | if (clearprepost == 1) | |
534 | __psynch_cvclrprepost(mutex, lgenval, ugenval, 0, 0, lgenval, (flags | _PTHREAD_MTX_OPT_MUTEX)); | |
535 | ||
536 | goto out; | |
537 | } | |
34e8f829 | 538 | |
1f2f436a | 539 | if (numwaiters < diffgen) { |
34e8f829 | 540 | #if _KSYN_TRACE_ |
1f2f436a | 541 | (void)__kdebug_trace(_KSYN_TRACE_UM_MDROP | DBG_FUNC_NONE, (uint32_t)mutex, numwaiters, lgenval, ugenval, 0); |
34e8f829 | 542 | #endif |
1f2f436a A |
543 | /* cannot drop more than existing number of waiters */ |
544 | diffgen = numwaiters; | |
545 | } | |
34e8f829 | 546 | |
1f2f436a A |
547 | oldval64 = (((uint64_t)ugenval) << 32); |
548 | oldval64 |= lgenval; | |
549 | ulval = ugenval + diffgen; | |
550 | nlval = lgenval; | |
551 | ||
552 | if ((lgenval & PTHRW_COUNT_MASK) == (ulval & PTHRW_COUNT_MASK)) { | |
553 | /* do not reset Ibit, just K&E */ | |
554 | nlval &= ~(PTH_RWL_KBIT | PTH_RWL_EBIT); | |
555 | flags &= ~_PTHREAD_MTX_OPT_NOTIFY; | |
556 | if ((firstfit != 0) && ((lgenval & PTH_RWL_PBIT) != 0)) { | |
557 | clearprepost = 1; | |
558 | nlval &= ~PTH_RWL_PBIT; | |
34e8f829 | 559 | } |
1f2f436a A |
560 | } else { |
561 | /* need to signal others waiting for mutex */ | |
562 | morewaiters = 1; | |
563 | flags |= _PTHREAD_MTX_OPT_NOTIFY; | |
564 | } | |
34e8f829 | 565 | |
1f2f436a A |
566 | if (((nlval & PTH_RWL_EBIT) != 0) && (firstfit != 0)) { |
567 | nlval &= ~PTH_RWL_EBIT; /* reset Ebit so another can acquire meanwhile */ | |
568 | } | |
34e8f829 | 569 | |
1f2f436a A |
570 | newval64 = (((uint64_t)ulval) << 32); |
571 | newval64 |= nlval; | |
34e8f829 | 572 | |
1f2f436a A |
573 | resettid = mutex->m_tid; |
574 | ||
575 | if ((lgenval & PTHRW_COUNT_MASK) == (ulval & PTHRW_COUNT_MASK)) | |
576 | mutex->m_tid = 0; | |
577 | else if (firstfit == 0) | |
578 | mutex->m_tid = PTHREAD_MTX_TID_SWITCHING; | |
579 | ||
580 | if (OSAtomicCompareAndSwap64(oldval64, newval64, (volatile int64_t *)lseqaddr) != TRUE) { | |
581 | mutex->m_tid = resettid; | |
582 | goto retry; | |
583 | } | |
34e8f829 | 584 | |
34e8f829 A |
585 | |
586 | #if _KSYN_TRACE_ | |
1f2f436a A |
587 | (void)__kdebug_trace(_KSYN_TRACE_UM_MDROP | DBG_FUNC_NONE, (uint32_t)mutex, 2, lgenval, ugenval, 0); |
588 | (void)__kdebug_trace(_KSYN_TRACE_UM_MDROP | DBG_FUNC_NONE, (uint32_t)mutex, 2, nlval, ulval, 0); | |
34e8f829 | 589 | #endif |
34e8f829 | 590 | |
1f2f436a A |
591 | if (clearprepost != 0) { |
592 | __psynch_cvclrprepost(mutex, nlval, ulval, 0, 0, nlval, (flags | _PTHREAD_MTX_OPT_MUTEX)); | |
34e8f829 | 593 | } |
1f2f436a A |
594 | |
595 | if (mgenp != NULL) | |
596 | *mgenp = nlval; | |
597 | if (ugenp != NULL) | |
598 | *ugenp = ulval; | |
599 | #if USE_COMPAGE | |
600 | if (pmtxp != NULL) | |
601 | *pmtxp = lseqaddr; | |
602 | #else | |
603 | if (pmtxp != NULL) | |
604 | *pmtxp = (uint32_t *)mutex; | |
605 | #endif | |
606 | ||
34e8f829 | 607 | out: |
1f2f436a A |
608 | if (flagsp != NULL) |
609 | *flagsp = flags; | |
610 | ||
34e8f829 | 611 | #if _KSYN_TRACE_ |
1f2f436a | 612 | (void)__kdebug_trace(_KSYN_TRACE_UM_MDROP | DBG_FUNC_END, (uint32_t)mutex, flags, 0, 0, 0); |
34e8f829 A |
613 | #endif |
614 | return(0); | |
615 | } | |
616 | ||
617 | int | |
1f2f436a | 618 | __mtx_updatebits(npthread_mutex_t *mutex, uint32_t oupdateval, int firstfit, int fromcond, uint64_t selfid) |
34e8f829 | 619 | { |
34e8f829 | 620 | uint32_t updateval = oupdateval; |
1f2f436a | 621 | #if !USE_COMPAGE |
34e8f829 | 622 | pthread_mutex_t * omutex = (pthread_mutex_t *)mutex; |
1f2f436a A |
623 | #endif |
624 | int isebit = 0; | |
625 | uint32_t lgenval, ugenval, nval, uval, bits; | |
626 | volatile uint32_t * lseqaddr, *useqaddr; | |
627 | uint64_t oldval64, newval64; | |
628 | ||
629 | MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr); | |
34e8f829 | 630 | |
34e8f829 A |
631 | #if _KSYN_TRACE_ |
632 | (void)__kdebug_trace(_KSYN_TRACE_UM_MUBITS | DBG_FUNC_START, (uint32_t)mutex, oupdateval, firstfit, fromcond, 0); | |
633 | #endif | |
634 | ||
635 | retry: | |
636 | lgenval = *lseqaddr; | |
1f2f436a | 637 | ugenval = *useqaddr; |
34e8f829 A |
638 | bits = updateval & PTHRW_BIT_MASK; |
639 | ||
34e8f829 | 640 | #if _KSYN_TRACE_ |
1f2f436a | 641 | (void)__kdebug_trace(_KSYN_TRACE_UM_MUBITS | DBG_FUNC_NONE, (uint32_t)mutex, 1, lgenval, ugenval, 0); |
34e8f829 | 642 | #endif |
34e8f829 | 643 | |
1f2f436a A |
644 | |
645 | if ((updateval & PTH_RWL_MTX_WAIT) != 0) { | |
646 | lgenval = (updateval & PTHRW_COUNT_MASK) | (lgenval & PTHRW_BIT_MASK); | |
647 | if (fromcond == 0) { | |
648 | /* if from mutex_lock(), it will handle the rewind */ | |
649 | return(1); | |
650 | } | |
651 | /* go block in the kernel with same lgenval as returned */ | |
652 | goto ml1; | |
653 | } else { | |
654 | /* firsfit might not have EBIT */ | |
655 | if (firstfit != 0) { | |
656 | if ((lgenval & PTH_RWL_EBIT) != 0) | |
657 | isebit = 1; | |
658 | else | |
659 | isebit = 0; | |
660 | } else if ((lgenval & (PTH_RWL_KBIT|PTH_RWL_EBIT)) == (PTH_RWL_KBIT|PTH_RWL_EBIT)) { | |
661 | /* fairshare mutex and the bits are already set, just update tid */ | |
662 | goto out; | |
663 | } | |
34e8f829 A |
664 | } |
665 | ||
1f2f436a A |
666 | /* either firstfist or no E bit set */ |
667 | /* update the bits */ | |
668 | oldval64 = (((uint64_t)ugenval) << 32); | |
669 | oldval64 |= lgenval; | |
670 | uval = ugenval; | |
671 | nval = lgenval | (PTH_RWL_KBIT|PTH_RWL_EBIT); | |
672 | newval64 = (((uint64_t)uval) << 32); | |
673 | newval64 |= nval; | |
674 | ||
675 | /* set s and b bit */ | |
676 | if (OSAtomicCompareAndSwap64(oldval64, newval64, (volatile int64_t *)lseqaddr) == TRUE) { | |
34e8f829 | 677 | #if _KSYN_TRACE_ |
1f2f436a | 678 | (void)__kdebug_trace(_KSYN_TRACE_UM_MUBITS | DBG_FUNC_NONE, (uint32_t)mutex, 2, nval, uval, 0); |
34e8f829 | 679 | #endif |
1f2f436a | 680 | if ((firstfit != 0) && (isebit != 0)) |
34e8f829 | 681 | goto handleffit; |
34e8f829 | 682 | |
1f2f436a A |
683 | goto out; |
684 | } else { | |
685 | if (firstfit == 0) | |
686 | goto retry; | |
687 | else | |
688 | goto handleffit; | |
34e8f829 | 689 | } |
1f2f436a | 690 | |
34e8f829 | 691 | #if _KSYN_TRACE_ |
1f2f436a | 692 | (void)__kdebug_trace(_KSYN_TRACE_UM_MUBITS | DBG_FUNC_NONE, (uint32_t)mutex, 4, nval, uval, 0); |
34e8f829 | 693 | #endif |
1f2f436a | 694 | |
34e8f829 A |
695 | out: |
696 | /* succesful bits updation */ | |
1f2f436a | 697 | mutex->m_tid = selfid; |
34e8f829 A |
698 | #if _KSYN_TRACE_ |
699 | (void)__kdebug_trace(_KSYN_TRACE_UM_MUBITS | DBG_FUNC_END, (uint32_t)mutex, 0, 0, 0, 0); | |
700 | #endif | |
701 | return(0); | |
702 | ||
703 | handleffit: | |
704 | /* firstfit failure */ | |
1f2f436a A |
705 | lgenval = *lseqaddr; |
706 | ugenval = *useqaddr; | |
707 | if ((lgenval & PTH_RWL_EBIT) == 0) | |
34e8f829 | 708 | goto retry; |
1f2f436a A |
709 | |
710 | if (fromcond == 0) | |
711 | return(1); | |
712 | else { | |
713 | /* called from condition variable code block again */ | |
34e8f829 A |
714 | ml1: |
715 | #if USE_COMPAGE /* [ */ | |
1f2f436a A |
716 | updateval = __psynch_mutexwait((pthread_mutex_t *)lseqaddr, lgenval | PTH_RWL_RETRYBIT, ugenval, mutex->m_tid, |
717 | mutex->mtxopts.value); | |
34e8f829 | 718 | #else /* USECOMPAGE ][ */ |
1f2f436a A |
719 | updateval = __psynch_mutexwait(omutex, lgenval | PTH_RWL_RETRYBIT, ugenval, mutex->m_tid, |
720 | mutex->mtxopts.value); | |
34e8f829 | 721 | #endif /* USE_COMPAGE ] */ |
1f2f436a A |
722 | if (updateval == (uint32_t)-1) { |
723 | goto ml1; | |
34e8f829 | 724 | } |
1f2f436a A |
725 | |
726 | /* now update the bits */ | |
727 | goto retry; | |
34e8f829 | 728 | } |
1f2f436a | 729 | /* cannot reach */ |
34e8f829 A |
730 | goto retry; |
731 | } | |
732 | ||
1f2f436a | 733 | |
34e8f829 | 734 | int |
1f2f436a A |
735 | __mtx_markprepost(npthread_mutex_t *mutex, uint32_t oupdateval, int firstfit) |
736 | { | |
737 | uint32_t updateval = oupdateval; | |
738 | int clearprepost = 0; | |
739 | uint32_t lgenval, ugenval,flags; | |
740 | volatile uint32_t * lseqaddr, *useqaddr; | |
741 | uint64_t oldval64, newval64; | |
742 | ||
743 | MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr); | |
744 | ||
745 | #if _KSYN_TRACE_ | |
746 | (void)__kdebug_trace(_KSYN_TRACE_UM_MARKPP | DBG_FUNC_START, (uint32_t)mutex, oupdateval, firstfit, 0, 0); | |
747 | #endif | |
748 | ||
749 | retry: | |
750 | ||
751 | ||
752 | ||
753 | if ((firstfit != 0) && ((updateval & PTH_RWL_PBIT) != 0)) { | |
754 | flags = mutex->mtxopts.value; | |
755 | ||
756 | lgenval = *lseqaddr; | |
757 | ugenval = *useqaddr; | |
758 | ||
759 | #if _KSYN_TRACE_ | |
760 | (void)__kdebug_trace(_KSYN_TRACE_UM_MARKPP | DBG_FUNC_NONE, (uint32_t)mutex, 1, lgenval, ugenval, 0); | |
761 | #endif | |
762 | /* update the bits */ | |
763 | oldval64 = (((uint64_t)ugenval) << 32); | |
764 | oldval64 |= lgenval; | |
765 | ||
766 | if ((lgenval & PTHRW_COUNT_MASK) == (ugenval & PTHRW_COUNT_MASK)) { | |
767 | clearprepost = 1; | |
768 | lgenval &= ~PTH_RWL_PBIT; | |
769 | ||
770 | } else { | |
771 | lgenval |= PTH_RWL_PBIT; | |
772 | } | |
773 | newval64 = (((uint64_t)ugenval) << 32); | |
774 | newval64 |= lgenval; | |
775 | ||
776 | if (OSAtomicCompareAndSwap64(oldval64, newval64, (volatile int64_t *)lseqaddr) == TRUE) { | |
777 | #if _KSYN_TRACE_ | |
778 | (void)__kdebug_trace(_KSYN_TRACE_UM_MARKPP | DBG_FUNC_NONE, (uint32_t)mutex, 2, lgenval, ugenval, 0); | |
779 | #endif | |
780 | ||
781 | if (clearprepost != 0) | |
782 | __psynch_cvclrprepost(mutex, lgenval, ugenval, 0, 0, lgenval, (flags | _PTHREAD_MTX_OPT_MUTEX)); | |
783 | ||
784 | } else { | |
785 | goto retry; | |
786 | } | |
787 | ||
788 | #if _KSYN_TRACE_ | |
789 | (void)__kdebug_trace(_KSYN_TRACE_UM_MARKPP | DBG_FUNC_END, (uint32_t)mutex, 0, 0, 0, 0); | |
790 | #endif | |
791 | } | |
792 | return(0); | |
793 | } | |
794 | ||
795 | /* | |
796 | * For the new style mutex, interlocks are not held all the time. | |
797 | * We needed the signature to be set in the end. And we need | |
798 | * to protect against the code getting reorganized by compiler. | |
799 | */ | |
800 | static void | |
801 | __pthread_mutex_set_signature(npthread_mutex_t * mutex) | |
802 | { | |
803 | mutex->sig = _PTHREAD_MUTEX_SIG; | |
804 | } | |
805 | ||
806 | int | |
807 | pthread_mutex_lock(pthread_mutex_t *omutex) | |
34e8f829 A |
808 | { |
809 | pthread_t self; | |
1f2f436a | 810 | uint64_t selfid; |
34e8f829 A |
811 | npthread_mutex_t * mutex = (npthread_mutex_t *)omutex; |
812 | int sig = mutex->sig; | |
1f2f436a A |
813 | #if NEVERINCOMPAGE || !USE_COMPAGE |
814 | //uint32_t oldval, newval; | |
815 | #endif | |
34e8f829 | 816 | int retval; |
1f2f436a A |
817 | int gotlock = 0, firstfit = 0; |
818 | uint32_t updateval, lgenval, ugenval, nval, uval; | |
819 | volatile uint32_t * lseqaddr, *useqaddr; | |
820 | uint64_t oldval64, newval64; | |
34e8f829 | 821 | #if USE_COMPAGE |
34e8f829 A |
822 | int sysret = 0; |
823 | uint32_t mask; | |
824 | #else | |
1f2f436a | 825 | int retrybit = 0; |
34e8f829 A |
826 | #endif |
827 | ||
828 | /* To provide backwards compat for apps using mutex incorrectly */ | |
1f2f436a | 829 | if ((sig != _PTHREAD_MUTEX_SIG) && ((sig & _PTHREAD_MUTEX_SIG_init_MASK) != _PTHREAD_MUTEX_SIG_CMP)) { |
34e8f829 A |
830 | PLOCKSTAT_MUTEX_ERROR(omutex, EINVAL); |
831 | return(EINVAL); | |
832 | } | |
1f2f436a | 833 | if (mutex->sig != _PTHREAD_MUTEX_SIG) { |
34e8f829 | 834 | LOCK(mutex->lock); |
1f2f436a A |
835 | if ((mutex->sig & _PTHREAD_MUTEX_SIG_init_MASK) == _PTHREAD_MUTEX_SIG_CMP) { |
836 | /* static initializer, init the mutex */ | |
837 | if(retval = _pthread_mutex_init(omutex, NULL, (mutex->sig & 0xf)) != 0){ | |
838 | UNLOCK(mutex->lock); | |
839 | PLOCKSTAT_MUTEX_ERROR(omutex, retval); | |
840 | return(retval); | |
841 | } | |
842 | } else if (mutex->sig != _PTHREAD_MUTEX_SIG) { | |
34e8f829 A |
843 | UNLOCK(mutex->lock); |
844 | PLOCKSTAT_MUTEX_ERROR(omutex, EINVAL); | |
845 | return(EINVAL); | |
846 | } | |
847 | UNLOCK(mutex->lock); | |
848 | } | |
849 | ||
850 | #if _KSYN_TRACE_ | |
851 | (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_START, (uint32_t)mutex, 0, 0, 0, 0); | |
852 | #endif | |
1f2f436a | 853 | MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr); |
34e8f829 A |
854 | |
855 | self = pthread_self(); | |
1f2f436a A |
856 | (void) pthread_threadid_np(self, &selfid); |
857 | ||
34e8f829 | 858 | if (mutex->mtxopts.options.type != PTHREAD_MUTEX_NORMAL) { |
1f2f436a | 859 | if (mutex->m_tid == selfid) { |
34e8f829 A |
860 | if (mutex->mtxopts.options.type == PTHREAD_MUTEX_RECURSIVE) |
861 | { | |
862 | if (mutex->mtxopts.options.lock_count < USHRT_MAX) | |
863 | { | |
864 | mutex->mtxopts.options.lock_count++; | |
865 | PLOCKSTAT_MUTEX_ACQUIRE(omutex, 1, 0); | |
866 | retval = 0; | |
867 | } else { | |
868 | retval = EAGAIN; | |
869 | PLOCKSTAT_MUTEX_ERROR(omutex, retval); | |
870 | } | |
871 | } else { /* PTHREAD_MUTEX_ERRORCHECK */ | |
872 | retval = EDEADLK; | |
873 | PLOCKSTAT_MUTEX_ERROR(omutex, retval); | |
874 | } | |
875 | return (retval); | |
876 | } | |
877 | } | |
1f2f436a | 878 | |
34e8f829 A |
879 | #if _KSYN_TRACE_ |
880 | (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_NONE, (uint32_t)mutex, 1, 0, 0, 0); | |
881 | #endif | |
34e8f829 | 882 | |
1f2f436a | 883 | #if USE_COMPAGE /* [ */ |
34e8f829 A |
884 | |
885 | ml0: | |
1f2f436a A |
886 | mask = PTH_RWL_EBIT; |
887 | retval = _commpage_pthread_mutex_lock(lseqaddr, mutex->mtxopts.value, selfid, mask, &mutex->m_tid, &sysret); | |
34e8f829 A |
888 | if (retval == 0) { |
889 | gotlock = 1; | |
890 | } else if (retval == 1) { | |
891 | gotlock = 1; | |
892 | updateval = sysret; | |
893 | /* returns 0 on succesful update */ | |
1f2f436a | 894 | if (__mtx_updatebits( mutex, updateval, firstfit, 0, selfid) == 1) { |
34e8f829 A |
895 | /* could not acquire, may be locked in ffit case */ |
896 | #if USE_COMPAGE | |
897 | LIBC_ABORT("comapge implementatin looping in libc \n"); | |
898 | #endif | |
899 | goto ml0; | |
900 | } | |
901 | } | |
902 | #if NEVERINCOMPAGE | |
903 | else if (retval == 3) { | |
904 | cthread_set_errno_self(sysret); | |
905 | oldval = *lseqaddr; | |
906 | uval = *useqaddr; | |
907 | newval = oldval + PTHRW_INC; | |
908 | gotlock = 0; | |
909 | /* to block in the kerenl again */ | |
910 | } | |
911 | #endif | |
912 | else { | |
1f2f436a | 913 | LIBC_ABORT("comapge implementation bombed \n"); |
34e8f829 A |
914 | } |
915 | ||
916 | ||
917 | #else /* USECOMPAGE ][ */ | |
1f2f436a A |
918 | retry: |
919 | lgenval = *lseqaddr; | |
920 | ugenval = *useqaddr; | |
34e8f829 | 921 | |
1f2f436a A |
922 | #if _KSYN_TRACE_ |
923 | (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_NONE, (uint32_t)mutex, 2, lgenval, ugenval, 0); | |
924 | #endif /* _KSYN_TRACE_ */ | |
34e8f829 | 925 | |
1f2f436a | 926 | if((lgenval & PTH_RWL_EBIT) == 0) { |
34e8f829 | 927 | gotlock = 1; |
34e8f829 A |
928 | } else { |
929 | gotlock = 0; | |
34e8f829 | 930 | } |
1f2f436a A |
931 | |
932 | oldval64 = (((uint64_t)ugenval) << 32); | |
933 | oldval64 |= lgenval; | |
934 | uval = ugenval; | |
935 | nval = (lgenval + PTHRW_INC) | (PTH_RWL_EBIT|PTH_RWL_KBIT); | |
936 | newval64 = (((uint64_t)uval) << 32); | |
937 | newval64 |= nval; | |
938 | ||
939 | if (OSAtomicCompareAndSwap64(oldval64, newval64, (volatile int64_t *)lseqaddr) == TRUE) { | |
34e8f829 | 940 | #if _KSYN_TRACE_ |
1f2f436a | 941 | (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_NONE, (uint32_t)mutex, 2, nval, uval, 0); |
34e8f829 | 942 | #endif |
1f2f436a A |
943 | if (gotlock != 0) { |
944 | mutex->m_tid = selfid; | |
945 | goto out; | |
946 | } | |
34e8f829 | 947 | } else |
1f2f436a | 948 | goto retry; |
34e8f829 A |
949 | |
950 | ||
951 | retrybit = 0; | |
952 | if (gotlock == 0) { | |
953 | #if _KSYN_TRACE_ | |
1f2f436a | 954 | (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_NONE, (uint32_t)mutex, 3, nval, uval, 0); |
34e8f829 A |
955 | #endif |
956 | firstfit = (mutex->mtxopts.options.policy == _PTHREAD_MUTEX_POLICY_FIRSTFIT); | |
957 | ml1: | |
1f2f436a | 958 | updateval = __psynch_mutexwait(omutex, nval | retrybit, uval, mutex->m_tid, |
34e8f829 A |
959 | mutex->mtxopts.value); |
960 | ||
1f2f436a A |
961 | #if _KSYN_TRACE_ |
962 | (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_NONE, (uint32_t)mutex, 4, updateval, 0, 0); | |
963 | #endif | |
34e8f829 | 964 | if (updateval == (uint32_t)-1) { |
34e8f829 A |
965 | goto ml1; |
966 | } | |
967 | ||
1f2f436a A |
968 | /* returns 0 on succesful update; in firstfit it may fail with 1 */ |
969 | if (__mtx_updatebits( mutex, PTHRW_INC | (PTH_RWL_KBIT | PTH_RWL_EBIT), firstfit, 0, selfid) == 1) { | |
34e8f829 | 970 | /* could not acquire, may be locked in ffit case */ |
1f2f436a | 971 | retrybit = PTH_RWL_RETRYBIT; |
34e8f829 A |
972 | #if USE_COMPAGE |
973 | LIBC_ABORT("comapge implementatin looping in libc \n"); | |
974 | ||
975 | #endif | |
976 | goto ml1; | |
977 | } | |
978 | } | |
979 | #endif /* USE_COMPAGE ] */ | |
980 | ||
1f2f436a | 981 | out: |
34e8f829 | 982 | if (mutex->mtxopts.options.type == PTHREAD_MUTEX_RECURSIVE) |
1f2f436a | 983 | mutex->mtxopts.options.lock_count = 1; |
34e8f829 A |
984 | |
985 | #if _KSYN_TRACE_ | |
986 | (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_END, (uint32_t)mutex, 0, 0, 0, 0); | |
987 | #endif | |
988 | return (0); | |
989 | } | |
990 | ||
991 | /* | |
992 | * Attempt to lock a mutex, but don't block if this isn't possible. | |
993 | */ | |
994 | int | |
1f2f436a | 995 | pthread_mutex_trylock(pthread_mutex_t *omutex) |
34e8f829 A |
996 | { |
997 | npthread_mutex_t * mutex = (npthread_mutex_t *)omutex; | |
998 | int sig = mutex->sig; | |
34e8f829 A |
999 | int error = 0; |
1000 | pthread_t self; | |
1f2f436a A |
1001 | uint64_t selfid; |
1002 | int gotlock = 0; | |
1003 | uint32_t lgenval, ugenval, nval, uval; | |
1004 | volatile uint32_t * lseqaddr, *useqaddr; | |
1005 | uint64_t oldval64, newval64; | |
34e8f829 A |
1006 | |
1007 | /* To provide backwards compat for apps using mutex incorrectly */ | |
1f2f436a | 1008 | if ((sig != _PTHREAD_MUTEX_SIG) && ((sig & _PTHREAD_MUTEX_SIG_init_MASK) != _PTHREAD_MUTEX_SIG_CMP)) { |
34e8f829 A |
1009 | PLOCKSTAT_MUTEX_ERROR(omutex, EINVAL); |
1010 | return(EINVAL); | |
1011 | } | |
1012 | ||
1f2f436a | 1013 | if ((mutex->sig & _PTHREAD_MUTEX_SIG_init_MASK) == _PTHREAD_MUTEX_SIG_CMP) { |
34e8f829 | 1014 | LOCK(mutex->lock); |
1f2f436a | 1015 | if (mutex->sig == _PTHREAD_MUTEX_SIG_init) { |
34e8f829 | 1016 | /* static initializer, init the mutex */ |
1f2f436a A |
1017 | if((error = _pthread_mutex_init(omutex, NULL, (mutex->sig & 0xf))) != 0){ |
1018 | UNLOCK(mutex->lock); | |
1019 | PLOCKSTAT_MUTEX_ERROR(omutex, error); | |
1020 | return(error); | |
1021 | } | |
1022 | } else if (mutex->sig != _PTHREAD_MUTEX_SIG) { | |
34e8f829 A |
1023 | UNLOCK(mutex->lock); |
1024 | PLOCKSTAT_MUTEX_ERROR(omutex, EINVAL); | |
1025 | return(EINVAL); | |
1026 | } | |
1027 | UNLOCK(mutex->lock); | |
1028 | } | |
1029 | ||
1f2f436a | 1030 | MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr); |
34e8f829 A |
1031 | |
1032 | self = pthread_self(); | |
1f2f436a A |
1033 | (void) pthread_threadid_np(self, &selfid); |
1034 | ||
34e8f829 | 1035 | if (mutex->mtxopts.options.type != PTHREAD_MUTEX_NORMAL) { |
1f2f436a | 1036 | if (mutex->m_tid == selfid) { |
34e8f829 A |
1037 | if (mutex->mtxopts.options.type == PTHREAD_MUTEX_RECURSIVE) |
1038 | { | |
1039 | if (mutex->mtxopts.options.lock_count < USHRT_MAX) | |
1040 | { | |
1041 | mutex->mtxopts.options.lock_count++; | |
1042 | PLOCKSTAT_MUTEX_ACQUIRE(omutex, 1, 0); | |
1043 | error = 0; | |
1044 | } else { | |
1045 | error = EAGAIN; | |
1046 | PLOCKSTAT_MUTEX_ERROR(omutex, error); | |
1047 | } | |
1048 | } else { /* PTHREAD_MUTEX_ERRORCHECK */ | |
1049 | error = EDEADLK; | |
1050 | PLOCKSTAT_MUTEX_ERROR(omutex, error); | |
1051 | } | |
1052 | return (error); | |
1053 | } | |
1054 | } | |
1f2f436a A |
1055 | retry: |
1056 | lgenval = *lseqaddr; | |
1057 | ugenval = *useqaddr; | |
1058 | ||
1059 | #if _KSYN_TRACE_ | |
1060 | (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_NONE, (uint32_t)mutex, 2, lgenval, ugenval, 0); | |
1061 | #endif /* _KSYN_TRACE_ */ | |
1062 | ||
34e8f829 | 1063 | |
1f2f436a A |
1064 | oldval64 = (((uint64_t)ugenval) << 32); |
1065 | oldval64 |= lgenval; | |
1066 | uval = ugenval; | |
1067 | ||
1068 | /* if we can acquire go ahead otherwise ensure it is still busy */ | |
1069 | if((lgenval & PTH_RWL_EBIT) == 0) { | |
1070 | gotlock = 1; | |
1071 | nval = (lgenval + PTHRW_INC) | (PTH_RWL_EBIT|PTH_RWL_KBIT); | |
34e8f829 | 1072 | } else { |
1f2f436a A |
1073 | nval = (lgenval | PTH_RWL_TRYLKBIT); |
1074 | gotlock = 0; | |
34e8f829 | 1075 | } |
1f2f436a A |
1076 | |
1077 | newval64 = (((uint64_t)uval) << 32); | |
1078 | newval64 |= nval; | |
1079 | ||
1080 | /* set s and b bit */ | |
1081 | if (OSAtomicCompareAndSwap64(oldval64, newval64, (volatile int64_t *)lseqaddr) == TRUE) { | |
1082 | #if _KSYN_TRACE_ | |
1083 | (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_NONE, (uint32_t)mutex, 2, nval, uval, 0); | |
1084 | #endif | |
1085 | if (gotlock != 0) { | |
1086 | mutex->m_tid = selfid; | |
1087 | if (mutex->mtxopts.options.type == PTHREAD_MUTEX_RECURSIVE) | |
1088 | mutex->mtxopts.options.lock_count = 1; | |
1089 | PLOCKSTAT_MUTEX_ACQUIRE(omutex, 1, 0); | |
1090 | } else { | |
1091 | error = EBUSY; | |
1092 | PLOCKSTAT_MUTEX_ERROR(omutex, error); | |
1093 | } | |
1094 | } else | |
1095 | goto retry; | |
34e8f829 | 1096 | |
1f2f436a A |
1097 | |
1098 | #if _KSYN_TRACE_ | |
1099 | (void)__kdebug_trace(_KSYN_TRACE_UM_LOCK | DBG_FUNC_END, (uint32_t)mutex, 0xfafafafa, 0, error, 0); | |
1100 | #endif | |
1101 | return (error); | |
34e8f829 A |
1102 | } |
1103 | ||
1104 | /* | |
1105 | * Unlock a mutex. | |
1106 | * TODO: Priority inheritance stuff | |
1107 | */ | |
1108 | int | |
1f2f436a | 1109 | pthread_mutex_unlock(pthread_mutex_t *omutex) |
34e8f829 A |
1110 | { |
1111 | npthread_mutex_t * mutex = (npthread_mutex_t *)omutex; | |
1112 | int retval; | |
1f2f436a | 1113 | uint32_t mtxgen, mtxugen, flags, notify, updateval; |
34e8f829 | 1114 | int sig = mutex->sig; |
1f2f436a A |
1115 | pthread_t self; |
1116 | uint64_t selfid; | |
1117 | volatile uint32_t * lseqaddr, *useqaddr; | |
1118 | int firstfit = 0; | |
34e8f829 A |
1119 | |
1120 | /* To provide backwards compat for apps using mutex incorrectly */ | |
1121 | ||
1122 | #if _KSYN_TRACE_ | |
1123 | (void)__kdebug_trace(_KSYN_TRACE_UM_UNLOCK | DBG_FUNC_START, (uint32_t)mutex, 0, 0, 0, 0); | |
1124 | #endif | |
1f2f436a | 1125 | if ((sig != _PTHREAD_MUTEX_SIG) && ((sig & _PTHREAD_MUTEX_SIG_init_MASK) != _PTHREAD_MUTEX_SIG_CMP)) { |
34e8f829 A |
1126 | PLOCKSTAT_MUTEX_ERROR(omutex, EINVAL); |
1127 | return(EINVAL); | |
1128 | } | |
1f2f436a A |
1129 | |
1130 | if (mutex->sig != _PTHREAD_MUTEX_SIG) { | |
34e8f829 | 1131 | LOCK(mutex->lock); |
1f2f436a | 1132 | if ((mutex->sig & _PTHREAD_MUTEX_SIG_init_MASK) == _PTHREAD_MUTEX_SIG_CMP) { |
34e8f829 | 1133 | /* static initializer, init the mutex */ |
1f2f436a A |
1134 | if((retval = _pthread_mutex_init(omutex, NULL, (mutex->sig & 0xf))) != 0){ |
1135 | UNLOCK(mutex->lock); | |
1136 | PLOCKSTAT_MUTEX_ERROR(omutex, retval); | |
1137 | return(retval); | |
1138 | } | |
1139 | } else if (mutex->sig != _PTHREAD_MUTEX_SIG) { | |
34e8f829 A |
1140 | UNLOCK(mutex->lock); |
1141 | PLOCKSTAT_MUTEX_ERROR(omutex, EINVAL); | |
1142 | return(EINVAL); | |
1143 | } | |
1144 | UNLOCK(mutex->lock); | |
1145 | } | |
1f2f436a A |
1146 | |
1147 | MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr); | |
1148 | ||
34e8f829 | 1149 | notify = 0; |
1f2f436a | 1150 | retval = __mtx_droplock(mutex, PTHRW_INC, &flags, NULL, &mtxgen, &mtxugen); |
34e8f829 A |
1151 | if (retval != 0) |
1152 | return(retval); | |
1153 | ||
1f2f436a A |
1154 | if ((flags & _PTHREAD_MTX_OPT_NOTIFY) != 0) { |
1155 | firstfit = (mutex->mtxopts.options.policy == _PTHREAD_MUTEX_POLICY_FIRSTFIT); | |
1156 | ||
1157 | self = pthread_self(); | |
1158 | (void) pthread_threadid_np(self, &selfid); | |
1159 | ||
34e8f829 | 1160 | #if _KSYN_TRACE_ |
1f2f436a | 1161 | (void)__kdebug_trace(_KSYN_TRACE_UM_UNLOCK | DBG_FUNC_NONE, (uint32_t)mutex, 1, mtxgen, mtxugen, 0); |
34e8f829 A |
1162 | #endif |
1163 | #if USE_COMPAGE /* [ */ | |
1f2f436a | 1164 | if ((updateval = __psynch_mutexdrop((pthread_mutex_t *)lseqaddr, mtxgen, mtxugen, mutex->m_tid, flags)) == (uint32_t)-1) |
34e8f829 | 1165 | #else /* USECOMPAGE ][ */ |
1f2f436a | 1166 | if ((updateval = __psynch_mutexdrop(omutex, mtxgen, mtxugen, mutex->m_tid, flags))== (uint32_t)-1) |
34e8f829 A |
1167 | #endif /* USE_COMPAGE ] */ |
1168 | { | |
1f2f436a A |
1169 | retval = errno; |
1170 | #if _KSYN_TRACE_ | |
1171 | (void)__kdebug_trace(_KSYN_TRACE_UM_UNLOCK | DBG_FUNC_END, (uint32_t)mutex, retval, 0, 0, 0); | |
1172 | #endif | |
1173 | if (retval == 0) | |
34e8f829 | 1174 | return(0); |
1f2f436a A |
1175 | else if (errno == EINTR) |
1176 | return(0); | |
1177 | else { | |
1178 | LIBC_ABORT("__p_mutexdrop failed with error %d\n", retval); | |
1179 | return(retval); | |
1180 | } | |
1181 | } else if (firstfit == 1) { | |
1182 | if ((updateval & PTH_RWL_PBIT) != 0) { | |
1183 | __mtx_markprepost(mutex, updateval, firstfit); | |
1184 | } | |
34e8f829 A |
1185 | } |
1186 | } | |
1187 | #if _KSYN_TRACE_ | |
1188 | (void)__kdebug_trace(_KSYN_TRACE_UM_UNLOCK | DBG_FUNC_END, (uint32_t)mutex, 0, 0, 0, 0); | |
1189 | #endif | |
1190 | return(0); | |
1191 | } | |
1192 | ||
1193 | ||
1194 | /* | |
1195 | * Initialize a mutex variable, possibly with additional attributes. | |
1196 | */ | |
1197 | int | |
1f2f436a | 1198 | _pthread_mutex_init(pthread_mutex_t *omutex, const pthread_mutexattr_t *attr, uint32_t static_type) |
34e8f829 A |
1199 | { |
1200 | npthread_mutex_t * mutex = (npthread_mutex_t *)omutex; | |
1201 | ||
1202 | if (attr) | |
1203 | { | |
1204 | if (attr->sig != _PTHREAD_MUTEX_ATTR_SIG) | |
1205 | return (EINVAL); | |
1206 | mutex->prioceiling = attr->prioceiling; | |
1207 | mutex->mtxopts.options.protocol = attr->protocol; | |
1208 | mutex->mtxopts.options.policy = attr->policy; | |
1209 | mutex->mtxopts.options.type = attr->type; | |
1210 | mutex->mtxopts.options.pshared = attr->pshared; | |
1211 | } else { | |
1f2f436a A |
1212 | switch(static_type) { |
1213 | case 1: | |
1214 | mutex->mtxopts.options.type = PTHREAD_MUTEX_ERRORCHECK; | |
1215 | break; | |
1216 | case 2: | |
1217 | mutex->mtxopts.options.type = PTHREAD_MUTEX_RECURSIVE; | |
1218 | break; | |
1219 | case 3: | |
1220 | /* firstfit fall thru */ | |
1221 | case 7: | |
1222 | mutex->mtxopts.options.type = PTHREAD_MUTEX_DEFAULT; | |
1223 | break; | |
1224 | default: | |
1225 | return(EINVAL); | |
1226 | } | |
1227 | ||
34e8f829 A |
1228 | mutex->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING; |
1229 | mutex->mtxopts.options.protocol = _PTHREAD_DEFAULT_PROTOCOL; | |
1f2f436a A |
1230 | if (static_type != 3) |
1231 | mutex->mtxopts.options.policy = _PTHREAD_MUTEX_POLICY_FAIRSHARE; | |
1232 | else | |
1233 | mutex->mtxopts.options.policy = _PTHREAD_MUTEX_POLICY_FIRSTFIT; | |
34e8f829 A |
1234 | mutex->mtxopts.options.pshared = _PTHREAD_DEFAULT_PSHARED; |
1235 | } | |
1236 | ||
1f2f436a A |
1237 | mutex->mtxopts.options.notify = 0; |
1238 | mutex->mtxopts.options.rfu = 0; | |
1239 | mutex->mtxopts.options.hold = 0; | |
1240 | mutex->mtxopts.options.mutex = 1; | |
34e8f829 A |
1241 | mutex->mtxopts.options.lock_count = 0; |
1242 | /* address 8byte aligned? */ | |
1243 | if (((uintptr_t)mutex & 0x07) != 0) { | |
1244 | /* 4byte alinged */ | |
1245 | mutex->mtxopts.options.misalign = 1; | |
1246 | #if defined(__LP64__) | |
1247 | mutex->m_lseqaddr = &mutex->m_seq[0]; | |
1248 | mutex->m_useqaddr = &mutex->m_seq[1]; | |
1249 | #else /* __LP64__ */ | |
1250 | mutex->m_lseqaddr = &mutex->m_seq[1]; | |
1251 | mutex->m_useqaddr = &mutex->m_seq[2]; | |
1252 | #endif /* __LP64__ */ | |
1253 | } else { | |
1254 | /* 8byte alinged */ | |
1255 | mutex->mtxopts.options.misalign = 0; | |
1256 | #if defined(__LP64__) | |
1257 | mutex->m_lseqaddr = &mutex->m_seq[1]; | |
1258 | mutex->m_useqaddr = &mutex->m_seq[2]; | |
1259 | #else /* __LP64__ */ | |
1260 | mutex->m_lseqaddr = &mutex->m_seq[0]; | |
1261 | mutex->m_useqaddr = &mutex->m_seq[1]; | |
1262 | #endif /* __LP64__ */ | |
1263 | } | |
1264 | mutex->m_tid = 0; | |
1265 | mutex->m_seq[0] = 0; | |
1266 | mutex->m_seq[1] = 0; | |
1267 | mutex->m_seq[2] = 0; | |
1268 | mutex->prioceiling = 0; | |
1269 | mutex->priority = 0; | |
1f2f436a A |
1270 | /* |
1271 | * For the new style mutex, interlocks are not held all the time. | |
1272 | * We needed the signature to be set in the end. And we need | |
1273 | * to protect against the code getting reorganized by compiler. | |
1274 | * mutex->sig = _PTHREAD_MUTEX_SIG; | |
1275 | */ | |
1276 | __pthread_mutex_set_signature(mutex); | |
34e8f829 A |
1277 | return (0); |
1278 | } | |
1279 | ||
1280 | ||
34e8f829 A |
1281 | /* |
1282 | * Destroy a mutex variable. | |
1283 | */ | |
1284 | int | |
1f2f436a | 1285 | pthread_mutex_destroy(pthread_mutex_t *omutex) |
34e8f829 A |
1286 | { |
1287 | int res; | |
1288 | npthread_mutex_t * mutex = (npthread_mutex_t *)omutex; | |
1289 | ||
1290 | LOCK(mutex->lock); | |
1f2f436a | 1291 | res = _pthread_mutex_destroy_locked(omutex); |
34e8f829 A |
1292 | UNLOCK(mutex->lock); |
1293 | ||
1294 | return(res); | |
1295 | } | |
1296 | ||
1297 | ||
1f2f436a A |
1298 | static int |
1299 | _pthread_mutex_destroy_locked(pthread_mutex_t *omutex) | |
34e8f829 A |
1300 | { |
1301 | int res; | |
1302 | npthread_mutex_t * mutex = (npthread_mutex_t *)omutex; | |
1f2f436a A |
1303 | uint32_t lgenval, ugenval; |
1304 | volatile uint32_t * lseqaddr, *useqaddr; | |
34e8f829 A |
1305 | |
1306 | ||
1307 | if (mutex->sig == _PTHREAD_MUTEX_SIG) | |
1308 | { | |
1f2f436a | 1309 | MUTEX_GETSEQ_ADDR(mutex, lseqaddr, useqaddr); |
34e8f829 A |
1310 | |
1311 | lgenval = *(lseqaddr); | |
1f2f436a | 1312 | ugenval = *(useqaddr); |
34e8f829 | 1313 | if ((mutex->m_tid == (uint64_t)0) && |
1f2f436a | 1314 | ((lgenval & PTHRW_COUNT_MASK) == (ugenval & PTHRW_COUNT_MASK))) |
34e8f829 A |
1315 | { |
1316 | mutex->sig = _PTHREAD_NO_SIG; | |
1317 | res = 0; | |
1318 | } | |
1319 | else | |
1320 | res = EBUSY; | |
1f2f436a A |
1321 | } else if((mutex->sig & _PTHREAD_MUTEX_SIG_init_MASK )== _PTHREAD_MUTEX_SIG_CMP) { |
1322 | mutex->sig = _PTHREAD_NO_SIG; | |
1323 | res = 0; | |
1324 | } else | |
34e8f829 A |
1325 | res = EINVAL; |
1326 | ||
1327 | return (res); | |
1328 | } | |
1329 | ||
224c7076 A |
1330 | |
1331 | #endif /* !BUILDING_VARIANT ] */ | |
1332 | ||
1333 | /* | |
1334 | * Destroy a mutex attribute structure. | |
1335 | */ | |
1336 | int | |
1337 | pthread_mutexattr_destroy(pthread_mutexattr_t *attr) | |
1338 | { | |
1339 | #if __DARWIN_UNIX03 | |
1340 | if (__unix_conforming == 0) | |
1341 | __unix_conforming = 1; | |
1342 | if (attr->sig != _PTHREAD_MUTEX_ATTR_SIG) | |
1343 | return (EINVAL); | |
1344 | #endif /* __DARWIN_UNIX03 */ | |
1345 | ||
1346 | attr->sig = _PTHREAD_NO_SIG; /* Uninitialized */ | |
1347 | return (0); | |
1348 | } | |
1349 | ||
1350 |