4 * Implement the MP lock. Note that debug operations
6 #ifndef _SYS_MPLOCK2_H_
7 #define _SYS_MPLOCK2_H_
9 #ifndef _MACHINE_ATOMIC_H_
10 #include <machine/atomic.h>
12 #ifndef _SYS_THREAD_H_
13 #include <sys/thread.h>
15 #ifndef _SYS_GLOBALDATA_H_
16 #include <sys/globaldata.h>
21 #define get_mplock() get_mplock_debug(__FILE__, __LINE__)
22 #define try_mplock() try_mplock_debug(__FILE__, __LINE__)
23 #define cpu_try_mplock() cpu_try_mplock_debug(__FILE__, __LINE__)
25 void _get_mplock_predisposed(const char *file, int line);
26 void _get_mplock_contested(const char *file, int line);
27 void _try_mplock_contested(const char *file, int line);
28 void _cpu_try_mplock_contested(const char *file, int line);
29 void _rel_mplock_contested(void);
30 void cpu_get_initial_mplock(void);
31 void handle_cpu_contention_mask(void);
32 void yield_mplock(struct thread *td);
35 extern int cpu_contention_mask;
36 extern const char *mp_lock_holder_file;
37 extern int mp_lock_holder_line;
40 * Acquire the MP lock, block until we get it.
42 * In order to acquire the MP lock we must first pre-dispose td_mpcount
43 * for the acquisition and then get the actual lock.
45 * The mplock must check a number of conditions and it is better to
46 * leave it to a procedure if we cannot get it trivially.
50 get_mplock_debug(const char *file, int line)
52 globaldata_t gd = mycpu;
53 thread_t td = gd->gd_curthread;
56 if (mp_lock != gd->gd_cpuid)
57 _get_mplock_predisposed(file, line);
63 * In order to release the MP lock we must first pre-dispose td_mpcount
64 * for the release and then, if it is 0, release the actual lock.
66 * The contested function is called only if we are unable to release the
67 * Actual lock. This can occur if we raced an interrupt after decrementing
68 * td_mpcount to 0 and the interrupt acquired and released the lock.
70 * The function also catches the td_mpcount underflow case because the
71 * lock will be in a released state and thus fail the subsequent release.
77 globaldata_t gd = mycpu;
78 thread_t td = gd->gd_curthread;
82 if (n <= 0 && atomic_cmpset_int(&mp_lock, gd->gd_cpuid, -1) == 0)
83 _rel_mplock_contested();
87 * Attempt to acquire the MP lock, returning 0 on failure and 1 on success.
89 * The contested function is called on failure and typically serves simply
90 * to log the attempt (if debugging enabled).
94 try_mplock_debug(const char *file, int line)
96 globaldata_t gd = mycpu;
97 thread_t td = gd->gd_curthread;
100 if (mp_lock != gd->gd_cpuid &&
101 atomic_cmpset_int(&mp_lock, -1, gd->gd_cpuid) == 0) {
102 _try_mplock_contested(file, line);
106 mp_lock_holder_file = file;
107 mp_lock_holder_line = line;
113 * Low level acquisition of the MP lock ignoring curthred->td_mpcount
115 * This version of try_mplock() is used when the caller has already
116 * predisposed td->td_mpcount.
118 * Returns non-zero on success, 0 on failure.
120 * WARNING: Must be called from within a critical section if td_mpcount is
121 * zero, otherwise an itnerrupt race can cause the lock to be lost.
125 cpu_try_mplock_debug(const char *file, int line)
127 globaldata_t gd = mycpu;
129 if (mp_lock != gd->gd_cpuid &&
130 atomic_cmpset_int(&mp_lock, -1, gd->gd_cpuid) == 0) {
131 _cpu_try_mplock_contested(file, line);
135 mp_lock_holder_file = file;
136 mp_lock_holder_line = line;
142 * A cpu wanted the MP lock but could not get it. This function is also
143 * called directly from the LWKT scheduler.
145 * Reentrant, may be called even if the cpu is already contending the MP
150 set_cpu_contention_mask(globaldata_t gd)
152 atomic_set_int(&cpu_contention_mask, gd->gd_cpumask);
156 * A cpu is no longer contending for the MP lock after previously contending
159 * Reentrant, may be called even if the cpu was not previously contending
164 clr_cpu_contention_mask(globaldata_t gd)
166 atomic_clear_int(&cpu_contention_mask, gd->gd_cpumask);
177 * Low level release of the MP lock ignoring curthread->td_mpcount
179 * WARNING: Caller must be in a critical section, otherwise the
180 * mp_lock can be lost from an interrupt race and we would
181 * end up clearing someone else's lock.
184 cpu_rel_mplock(int cpu)
186 (void)atomic_cmpset_int(&mp_lock, cpu, -1);
189 #define MP_LOCK_HELD(gd) \
190 (mp_lock == gd->gd_cpuid)
192 #define ASSERT_MP_LOCK_HELD(td) \
193 KASSERT(MP_LOCK_HELD(td->td_gd), \
194 ("MP_LOCK_HELD: Not held thread %p", td))
199 * UNI-PROCESSOR BUILD - Degenerate case macros
203 #define try_mplock() 1
204 #define owner_mplock() 0
205 #define MP_LOCK_HELD(gd) (!0)
206 #define ASSERT_MP_LOCK_HELD(td)