1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // +build freebsd linux
9 // This implementation depends on OS-specific implementations of
11 // runtime_futexsleep(uint32 *addr, uint32 val, int64 ns)
13 // if(*addr == val) sleep
14 // Might be woken up spuriously; that's allowed.
15 // Don't sleep longer than ns; ns < 0 means forever.
17 // runtime_futexwakeup(uint32 *addr, uint32 cnt)
18 // If any procs are sleeping on addr, wake up at most cnt.
31 // Possible lock states are MUTEX_UNLOCKED, MUTEX_LOCKED and MUTEX_SLEEPING.
32 // MUTEX_SLEEPING means that there is presumably at least one sleeping thread.
33 // Note that there can be spinning threads during all states - they do not
34 // affect mutex's state.
38 uint32 i
, v
, wait
, spin
;
40 if(runtime_m()->locks
++ < 0)
41 runtime_throw("runtime_lock: lock count");
43 // Speculative grab for lock.
44 v
= runtime_xchg(&l
->key
, MUTEX_LOCKED
);
45 if(v
== MUTEX_UNLOCKED
)
48 // wait is either MUTEX_LOCKED or MUTEX_SLEEPING
49 // depending on whether there is a thread sleeping
50 // on this mutex. If we ever change l->key from
51 // MUTEX_SLEEPING to some other value, we must be
52 // careful to change it back to MUTEX_SLEEPING before
53 // returning, to ensure that the sleeping thread gets
57 // On uniprocessor's, no point spinning.
58 // On multiprocessors, spin for ACTIVE_SPIN attempts.
64 // Try for lock, spinning.
65 for(i
= 0; i
< spin
; i
++) {
66 while(l
->key
== MUTEX_UNLOCKED
)
67 if(runtime_cas(&l
->key
, MUTEX_UNLOCKED
, wait
))
69 runtime_procyield(ACTIVE_SPIN_CNT
);
72 // Try for lock, rescheduling.
73 for(i
=0; i
< PASSIVE_SPIN
; i
++) {
74 while(l
->key
== MUTEX_UNLOCKED
)
75 if(runtime_cas(&l
->key
, MUTEX_UNLOCKED
, wait
))
81 v
= runtime_xchg(&l
->key
, MUTEX_SLEEPING
);
82 if(v
== MUTEX_UNLOCKED
)
84 wait
= MUTEX_SLEEPING
;
85 runtime_futexsleep(&l
->key
, MUTEX_SLEEPING
, -1);
90 runtime_unlock(Lock
*l
)
94 if(--runtime_m()->locks
< 0)
95 runtime_throw("runtime_unlock: lock count");
97 v
= runtime_xchg(&l
->key
, MUTEX_UNLOCKED
);
98 if(v
== MUTEX_UNLOCKED
)
99 runtime_throw("unlock of unlocked lock");
100 if(v
== MUTEX_SLEEPING
)
101 runtime_futexwakeup(&l
->key
, 1);
104 // One-time notifications.
106 runtime_noteclear(Note
*n
)
112 runtime_notewakeup(Note
*n
)
114 runtime_xchg(&n
->key
, 1);
115 runtime_futexwakeup(&n
->key
, 1);
119 runtime_notesleep(Note
*n
)
121 if(runtime_m()->profilehz
> 0)
122 runtime_setprof(false);
123 while(runtime_atomicload(&n
->key
) == 0)
124 runtime_futexsleep(&n
->key
, 0, -1);
125 if(runtime_m()->profilehz
> 0)
126 runtime_setprof(true);
130 runtime_notetsleep(Note
*n
, int64 ns
)
135 runtime_notesleep(n
);
139 if(runtime_atomicload(&n
->key
) != 0)
142 if(runtime_m()->profilehz
> 0)
143 runtime_setprof(false);
144 deadline
= runtime_nanotime() + ns
;
146 runtime_futexsleep(&n
->key
, 0, ns
);
147 if(runtime_atomicload(&n
->key
) != 0)
149 now
= runtime_nanotime();
154 if(runtime_m()->profilehz
> 0)
155 runtime_setprof(true);