10Sigor@sysoev.ru
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru * Copyright (C) Igor Sysoev
40Sigor@sysoev.ru * Copyright (C) NGINX, Inc.
50Sigor@sysoev.ru */
60Sigor@sysoev.ru
70Sigor@sysoev.ru #include <nxt_main.h>
80Sigor@sysoev.ru
90Sigor@sysoev.ru
100Sigor@sysoev.ru /*
110Sigor@sysoev.ru * All modern pthread mutex implementations try to acquire a lock atomically
120Sigor@sysoev.ru * in userland before going to sleep in kernel. Some spins on SMP systems
130Sigor@sysoev.ru * before the sleeping.
140Sigor@sysoev.ru *
150Sigor@sysoev.ru * In Solaris since version 8 all mutex types spin before sleeping.
160Sigor@sysoev.ru * The default spin count is 1000. It can be overridden using
170Sigor@sysoev.ru * _THREAD_ADAPTIVE_SPIN=100 environment variable.
180Sigor@sysoev.ru *
190Sigor@sysoev.ru * In MacOSX all mutex types spin to acquire a lock protecting a mutex's
200Sigor@sysoev.ru * internals. If the mutex is busy, thread calls Mach semaphore_wait().
210Sigor@sysoev.ru *
220Sigor@sysoev.ru *
230Sigor@sysoev.ru * PTHREAD_MUTEX_NORMAL lacks deadlock detection and is the fastest
240Sigor@sysoev.ru * mutex type.
250Sigor@sysoev.ru *
260Sigor@sysoev.ru * Linux: No spinning. The internal name PTHREAD_MUTEX_TIMED_NP
270Sigor@sysoev.ru * remains from the times when pthread_mutex_timedlock() was
280Sigor@sysoev.ru * non-standard extension. Alias name: PTHREAD_MUTEX_FAST_NP.
290Sigor@sysoev.ru * FreeBSD: No spinning.
300Sigor@sysoev.ru *
310Sigor@sysoev.ru *
320Sigor@sysoev.ru * PTHREAD_MUTEX_ERRORCHECK is usually as fast as PTHREAD_MUTEX_NORMAL
330Sigor@sysoev.ru * yet has lightweight deadlock detection.
340Sigor@sysoev.ru *
350Sigor@sysoev.ru * Linux: No spinning. The internal name: PTHREAD_MUTEX_ERRORCHECK_NP.
360Sigor@sysoev.ru * FreeBSD: No spinning.
370Sigor@sysoev.ru *
380Sigor@sysoev.ru *
390Sigor@sysoev.ru * PTHREAD_MUTEX_RECURSIVE allows recursive locking.
400Sigor@sysoev.ru *
410Sigor@sysoev.ru * Linux: No spinning. The internal name: PTHREAD_MUTEX_RECURSIVE_NP.
420Sigor@sysoev.ru * FreeBSD: No spinning.
430Sigor@sysoev.ru *
440Sigor@sysoev.ru *
450Sigor@sysoev.ru * PTHREAD_MUTEX_ADAPTIVE_NP spins on SMP systems before sleeping.
460Sigor@sysoev.ru *
470Sigor@sysoev.ru * Linux: No deadlock detection. Dynamically changes a spin count
480Sigor@sysoev.ru * for each mutex from 10 to 100 based on spin count taken
490Sigor@sysoev.ru * previously.
500Sigor@sysoev.ru *
510Sigor@sysoev.ru * FreeBSD: Deadlock detection. The default spin count is 2000.
520Sigor@sysoev.ru * It can be overriden using LIBPTHREAD_SPINLOOPS environment
530Sigor@sysoev.ru * variable or by pthread_mutex_setspinloops_np(). If a lock
540Sigor@sysoev.ru * is still busy, sched_yield() can be called on both UP and
550Sigor@sysoev.ru * SMP systems. The default yield loop count is zero, but it
560Sigor@sysoev.ru * can be set by LIBPTHREAD_YIELDLOOPS environment variable or
570Sigor@sysoev.ru * by pthread_mutex_setyieldloops_np(). sched_yield() moves
580Sigor@sysoev.ru * a thread to the end of CPU scheduler run queue and this is
590Sigor@sysoev.ru * cheaper than removing the thread from the queue and sleeping.
600Sigor@sysoev.ru *
610Sigor@sysoev.ru * Solaris: No PTHREAD_MUTEX_ADAPTIVE_NP .
620Sigor@sysoev.ru * MacOSX: No PTHREAD_MUTEX_ADAPTIVE_NP.
630Sigor@sysoev.ru *
640Sigor@sysoev.ru *
650Sigor@sysoev.ru * PTHREAD_MUTEX_ELISION_NP is a Linux extension to elide locks using
660Sigor@sysoev.ru * Intel Restricted Transactional Memory. It is the most suitable for
670Sigor@sysoev.ru * rwlock pattern access because it allows simultaneous reads without lock.
680Sigor@sysoev.ru * Supported since glibc 2.18.
690Sigor@sysoev.ru *
700Sigor@sysoev.ru *
710Sigor@sysoev.ru * PTHREAD_MUTEX_DEFAULT is default mutex type.
720Sigor@sysoev.ru *
730Sigor@sysoev.ru * Linux: PTHREAD_MUTEX_NORMAL.
740Sigor@sysoev.ru * FreeBSD: PTHREAD_MUTEX_ERRORCHECK.
750Sigor@sysoev.ru * Solaris: PTHREAD_MUTEX_NORMAL.
760Sigor@sysoev.ru * MacOSX: PTHREAD_MUTEX_NORMAL.
770Sigor@sysoev.ru */
780Sigor@sysoev.ru
790Sigor@sysoev.ru
800Sigor@sysoev.ru nxt_int_t
nxt_thread_mutex_create(nxt_thread_mutex_t * mtx)810Sigor@sysoev.ru nxt_thread_mutex_create(nxt_thread_mutex_t *mtx)
820Sigor@sysoev.ru {
830Sigor@sysoev.ru nxt_err_t err;
840Sigor@sysoev.ru pthread_mutexattr_t attr;
850Sigor@sysoev.ru
860Sigor@sysoev.ru err = pthread_mutexattr_init(&attr);
870Sigor@sysoev.ru if (err != 0) {
88*564Svbart@nginx.com nxt_thread_log_alert("pthread_mutexattr_init() failed %E", err);
890Sigor@sysoev.ru return NXT_ERROR;
900Sigor@sysoev.ru }
910Sigor@sysoev.ru
920Sigor@sysoev.ru err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
930Sigor@sysoev.ru if (err != 0) {
94*564Svbart@nginx.com nxt_thread_log_alert("pthread_mutexattr_settype"
950Sigor@sysoev.ru "(PTHREAD_MUTEX_ERRORCHECK) failed %E", err);
960Sigor@sysoev.ru return NXT_ERROR;
970Sigor@sysoev.ru }
980Sigor@sysoev.ru
990Sigor@sysoev.ru err = pthread_mutex_init(mtx, &attr);
1000Sigor@sysoev.ru if (err != 0) {
101*564Svbart@nginx.com nxt_thread_log_alert("pthread_mutex_init() failed %E", err);
1020Sigor@sysoev.ru return NXT_ERROR;
1030Sigor@sysoev.ru }
1040Sigor@sysoev.ru
1050Sigor@sysoev.ru err = pthread_mutexattr_destroy(&attr);
1060Sigor@sysoev.ru if (err != 0) {
1070Sigor@sysoev.ru nxt_thread_log_alert("pthread_mutexattr_destroy() failed %E", err);
1080Sigor@sysoev.ru }
1090Sigor@sysoev.ru
1100Sigor@sysoev.ru nxt_thread_log_debug("pthread_mutex_init(%p)", mtx);
1110Sigor@sysoev.ru
1120Sigor@sysoev.ru return NXT_OK;
1130Sigor@sysoev.ru }
1140Sigor@sysoev.ru
1150Sigor@sysoev.ru
1160Sigor@sysoev.ru void
nxt_thread_mutex_destroy(nxt_thread_mutex_t * mtx)1170Sigor@sysoev.ru nxt_thread_mutex_destroy(nxt_thread_mutex_t *mtx)
1180Sigor@sysoev.ru {
1190Sigor@sysoev.ru nxt_err_t err;
1200Sigor@sysoev.ru
1210Sigor@sysoev.ru err = pthread_mutex_destroy(mtx);
1220Sigor@sysoev.ru if (nxt_slow_path(err != 0)) {
1230Sigor@sysoev.ru nxt_thread_log_alert("pthread_mutex_destroy() failed %E", err);
1240Sigor@sysoev.ru }
1250Sigor@sysoev.ru
1260Sigor@sysoev.ru nxt_thread_log_debug("pthread_mutex_destroy(%p)", mtx);
1270Sigor@sysoev.ru }
1280Sigor@sysoev.ru
1290Sigor@sysoev.ru
1300Sigor@sysoev.ru nxt_int_t
nxt_thread_mutex_lock(nxt_thread_mutex_t * mtx)1310Sigor@sysoev.ru nxt_thread_mutex_lock(nxt_thread_mutex_t *mtx)
1320Sigor@sysoev.ru {
1330Sigor@sysoev.ru nxt_err_t err;
1340Sigor@sysoev.ru
1350Sigor@sysoev.ru nxt_thread_log_debug("pthread_mutex_lock(%p) enter", mtx);
1360Sigor@sysoev.ru
1370Sigor@sysoev.ru err = pthread_mutex_lock(mtx);
1380Sigor@sysoev.ru if (nxt_fast_path(err == 0)) {
1390Sigor@sysoev.ru return NXT_OK;
1400Sigor@sysoev.ru }
1410Sigor@sysoev.ru
1420Sigor@sysoev.ru nxt_thread_log_alert("pthread_mutex_lock() failed %E", err);
1430Sigor@sysoev.ru
1440Sigor@sysoev.ru return NXT_ERROR;
1450Sigor@sysoev.ru }
1460Sigor@sysoev.ru
1470Sigor@sysoev.ru
1480Sigor@sysoev.ru nxt_bool_t
nxt_thread_mutex_trylock(nxt_thread_mutex_t * mtx)1490Sigor@sysoev.ru nxt_thread_mutex_trylock(nxt_thread_mutex_t *mtx)
1500Sigor@sysoev.ru {
1510Sigor@sysoev.ru nxt_err_t err;
1520Sigor@sysoev.ru
1530Sigor@sysoev.ru nxt_thread_debug(thr);
1540Sigor@sysoev.ru
1550Sigor@sysoev.ru nxt_log_debug(thr->log, "pthread_mutex_trylock(%p) enter", mtx);
1560Sigor@sysoev.ru
1570Sigor@sysoev.ru err = pthread_mutex_trylock(mtx);
1580Sigor@sysoev.ru if (nxt_fast_path(err == 0)) {
1590Sigor@sysoev.ru return 1;
1600Sigor@sysoev.ru }
1610Sigor@sysoev.ru
1620Sigor@sysoev.ru if (err == NXT_EBUSY) {
1630Sigor@sysoev.ru nxt_log_debug(thr->log, "pthread_mutex_trylock(%p) failed", mtx);
1640Sigor@sysoev.ru
1650Sigor@sysoev.ru } else {
1660Sigor@sysoev.ru nxt_thread_log_alert("pthread_mutex_trylock() failed %E", err);
1670Sigor@sysoev.ru }
1680Sigor@sysoev.ru
1690Sigor@sysoev.ru return 0;
1700Sigor@sysoev.ru }
1710Sigor@sysoev.ru
1720Sigor@sysoev.ru
1730Sigor@sysoev.ru nxt_int_t
nxt_thread_mutex_unlock(nxt_thread_mutex_t * mtx)1740Sigor@sysoev.ru nxt_thread_mutex_unlock(nxt_thread_mutex_t *mtx)
1750Sigor@sysoev.ru {
1760Sigor@sysoev.ru nxt_err_t err;
1770Sigor@sysoev.ru nxt_thread_t *thr;
1780Sigor@sysoev.ru
1790Sigor@sysoev.ru err = pthread_mutex_unlock(mtx);
1800Sigor@sysoev.ru
1810Sigor@sysoev.ru thr = nxt_thread();
1820Sigor@sysoev.ru nxt_thread_time_update(thr);
1830Sigor@sysoev.ru
1840Sigor@sysoev.ru if (nxt_fast_path(err == 0)) {
1850Sigor@sysoev.ru nxt_log_debug(thr->log, "pthread_mutex_unlock(%p) exit", mtx);
1860Sigor@sysoev.ru return NXT_OK;
1870Sigor@sysoev.ru }
1880Sigor@sysoev.ru
1890Sigor@sysoev.ru nxt_log_alert(thr->log, "pthread_mutex_unlock() failed %E", err);
1900Sigor@sysoev.ru
1910Sigor@sysoev.ru return NXT_ERROR;
1920Sigor@sysoev.ru }
193