github.com/afumu/libc@v0.0.6/musl/src/thread/__lock.c (about)

     1  #include "pthread_impl.h"
     2  
     3  /* This lock primitive combines a flag (in the sign bit) and a
     4   * congestion count (= threads inside the critical section, CS) in a
     5   * single int that is accessed through atomic operations. The states
     6   * of the int for value x are:
     7   *
     8   * x == 0: unlocked and no thread inside the critical section
     9   *
    10   * x < 0: locked with a congestion of x-INT_MIN, including the thread
    11   * that holds the lock
    12   *
    13   * x > 0: unlocked with a congestion of x
    14   *
    15   * or in an equivalent formulation x is the congestion count or'ed
    16   * with INT_MIN as a lock flag.
    17   */
    18  
    19  void __lock(volatile int *l)
    20  {
    21  	int need_locks = libc.need_locks;
    22  	if (!need_locks) return;
    23  	/* fast path: INT_MIN for the lock, +1 for the congestion */
    24  	int current = a_cas(l, 0, INT_MIN + 1);
    25  	if (need_locks < 0) libc.need_locks = 0;
    26  	if (!current) return;
    27  	/* A first spin loop, for medium congestion. */
    28  	for (unsigned i = 0; i < 10; ++i) {
    29  		if (current < 0) current -= INT_MIN + 1;
    30  		// assertion: current >= 0
    31  		int val = a_cas(l, current, INT_MIN + (current + 1));
    32  		if (val == current) return;
    33  		current = val;
    34  	}
    35  	// Spinning failed, so mark ourselves as being inside the CS.
    36  	current = a_fetch_add(l, 1) + 1;
    37  	/* The main lock acquisition loop for heavy congestion. The only
    38  	 * change to the value performed inside that loop is a successful
    39  	 * lock via the CAS that acquires the lock. */
    40  	for (;;) {
    41  		/* We can only go into wait, if we know that somebody holds the
    42  		 * lock and will eventually wake us up, again. */
    43  		if (current < 0) {
    44  			__futexwait(l, current, 1);
    45  			current -= INT_MIN + 1;
    46  		}
    47  		/* assertion: current > 0, the count includes us already. */
    48  		int val = a_cas(l, current, INT_MIN + current);
    49  		if (val == current) return;
    50  		current = val;
    51  	}
    52  }
    53  
    54  void __unlock(volatile int *l)
    55  {
    56  	/* Check l[0] to see if we are multi-threaded. */
    57  	if (l[0] < 0) {
    58  		if (a_fetch_add(l, -(INT_MIN + 1)) != (INT_MIN + 1)) {
    59  			__wake(l, 1, 1);
    60  		}
    61  	}
    62  }