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