Coverage Report

Created: 2026-03-08 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/unit/src/nxt_spinlock.c
Line
Count
Source
1
2
/*
3
 * Copyright (C) Igor Sysoev
4
 * Copyright (C) NGINX, Inc.
5
 */
6
7
#include <nxt_main.h>
8
9
10
/*
11
 * Linux supports pthread spinlocks since glibc 2.3.  Spinlock is an
12
 * atomic integer with zero initial value.  On i386/amd64 however the
13
 * initial value is one.  Spinlock never yields control.
14
 *
15
 * FreeBSD 5.2 and Solaris 10 support pthread spinlocks.  Spinlock is a
16
 * structure and uses mutex implementation so it must be initialized by
17
 * by pthread_spin_init() and destroyed by pthread_spin_destroy().
18
 *
19
 * MacOSX supported OSSpinLockLock(), it was deprecated in 10.12 (Sierra).
20
 * OSSpinLockLock() tries to acquire a lock atomically.  If the lock is
21
 * busy, on SMP system it tests the lock 1000 times in a tight loop with
22
 * "pause" instruction.  If the lock has been released, OSSpinLockLock()
23
 * tries to acquire it again.  On failure it goes again in the tight loop.
24
 * If the lock has not been released during spinning in the loop or
25
 * on UP system, OSSpinLockLock() calls thread_switch() to run 1ms
26
 * with depressed (the lowest) priority.
27
 */
28
29
30
/* It should be adjusted with the "spinlock_count" directive. */
31
static nxt_uint_t  nxt_spinlock_count = 1000;
32
33
34
void
35
nxt_thread_spin_init(nxt_uint_t ncpu, nxt_uint_t count)
36
2
{
37
2
    switch (ncpu) {
38
39
0
    case 0:
40
        /* Explicit spinlock count. */
41
0
        nxt_spinlock_count = count;
42
0
        break;
43
44
0
    case 1:
45
        /* Spinning is useless on UP. */
46
0
        nxt_spinlock_count = 0;
47
0
        break;
48
49
2
    default:
50
        /*
51
         * SMP.
52
         *
53
         * TODO: The count should be 10 on a virtualized system
54
         * since virtualized CPUs may share the same physical CPU.
55
         */
56
2
        nxt_spinlock_count = 1000;
57
2
        break;
58
2
    }
59
2
}
60
61
62
void
63
nxt_thread_spin_lock(nxt_thread_spinlock_t *lock)
64
0
{
65
0
    nxt_uint_t  n;
66
67
0
    nxt_thread_log_debug("spin_lock(%p) enter", lock);
68
69
0
    for ( ;; ) {
70
71
0
    again:
72
73
0
        if (nxt_fast_path(nxt_atomic_try_lock(lock))) {
74
0
            return;
75
0
        }
76
77
0
        for (n = nxt_spinlock_count; n != 0; n--) {
78
79
0
            nxt_cpu_pause();
80
81
0
            if (*lock == 0) {
82
0
                goto again;
83
0
            }
84
0
        }
85
86
0
        nxt_thread_yield();
87
0
    }
88
0
}
89
90
91
nxt_bool_t
92
nxt_thread_spin_trylock(nxt_thread_spinlock_t *lock)
93
0
{
94
0
    nxt_thread_log_debug("spin_trylock(%p) enter", lock);
95
96
0
    if (nxt_fast_path(nxt_atomic_try_lock(lock))) {
97
0
        return 1;
98
0
    }
99
100
0
    nxt_thread_log_debug("spin_trylock(%p) failed", lock);
101
102
0
    return 0;
103
0
}
104
105
106
void
107
nxt_thread_spin_unlock(nxt_thread_spinlock_t *lock)
108
0
{
109
0
    nxt_atomic_release(lock);
110
111
0
    nxt_thread_log_debug("spin_unlock(%p) exit", lock);
112
0
}