android mutex 详细介绍

一个进程中不可能只有一个线程在战斗,所以一个进程中一般都是有多个线程的同时协助工作,多线程情况下,对于一些全局变量,也就是多个线程能够同时访问的变量,我们需要通过加锁来防止“同时”访问这个变量,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  ,表示不可用了





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章