一個進程中不可能只有一個線程在戰鬥,所以一個進程中一般都是有多個線程的同時協助工作,多線程情況下,對於一些全局變量,也就是多個線程能夠同時訪問的變量,我們需要通過加鎖來防止“同時”訪問這個變量,Mutex 就是我們常用的一個。
frameworks/av/include/camera/CameraBase.h
113 Mutex mLock;
frameworks/av/camera/Camera.cpp
214 void Camera::stopRecording()
215 {
216 ALOGV("stopRecording");
217 {
218 Mutex::Autolock _l(mLock);
219 mRecordingProxyListener.clear();
220 }
221 sp <::android::hardware::ICamera> c = mCamera;
222 if (c == 0) return;
223 c->stopRecording();
224 }
例如上面的代碼,首先會定義一個Mutex 對象mLock,在代碼中對全局變量訪問時,先要獲取mLock,例如上面在操作mRecordingProxyListener 時,先通過Mutex::Autolock _l(mLock);獲取這把鎖,加了大括號是限制這個鎖的作用域,離開這個作用域之後,這把鎖會自動釋放,下面會介紹。
system/core/include/utils/Mutex.h
100 pthread_mutex_t mMutex;
111 inline Mutex::Mutex() {
112 pthread_mutex_init(&mMutex, NULL);
113 }
83 class Autolock {
84 public:
85 inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
86 inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
87 inline ~Autolock() { mLock.unlock(); }
88 private:
89 Mutex& mLock;
90 };
131 inline status_t Mutex::lock() {
132 return -pthread_mutex_lock(&mMutex);
133 }
134 inline void Mutex::unlock() {
135 pthread_mutex_unlock(&mMutex);
136 }
128 inline Mutex::~Mutex() {
129 pthread_mutex_destroy(&mMutex);
130 }
通過上面的代碼我們知道 Mutex::Autolock _l(mLock) 獲取鎖和釋放鎖 是利用了C++ 類的構造函數和析構函數的特性實現的。在.h頭文件裏面定義 Mutex mLock; 的時候就已經調用了Mutex 的構造函數,進而調用到pthread_mutex_init()初始化pthread_mutex_t mMutex; 而Mutex::Autolock _l(mLock); 放在函數裏面定義,是一個局部變量,也會調用Autolock
的構造函數,進而調用到Mutex::lock(); Autolock 對象 _l 跑出大括號後,也就是跑出它的作用域後,會調用它的析構函數,進而調用到Mutex::unlock() 釋放鎖。
Mutex 只是對對pthread_mutex_xxx()接口做了一層封裝而已,真正的實現在pthread_mutex_xxx()接口。
pthread_mutex_xxx()聲明在bionic/libc/include/pthread.h
39 typedef struct {
40 #if defined(__LP64__)
41 int32_t __private[10]; //長度爲10的整形數組
42 #else
43 int32_t __private[1]; //長度爲1 的整形數組
44 #endif
45 } pthread_mutex_t;
1、初始化函數pthread_mutex_init()
bionic/libc/bionic/pthread_mutex.cpp
241 int pthread_mutex_init(pthread_mutex_t* mutex_interface, const pthread_mutexattr_t* attr) {
/*
* struct pthread_mutex_internal_t {
* _Atomic(uint16_t) state; //2 byte
* #if defined(__LP64__) //64爲定義是長度爲10的整形數組, 40 byte
* uint16_t __pad; //2 byte
* atomic_int owner_tid; //4 byte
* char __reserved[32]; //32 byte
* #else //長度爲1 的整形數組, 4 byte
* _Atomic(uint16_t) owner_tid; //2 byte
* #endif
* } __attribute__((aligned(4)));
*/
242 pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
243
244 memset(mutex, 0, sizeof(pthread_mutex_internal_t)); //mutex 所有byte設置爲 0
245
246 if (__predict_true(attr == NULL)) { //沒有設置相關屬性時
247 atomic_init(&mutex->state, MUTEX_TYPE_BITS_NORMAL); //mutex->state = (((0) & ((1 << (2))-1)) << (14)) 也就是0
248 return 0;
249 }
... //因爲針對上面的實現傳入的attr 爲NULL,所以這部分的代碼先不做分析
272 return 0;
273 }
2、獲取鎖函數pthread_mutex_lock()
bionic/libc/bionic/pthread_mutex.cpp
503 int pthread_mutex_lock(pthread_mutex_t* mutex_interface) {
504 #if !defined(__LP64__) //非64爲系統
505 if (mutex_interface == NULL) {
506 return EINVAL;
507 }
508 #endif
509
510 pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
511
512 uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed); //old_state = mutex->state
513 uint16_t mtype = (old_state & MUTEX_TYPE_MASK); //mtype =old_state &(((1 << (2))-1) << (14)) 也就是mtype =old_state & 49152
514 uint16_t shared = (old_state & MUTEX_SHARED_MASK);//shared =old_state &(((1 << (1))-1) << (13)) 也就是shared =old_state & 8192
515 // Avoid slowing down fast path of normal mutex lock operation.
516 if (__predict_true(mtype == MUTEX_TYPE_BITS_NORMAL)) { //MUTEX_TYPE_BITS_NORMAL =0
517 if (__predict_true(__pthread_normal_mutex_trylock(mutex, shared) == 0)) {
518 return 0;
519 }
520 }
521 return __pthread_mutex_lock_with_timeout(mutex, false, nullptr);
522 }
pthread_mutex_lock() 先判斷 是否可以直接獲取鎖,沒有其他線程在使用的時候可以獲取,通過__pthread_normal_mutex_trylock()來實現
275 static inline __always_inline int __pthread_normal_mutex_trylock(pthread_mutex_internal_t* mutex,
276 uint16_t shared) {
277 const uint16_t unlocked = shared | MUTEX_STATE_BITS_UNLOCKED; //MUTEX_STATE_BITS_UNLOCKED = 0
278 const uint16_t locked_uncontended = shared | MUTEX_STATE_BITS_LOCKED_UNCONTENDED; //MUTEX_STATE_BITS_LOCKED_UNCONTENDED = 16384
279
280 uint16_t old_state = unlocked;
//如果 mutex->state == old_state, mutex->state = locked_uncontended
//否則 mutex->state = old_state
281 if (__predict_true(atomic_compare_exchange_strong_explicit(&mutex->state, &old_state, //
282 locked_uncontended, memory_order_acquire, memory_order_relaxed))) {
283 return 0;
284 }
285 return EBUSY;
286 }
__pthread_normal_mutex_trylock()會判讀mutex->state 是否等於old_state,如果相等 ,將 mutex->state 的值設置成 locked_uncontended,否則設置成old_state 。
如果獲取不到這個鎖,就會往下走到__pthread_mutex_lock_with_timeout()。
421 static int __pthread_mutex_lock_with_timeout(pthread_mutex_internal_t* mutex,
422 bool use_realtime_clock,
423 const timespec* abs_timeout_or_null) {
424 uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed); //old_state = mutex->state
425 uint16_t mtype = (old_state & MUTEX_TYPE_MASK); //mtype =old_state &(((1 << (2))-1) << (14)) 也就是mtype =old_state & 49152
426 uint16_t shared = (old_state & MUTEX_SHARED_MASK); //shared =old_state &(((1 << (1))-1) << (13)) 也就是shared =old_state & 8192
427
428 // Handle common case first.
429 if ( __predict_true(mtype == MUTEX_TYPE_BITS_NORMAL) ) { //MUTEX_TYPE_BITS_NORMAL = 0
430 return __pthread_normal_mutex_lock(mutex, shared, use_realtime_clock, abs_timeout_or_null);
431 }
... //我們重點關注實現的流程,其他額外處理部分的代碼先不分析
501 }
接着走到__pthread_normal_mutex_lock(), 傳入的參數use_realtime_clock 爲false,abs_timeout_or_null 爲 nullptr
static inline __always_inline int __pthread_normal_mutex_lock(pthread_mutex_internal_t* mutex,
301 uint16_t shared,
302 bool use_realtime_clock,
303 const timespec* abs_timeout_or_null) {
304 if (__predict_true(__pthread_normal_mutex_trylock(mutex, shared) == 0)) { //前面解釋過了
305 return 0;
306 }
307 int result = check_timespec(abs_timeout_or_null, true); //這裏會返回 0
308 if (result != 0) {
309 return result;
310 }
311
312 ScopedTrace trace("Contending for pthread mutex");
313
314 const uint16_t unlocked = shared | MUTEX_STATE_BITS_UNLOCKED;
315 const uint16_t locked_contended = shared | MUTEX_STATE_BITS_LOCKED_CONTENDED;
316
317 // We want to go to sleep until the mutex is available, which requires
318 // promoting it to locked_contended. We need to swap in the new state
319 // and then wait until somebody wakes us up.
320 // An atomic_exchange is used to compete with other threads for the lock.
321 // If it returns unlocked, we have acquired the lock, otherwise another
322 // thread still holds the lock and we should wait again.
323 // If lock is acquired, an acquire fence is needed to make all memory accesses
324 // made by other threads visible to the current CPU.
/*
* atomic_exchange_explicit()執行的結果是mutex->state = locked_contended ,返回值是之前的 mutex->state
* 所以這個條件可以理解成 uint16_t temp = mutex->state;mutex->state = locked_contended , temp != unlocked
*/
325 while (atomic_exchange_explicit(&mutex->state, locked_contended,
326 memory_order_acquire) != unlocked) {
327 if (__futex_wait_ex(&mutex->state, shared, locked_contended, use_realtime_clock,
328 abs_timeout_or_null) == -ETIMEDOUT) {
329 return ETIMEDOUT;
330 }
331 }
332 return 0;
333 }
首先會重新去獲取鎖,調用__pthread_normal_mutex_trylock() 嘗試去獲取,前面有介紹這個函數,如果還是拿不到,會走到最後的while 裏面,atomic_exchange_explicit() 的返回值是修改之前的mutex->state,也就是進入這個函數之前的mutex->state,如果狀態不是unlocked,繼續走到__futex_wait_ex(),
bionic/libc/private/bionic_futex.h
68 static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value,
69 bool use_realtime_clock, const struct timespec* abs_timeout) {
70 return __futex(ftx, (shared ? FUTEX_WAIT_BITSET : FUTEX_WAIT_BITSET_PRIVATE) |
71 (use_realtime_clock ? FUTEX_CLOCK_REALTIME : 0), value, abs_timeout,
72 FUTEX_BITSET_MATCH_ANY);
73 }
繼續調用__futex_wait_ex()
43 static inline __always_inline int __futex(volatile void* ftx, int op, int value,
44 const struct timespec* timeout,
45 int bitset) {
46 // Our generated syscall assembler sets errno, but our callers (pthread functions) don't want to.
47 int saved_errno = errno;
48 int result = syscall(__NR_futex, ftx, op, value, timeout, NULL, bitset);
49 if (__predict_false(result == -1)) {
50 result = -errno;
51 errno = saved_errno;
52 }
53 return result;
54 }
__futex_wait_ex()會調用到syscall()函數,是一個系統調用函數,所以接下里就跑到kernel。
linux-4.10/kernel/futex.c
3243 SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
3244 struct timespec __user *, utime, u32 __user *, uaddr2,
3245 u32, val3)
3246 {
...
3275 return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
3276 }
系統調用從user 空間切換到kernel 空間,前面的博客有詳細介紹過,這裏不再介紹,我們理所當然地認爲就調用到了kernel 的do_futex()。
傳入的參數uaddr 就是指向mutex->state 的地址,op 是FUTEX_WAIT/FUTEX_WAIT_BITSET, val 是上面的locked_contended,tp 是 NULL。
3185 long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
3186 u32 __user *uaddr2, u32 val2, u32 val3)
3187 {
3188 int cmd = op & FUTEX_CMD_MASK;
...
3211 switch (cmd) {
3212 case FUTEX_WAIT:
3213 val3 = FUTEX_BITSET_MATCH_ANY;
3214 case FUTEX_WAIT_BITSET:
3215 return futex_wait(uaddr, flags, val, timeout, val3); //原子檢查uaddr 的值是否和val相等
...
3238 }
3239 return -ENOSYS;
3240 }
根據前面參數的解釋,我們知道上面的case 會走到 futex_wait()
2402 static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val,
2403 ktime_t *abs_time, u32 bitset)
2404 {
2405 struct hrtimer_sleeper timeout, *to = NULL;
2406 struct restart_block *restart;
2407 struct futex_hash_bucket *hb;
2408 struct futex_q q = futex_q_init;
2409 int ret;
2410
2411 if (!bitset)
2412 return -EINVAL;
2413 q.bitset = bitset;
2414
2415 if (abs_time) {
2416 to = &timeout;
2417
2418 hrtimer_init_on_stack(&to->timer, (flags & FLAGS_CLOCKRT) ?
2419 CLOCK_REALTIME : CLOCK_MONOTONIC,
2420 HRTIMER_MODE_ABS);
2421 hrtimer_init_sleeper(to, current);
2422 hrtimer_set_expires_range_ns(&to->timer, *abs_time,
2423 current->timer_slack_ns);
2424 }
2425
2426 retry:
2427 /*
2428 * Prepare to wait on uaddr. On success, holds hb lock and increments
2429 * q.key refs.
2430 */
2431 ret = futex_wait_setup(uaddr, val, flags, &q, &hb); //
2432 if (ret)
2433 goto out;
2434
2435 /* queue_me and wait for wakeup, timeout, or a signal. */
2436 futex_wait_queue_me(hb, &q, to);
2437
2438 /* If we were woken (and unqueued), we succeeded, whatever. */
2439 ret = 0;
2440 /* unqueue_me() drops q.key ref */
2441 if (!unqueue_me(&q))
2442 goto out;
...
2468 out:
2469 if (to) {
2470 hrtimer_cancel(&to->timer);
2471 destroy_hrtimer_on_stack(&to->timer);
2472 }
2473 return ret;
2474 }
如果設置有超時,會掛到hrtimer(高精度實時定時器)上,這裏沒有設置,我們重點關注futex_wait_setup() 和futex_wait_queue_me()
static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
2344 struct futex_q *q, struct futex_hash_bucket **hb)
2345 {
2346 u32 uval;
2347 int ret;
...
2367 retry:
2368 ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key, VERIFY_READ);
2369 if (unlikely(ret != 0))
2370 return ret;
2371
2372 retry_private:
2373 *hb = queue_lock(q);
2374
2375 ret = get_futex_value_locked(&uval, uaddr);
2376
2377 if (ret) {
2378 queue_unlock(*hb);
2379
2380 ret = get_user(uval, uaddr);
2381 if (ret)
2382 goto out;
2383
2384 if (!(flags & FLAGS_SHARED))
2385 goto retry_private;
2386
2387 put_futex_key(&q->key);
2388 goto retry;
2389 }
2390
2391 if (uval != val) {
2392 queue_unlock(*hb);
2393 ret = -EWOULDBLOCK;
2394 }
2395
2396 out:
2397 if (ret)
2398 put_futex_key(&q->key);
2399 return ret;
2400 }
這個函數裏面會比較mutex->state 和 val(locked_contended)是否相等,因爲可能這時候有線程把鎖釋放了,不相等表示可以拿到鎖了。
2294 static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
2295 struct hrtimer_sleeper *timeout)
2296 {
2297 /*
2298 * The task state is guaranteed to be set before another task can
2299 * wake it. set_current_state() is implemented using smp_store_mb() and
2300 * queue_me() calls spin_unlock() upon completion, both serializing
2301 * access to the hash list and forcing another memory barrier.
2302 */
2303 set_current_state(TASK_INTERRUPTIBLE); //可以被中斷
2304 queue_me(q, hb);
2305
2306 /* Arm the timer */
2307 if (timeout)
2308 hrtimer_start_expires(&timeout->timer, HRTIMER_MODE_ABS);
2309
2310 /*
2311 * If we have been removed from the hash list, then another task
2312 * has tried to wake us, and we can skip the call to schedule().
2313 */
2314 if (likely(!plist_node_empty(&q->list))) {
2315 /*
2316 * If the timer has already expired, current will already be
2317 * flagged for rescheduling. Only call schedule if there
2318 * is no timeout, or if it has yet to expire.
2319 */
2320 if (!timeout || timeout->task)
2321 freezable_schedule(); //調用 schedule() 進行調度
2322 }
2323 __set_current_state(TASK_RUNNING);
2324 }
如果還是沒有拿到鎖,就會進入到上面的futex_wait_queue_me(),這個裏面會把當前進程設置爲可中斷的,並且把當前task_structr放到 futex_q 中。
2022 static inline void queue_me(struct futex_q *q, struct futex_hash_bucket *hb)
2023 __releases(&hb->lock)
2024 {
2025 int prio;
2026
2027 /*
2028 * The priority used to register this element is
2029 * - either the real thread-priority for the real-time threads
2030 * (i.e. threads with a priority lower than MAX_RT_PRIO)
2031 * - or MAX_RT_PRIO for non-RT threads.
2032 * Thus, all RT-threads are woken first in priority order, and
2033 * the others are woken last, in FIFO order.
2034 */
2035 prio = min(current->normal_prio, MAX_RT_PRIO); //設置進程的優先級
2036
2037 plist_node_init(&q->list, prio);
2038 plist_add(&q->list, &hb->chain);
2039 q->task = current;
2040 spin_unlock(&hb->lock);
2041 }
把當前task_structr放到 futex_q 後,調用freezable_schedule() 做進程調度,所以這個進程就被調度出去了。linux-4.10/include/linux/freezer.h
168 static inline void freezable_schedule(void)
169 {
170 freezer_do_not_count();
171 schedule();
172 freezer_count();
173 }
走到這裏,相當於當前進程陷入到kernel 的系統調用中,並且被調度出cpu的運行隊列,放到futex_q 隊列中。
3、釋放鎖函數pthread_mutex_unlock()
bionic/libc/bionic/pthread_mutex.cpp
524 int pthread_mutex_unlock(pthread_mutex_t* mutex_interface) {
525 #if !defined(__LP64__)
526 if (mutex_interface == NULL) {
527 return EINVAL;
528 }
529 #endif
530
531 pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
532
533 uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
534 uint16_t mtype = (old_state & MUTEX_TYPE_MASK);
535 uint16_t shared = (old_state & MUTEX_SHARED_MASK);
536
537 // Handle common case first.
538 if (__predict_true(mtype == MUTEX_TYPE_BITS_NORMAL)) {
539 __pthread_normal_mutex_unlock(mutex, shared);
540 return 0;
541 }
...
571 return 0;
572 }
如前面描述的,跑出作用域後,會釋放這個鎖,繼而調用到pthread_mutex_unlock()
339 static inline __always_inline void __pthread_normal_mutex_unlock(pthread_mutex_internal_t* mutex,
340 uint16_t shared) {
341 const uint16_t unlocked = shared | MUTEX_STATE_BITS_UNLOCKED;
342 const uint16_t locked_contended = shared | MUTEX_STATE_BITS_LOCKED_CONTENDED;
343
344 // We use an atomic_exchange to release the lock. If locked_contended state
345 // is returned, some threads is waiting for the lock and we need to wake up
346 // one of them.
347 // A release fence is required to make previous stores visible to next
348 // lock owner threads.
349 if (atomic_exchange_explicit(&mutex->state, unlocked,
350 memory_order_release) == locked_contended) {
351 // Wake up one waiting thread. We don't know which thread will be
352 // woken or when it'll start executing -- futexes make no guarantees
353 // here. There may not even be a thread waiting.
354 //
355 // The newly-woken thread will replace the unlocked state we just set above
356 // with locked_contended state, which means that when it eventually releases
357 // the mutex it will also call FUTEX_WAKE. This results in one extra wake
358 // call whenever a lock is contended, but let us avoid forgetting anyone
359 // without requiring us to track the number of sleepers.
360 //
361 // It's possible for another thread to sneak in and grab the lock between
362 // the exchange above and the wake call below. If the new thread is "slow"
363 // and holds the lock for a while, we'll wake up a sleeper, which will swap
364 // in locked_uncontended state and then go back to sleep since the lock is
365 // still held. If the new thread is "fast", running to completion before
366 // we call wake, the thread we eventually wake will find an unlocked mutex
367 // and will execute. Either way we have correct behavior and nobody is
368 // orphaned on the wait queue.
369 __futex_wake_ex(&mutex->state, shared, 1);
370 }
371 }
__pthread_normal_mutex_unlock()會判斷當前線程是否還持有這個鎖,如果是,會調用到__futex_wake_ex() bionic/libc/private/bionic_futex.h
60 static inline int __futex_wake_ex(volatile void* ftx, bool shared, int count) {
61 return __futex(ftx, shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, count, NULL, 0);
62 }
43 static inline __always_inline int __futex(volatile void* ftx, int op, int value,
44 const struct timespec* timeout,
45 int bitset) {
46 // Our generated syscall assembler sets errno, but our callers (pthread functions) don't want to.
47 int saved_errno = errno;
48 int result = syscall(__NR_futex, ftx, op, value, timeout, NULL, bitset);
49 if (__predict_false(result == -1)) {
50 result = -errno;
51 errno = saved_errno;
52 }
53 return result;
54 }
又是系統調用,這裏我們直接跳到kernel 的 do_futex()
linux-4.10/kernel/futex.c
3185 long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
3186 u32 __user *uaddr2, u32 val2, u32 val3)
3187 {
3188 int cmd = op & FUTEX_CMD_MASK;
...
3211 switch (cmd) {
...
3216 case FUTEX_WAKE:
3217 val3 = FUTEX_BITSET_MATCH_ANY;
3218 case FUTEX_WAKE_BITSET:
3219 return futex_wake(uaddr, flags, val, val3);
...
3238 }
3239 return -ENOSYS;
3240 }
傳入的參數uaddr 指向&mutex->state,op 爲FUTEX_WAKE / FUTEX_WAKE_PRIVATE ,val等於 1,接着跑到futex_wake()
1411 static int
1412 futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
1413 {
1414 struct futex_hash_bucket *hb;
1415 struct futex_q *this, *next;
1416 union futex_key key = FUTEX_KEY_INIT;
1417 int ret;
1418 DEFINE_WAKE_Q(wake_q);
1419
1420 if (!bitset)
1421 return -EINVAL;
1422
1423 ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_READ);
1424 if (unlikely(ret != 0))
1425 goto out;
1426
1427 hb = hash_futex(&key);
1428
1429 /* Make sure we really have tasks to wakeup */
1430 if (!hb_waiters_pending(hb))
1431 goto out_put_key;
1432
1433 spin_lock(&hb->lock);
1434
1435 plist_for_each_entry_safe(this, next, &hb->chain, list) {
1436 if (match_futex (&this->key, &key)) {
1437 if (this->pi_state || this->rt_waiter) {
1438 ret = -EINVAL;
1439 break;
1440 }
1441
1442 /* Check if one of the bits is set in both bitsets */
1443 if (!(this->bitset & bitset))
1444 continue;
1445
1446 mark_wake_futex(&wake_q, this);
1447 if (++ret >= nr_wake)
1448 break;
1449 }
1450 }
1451
1452 spin_unlock(&hb->lock);
1453 wake_up_q(&wake_q); //喚醒隊列中的task_struct
1454 out_put_key:
1455 put_futex_key(&key);
1456 out:
1457 return ret;
1458 }
根據上傳下來的值知道nr_wake 爲1,所以mark_wake_futex()只會跑一次。
1272 static void mark_wake_futex(struct wake_q_head *wake_q, struct futex_q *q)
1273 {
1274 struct task_struct *p = q->task;
1275
1276 if (WARN(q->pi_state || q->rt_waiter, "refusing to wake PI futex\n"))
1277 return;
1278
1279 /*
1280 * Queue the task for later wakeup for after we've released
1281 * the hb->lock. wake_q_add() grabs reference to p.
1282 */
1283 wake_q_add(wake_q, p);
1284 __unqueue_futex(q);
1285 /*
1286 * The waiting task can free the futex_q as soon as
1287 * q->lock_ptr = NULL is written, without taking any locks. A
1288 * memory barrier is required here to prevent the following
1289 * store to lock_ptr from getting ahead of the plist_del.
1290 */
1291 smp_wmb();
1292 q->lock_ptr = NULL;
1293 }
mark_wake_futex() 就是把要喚醒的task_struct 放入wake_q 隊列中 ,wake_q_add() ,最後調用wake_up_q(&wake_q); 來喚醒(調度)task_struct, 所以前面獲取鎖的系統調用就會返回。
4、銷燬mutex pthread_mutex_destroy()
bionic/libc/bionic/pthread_mutex.cpp
634 int pthread_mutex_destroy(pthread_mutex_t* mutex_interface) {
635 pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
636 uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
637 // Store 0xffff to make the mutex unusable. Although POSIX standard says it is undefined
638 // behavior to destroy a locked mutex, we prefer not to change mutex->state in that situation.
639 if (MUTEX_STATE_BITS_IS_UNLOCKED(old_state) && //old_state & 49152 == 0
640 atomic_compare_exchange_strong_explicit(&mutex->state, &old_state, 0xffff,
641 memory_order_relaxed, memory_order_relaxed)) {
642 return 0;
643 }
644 return EBUSY;
645 }
如果沒有線程在使用,就把mutex->state 設置成0xffff ,表示不可用了