1
/* ``The contents of this file are subject to the Erlang Public License,
4
* Copyright Ericsson AB 2007-2009. All Rights Reserved.
6
* The contents of this file are subject to the Erlang Public License,
2
7
* Version 1.1, (the "License"); you may not use this file except in
3
8
* compliance with the License. You should have received a copy of the
4
9
* Erlang Public License along with this software. If not, it can be
5
* retrieved via the world wide web at http://www.erlang.org/.
10
* retrieved online at http://www.erlang.org/.
7
12
* Software distributed under the License is distributed on an "AS IS"
8
13
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
14
* the License for the specific language governing rights and limitations
10
15
* under the License.
12
* The Initial Developer of the Original Code is Ericsson AB.
13
* Portions created by Ericsson are Copyright 2007, Ericsson AB.
14
* All Rights Reserved.''
185
195
#endif /* #ifndef ERTS_PROC_LOCK_TYPE__ */
187
197
#ifndef ERTS_PROCESS_LOCK_ONLY_PROC_LOCK_TYPE__
188
#ifndef ERTS_PROCESS_LOCK_H__
189
#define ERTS_PROCESS_LOCK_H__
198
#ifndef ERTS_PROC_LOCK_LOCK_CHECK__
199
#define ERTS_PROC_LOCK_LOCK_CHECK__
201
/* Lock counter implemetation */
203
#ifdef ERTS_ENABLE_LOCK_COUNT
204
#define erts_smp_proc_lock__(P,I,L) erts_smp_proc_lock_x__(P,I,L,__FILE__,__LINE__)
205
#define erts_smp_proc_lock(P,L) erts_smp_proc_lock_x(P,L,__FILE__,__LINE__)
208
#if defined(ERTS_SMP) && defined (ERTS_ENABLE_LOCK_COUNT)
210
void erts_lcnt_proc_lock_init(Process *p);
211
void erts_lcnt_proc_lock_destroy(Process *p);
212
void erts_lcnt_proc_lock(erts_proc_lock_t *lock, ErtsProcLocks locks);
213
void erts_lcnt_proc_lock_post_x(erts_proc_lock_t *lock, ErtsProcLocks locks, char *file, unsigned int line);
214
void erts_lcnt_proc_lock_unaquire(erts_proc_lock_t *lock, ErtsProcLocks locks);
215
void erts_lcnt_proc_unlock(erts_proc_lock_t *lock, ErtsProcLocks locks);
216
void erts_lcnt_proc_trylock(erts_proc_lock_t *lock, ErtsProcLocks locks, int res);
218
#endif /* ERTS_ENABLE_LOCK_COUNT*/
191
222
/* --- Process lock checking ----------------------------------------------- */
311
ERTS_GLB_INLINE ErtsProcLocks
312
erts_proc_lock_flags_cmpxchg(erts_proc_lock_t *lck, ErtsProcLocks new,
313
ErtsProcLocks expected)
315
ErtsProcLocks res = lck->flags;
271
323
#define ERTS_PROC_LOCK_FLGS_BAND_(L, MSK) erts_proc_lock_flags_band((L), (MSK))
272
324
#define ERTS_PROC_LOCK_FLGS_BOR_(L, MSK) erts_proc_lock_flags_bor((L), (MSK))
325
#define ERTS_PROC_LOCK_FLGS_CMPXCHG_(L, NEW, EXPECTED) \
326
erts_proc_lock_flags_cmpxchg((L), (NEW), (EXPECTED))
273
327
#define ERTS_PROC_LOCK_FLGS_READ_(L) ((L)->flags)
275
329
#endif /* end no opt atomic ops */
285
339
void erts_proc_unlock_failed(Process *,
286
340
erts_pix_lock_t *,
288
void erts_proc_trylock_failed(Process *,
289
erts_pix_lock_t *pix_lck,
293
343
ERTS_GLB_INLINE void erts_pix_lock(erts_pix_lock_t *);
294
344
ERTS_GLB_INLINE void erts_pix_unlock(erts_pix_lock_t *);
295
345
ERTS_GLB_INLINE int erts_lc_pix_lock_is_locked(erts_pix_lock_t *);
297
ERTS_GLB_INLINE void erts_inc_proc_lock_refc(Process *);
298
ERTS_GLB_INLINE void erts_dec_proc_lock_refc(Process *);
347
ERTS_GLB_INLINE ErtsProcLocks erts_smp_proc_raw_trylock__(Process *p,
348
ErtsProcLocks locks);
349
#ifdef ERTS_ENABLE_LOCK_COUNT
350
ERTS_GLB_INLINE void erts_smp_proc_lock_x__(Process *,
353
char *file, unsigned int line);
300
355
ERTS_GLB_INLINE void erts_smp_proc_lock__(Process *,
301
356
erts_pix_lock_t *,
303
359
ERTS_GLB_INLINE void erts_smp_proc_unlock__(Process *,
304
360
erts_pix_lock_t *,
345
ERTS_GLB_INLINE void erts_inc_proc_lock_refc(Process *p)
347
erts_pix_lock_t *pixlck = ERTS_PID2PIXLOCK(p->id);
348
erts_pix_lock(pixlck);
349
ERTS_LC_ASSERT(p->lock.refc > 0);
351
erts_pix_unlock(pixlck);
354
ERTS_GLB_INLINE void erts_dec_proc_lock_refc(Process *p)
357
erts_pix_lock_t *pixlck = ERTS_PID2PIXLOCK(p->id);
358
erts_pix_lock(pixlck);
359
ERTS_LC_ASSERT(p->lock.refc > 0);
360
fp = --p->lock.refc == 0 ? p : NULL;
361
erts_pix_unlock(pixlck);
402
* Helper function for erts_smp_proc_lock__ and erts_smp_proc_trylock__.
404
* Attempts to grab all of 'locks' simultaneously.
406
* On success, returns zero.
408
* On failure, returns the p->locks at the moment it tried to grab them,
409
* at least some of which will intersect with 'locks', so it is nonzero.
411
* This assumes p's pix lock is held on entry if !ERTS_PROC_LOCK_ATOMIC_IMPL.
412
* Does not release the pix lock.
414
ERTS_GLB_INLINE ErtsProcLocks
415
erts_smp_proc_raw_trylock__(Process *p, ErtsProcLocks locks)
417
ErtsProcLocks expct_lflgs = 0;
420
ErtsProcLocks lflgs = ERTS_PROC_LOCK_FLGS_CMPXCHG_(&p->lock,
423
if (ERTS_LIKELY(lflgs == expct_lflgs)) {
424
/* We successfully grabbed all locks. */
429
/* Some locks we need are locked, give up. */
433
/* cmpxchg failed, try again (should be rare). */
366
439
ERTS_GLB_INLINE void
440
#ifdef ERTS_ENABLE_LOCK_COUNT
441
erts_smp_proc_lock_x__(Process *p,
442
erts_pix_lock_t *pix_lck,
444
char *file, unsigned int line)
367
446
erts_smp_proc_lock__(Process *p,
368
447
erts_pix_lock_t *pix_lck,
369
448
ErtsProcLocks locks)
371
ErtsProcLocks waiters, old_lflgs;
451
ErtsProcLocks old_lflgs;
372
452
#if !ERTS_PROC_LOCK_ATOMIC_IMPL
373
453
erts_pix_lock(pix_lck);
455
#ifdef ERTS_ENABLE_LOCK_COUNT
456
erts_lcnt_proc_lock(&(p->lock), locks);
376
459
ERTS_LC_ASSERT((locks & ~ERTS_PROC_LOCKS_ALL) == 0);
377
waiters = locks << ERTS_PROC_LOCK_WAITER_SHIFT;
378
old_lflgs = ERTS_PROC_LOCK_FLGS_BOR_(&p->lock, locks);
380
if (old_lflgs & (waiters | locks)) {
381
/* erts_proc_lock_failed() always returns with pix_lck unlocked. */
461
old_lflgs = erts_smp_proc_raw_trylock__(p, locks);
463
if (old_lflgs != 0) {
465
* There is lock contention, so let erts_proc_lock_failed() deal
466
* with it. Note that erts_proc_lock_failed() returns with
382
469
erts_proc_lock_failed(p, pix_lck, locks, old_lflgs);
384
472
#if !ERTS_PROC_LOCK_ATOMIC_IMPL
386
474
ERTS_LC_ASSERT(locks == (ERTS_PROC_LOCK_FLGS_READ_(&p->lock) & locks));
387
475
erts_pix_unlock(pix_lck);
478
#ifdef ERTS_ENABLE_LOCK_COUNT
479
erts_lcnt_proc_lock_post_x(&(p->lock), locks, file, line);
391
481
#ifdef ERTS_ENABLE_LOCK_CHECK
392
482
erts_proc_lc_lock(p, locks);
422
516
erts_pix_lock(pix_lck);
519
old_lflgs = ERTS_PROC_LOCK_FLGS_READ_(&p->lock);
425
521
ERTS_LC_ASSERT((locks & ~ERTS_PROC_LOCKS_ALL) == 0);
426
ERTS_LC_ASSERT(locks == (ERTS_PROC_LOCK_FLGS_READ_(&p->lock) & locks));
428
old_lflgs = ERTS_PROC_LOCK_FLGS_BAND_(&p->lock, ~locks);
429
waiters = (old_lflgs >> ERTS_PROC_LOCK_WAITER_SHIFT) & locks;
431
/* erts_proc_unlock_failed() always returns with pix_lck unlocked. */
432
erts_proc_unlock_failed(p, pix_lck, waiters);
522
ERTS_LC_ASSERT(locks == (old_lflgs & locks));
526
* We'll atomically unlock every lock that has no waiter.
527
* If any locks with waiters remain we'll let
528
* erts_proc_unlock_failed() deal with them.
530
ErtsProcLocks wait_locks =
531
(old_lflgs >> ERTS_PROC_LOCK_WAITER_SHIFT) & locks;
533
/* What p->lock will look like with all non-waited locks released. */
534
ErtsProcLocks want_lflgs = old_lflgs & (wait_locks | ~locks);
536
if (want_lflgs != old_lflgs) {
537
ErtsProcLocks new_lflgs =
538
ERTS_PROC_LOCK_FLGS_CMPXCHG_(&p->lock, want_lflgs, old_lflgs);
540
if (new_lflgs != old_lflgs) {
541
/* cmpxchg failed, try again. */
542
old_lflgs = new_lflgs;
547
/* We have successfully unlocked every lock with no waiter. */
549
if (want_lflgs & locks) {
550
/* Locks with waiters remain. */
551
/* erts_proc_unlock_failed() returns with pix_lck unlocked. */
552
erts_proc_unlock_failed(p, pix_lck, want_lflgs & locks);
434
555
#if !ERTS_PROC_LOCK_ATOMIC_IMPL
436
erts_pix_unlock(pix_lck);
556
erts_pix_unlock(pix_lck);
441
564
ERTS_GLB_INLINE int
524
646
#endif /* ERTS_SMP */
648
#ifdef ERTS_ENABLE_LOCK_COUNT
649
ERTS_GLB_INLINE void erts_smp_proc_lock_x(Process *, ErtsProcLocks, char *file, unsigned int line);
526
651
ERTS_GLB_INLINE void erts_smp_proc_lock(Process *, ErtsProcLocks);
527
653
ERTS_GLB_INLINE void erts_smp_proc_unlock(Process *, ErtsProcLocks);
528
654
ERTS_GLB_INLINE int erts_smp_proc_trylock(Process *, ErtsProcLocks);
656
ERTS_GLB_INLINE void erts_smp_proc_inc_refc(Process *);
657
ERTS_GLB_INLINE void erts_smp_proc_dec_refc(Process *);
531
660
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
533
662
ERTS_GLB_INLINE void
663
#ifdef ERTS_ENABLE_LOCK_COUNT
664
erts_smp_proc_lock_x(Process *p, ErtsProcLocks locks, char *file, unsigned int line)
534
666
erts_smp_proc_lock(Process *p, ErtsProcLocks locks)
669
#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_COUNT)
670
erts_smp_proc_lock_x__(p,
671
#if ERTS_PROC_LOCK_ATOMIC_IMPL
674
ERTS_PID2PIXLOCK(p->id),
675
#endif /*ERTS_PROC_LOCK_ATOMIC_IMPL*/
677
#elif defined(ERTS_SMP)
537
678
erts_smp_proc_lock__(p,
538
679
#if ERTS_PROC_LOCK_ATOMIC_IMPL
541
682
ERTS_PID2PIXLOCK(p->id),
683
#endif /*ERTS_PROC_LOCK_ATOMIC_IMPL*/
547
688
ERTS_GLB_INLINE void
618
erts_pid2proc_trylock_failed(Process *p,
619
erts_pix_lock_t *pixlck,
621
ErtsProcLocks wlocks,
622
ErtsProcLocks old_lflgs);
624
785
erts_pid2proc_safelock(Process *c_p,
625
786
ErtsProcLocks c_p_have_locks,
627
ErtsProcLocks have_locks,
628
788
ErtsProcLocks need_locks,
629
ErtsProcLocks wait_locks,
630
789
erts_pix_lock_t *pix_lock,
632
791
ERTS_GLB_INLINE Process *erts_pid2proc_unlocked_opt(Eterm pid, int flags);
726
892
&& ERTS_PROC_IS_EXITING(proc))) {
895
else if (!need_locks) {
896
if (flags & ERTS_P2P_FLG_SMP_INC_REFC)
730
ErtsProcLocks have_locks, wait_locks;
902
#ifdef ERTS_ENABLE_LOCK_COUNT
903
lcnt_locks = need_locks;
904
if (!(flags & ERTS_P2P_FLG_TRY_LOCK)) {
905
erts_lcnt_proc_lock(&proc->lock, need_locks);
732
909
#ifdef ERTS_ENABLE_LOCK_CHECK
733
if (erts_proc_lc_trylock_force_busy(proc, need_locks)) {
734
/* Make sure erts_proc_safelock() is enough to handle
735
a potential lock order violation situation... */
738
if (flags & ERTS_P2P_FLG_TRY_LOCK) {
739
erts_pix_unlock(pix_lock);
740
proc = ERTS_PROC_LOCK_BUSY;
910
/* Make sure erts_pid2proc_safelock() is enough to handle
911
a potential lock order violation situation... */
912
busy = erts_proc_lc_trylock_force_busy(proc, need_locks);
747
/* Try to aquire as many locks as possible... */
748
ErtsProcLocks old_lflgs;
916
/* Try a quick trylock to grab all the locks we need. */
917
busy = (int) erts_smp_proc_raw_trylock__(proc, need_locks);
918
#ifdef ERTS_ENABLE_LOCK_CHECK
919
erts_proc_lc_trylock(proc, need_locks, !busy);
921
#ifdef ERTS_PROC_LOCK_DEBUG
923
erts_proc_lock_op_debug(proc, need_locks, 1);
750
have_locks = need_locks;
751
old_lflgs = ERTS_PROC_LOCK_FLGS_BOR_(&proc->lock, need_locks);
752
have_locks &= ~old_lflgs;
753
wait_locks = old_lflgs >> ERTS_PROC_LOCK_WAITER_SHIFT;
754
wait_locks &= have_locks;
755
have_locks &= ~wait_locks;
756
#ifdef ERTS_ENABLE_LOCK_CHECK
757
if (flags & ERTS_P2P_FLG_TRY_LOCK) {
758
erts_proc_lc_trylock(proc,
760
need_locks == have_locks);
927
#ifdef ERTS_ENABLE_LOCK_COUNT
928
if (flags & ERTS_P2P_FLG_TRY_LOCK) {
930
erts_lcnt_proc_trylock(&proc->lock, need_locks, EBUSY);
932
erts_lcnt_proc_trylock(&proc->lock, need_locks, 0);
937
if (flags & ERTS_P2P_FLG_SMP_INC_REFC)
939
#ifdef ERTS_ENABLE_LOCK_COUNT
941
if (!(flags & ERTS_P2P_FLG_TRY_LOCK)) {
942
erts_lcnt_proc_lock_post_x(&proc->lock, lcnt_locks, __FILE__, __LINE__);
947
if (flags & ERTS_P2P_FLG_TRY_LOCK)
948
proc = ERTS_PROC_LOCK_BUSY;
763
if (need_locks != have_locks)
764
erts_proc_lc_trylock(proc, need_locks & ~have_locks, 0);
766
erts_proc_lc_trylock(proc, have_locks, 1);
769
#ifdef ERTS_PROC_LOCK_DEBUG
770
if (!(flags & ERTS_P2P_FLG_TRY_LOCK)
771
|| need_locks == have_locks)
772
erts_proc_lock_op_debug(proc, have_locks, 1);
774
ERTS_SMP_LC_ASSERT(!wait_locks || (need_locks & ~have_locks));
776
if ((flags & ERTS_P2P_FLG_TRY_LOCK)
777
&& (need_locks & ~have_locks)) {
778
erts_pid2proc_trylock_failed(proc,
782
old_lflgs); /* Unlocks
784
proc = ERTS_PROC_LOCK_BUSY;
788
need_locks &= ~have_locks;
950
if (flags & ERTS_P2P_FLG_SMP_INC_REFC)
952
#ifdef ERTS_ENABLE_LOCK_COUNT
953
erts_lcnt_proc_lock_unaquire(&proc->lock, lcnt_locks);
955
erts_pid2proc_safelock(c_p,
792
erts_pid2proc_safelock(c_p,
803
966
erts_pix_unlock(pix_lock);
804
967
#ifdef ERTS_PROC_LOCK_DEBUG
805
968
ERTS_LC_ASSERT(!proc
969
|| proc == ERTS_PROC_LOCK_BUSY
806
970
|| (pid_need_locks ==
807
971
(ERTS_PROC_LOCK_FLGS_READ_(&proc->lock)
808
972
& pid_need_locks)));
813
978
#if ERTS_PROC_LOCK_ATOMIC_IMPL
814
979
ETHR_COMPILER_BARRIER;