Mercurial > hg > nginx
comparison src/os/unix/ngx_thread_mutex.c @ 6018:466bd63b63d1
Thread pools implementation.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Sat, 14 Mar 2015 17:37:07 +0300 |
parents | |
children | e511e3d581bb |
comparison
equal
deleted
inserted
replaced
6017:83d54192e97b | 6018:466bd63b63d1 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 * Copyright (C) Nginx, Inc. | |
5 */ | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 | |
10 | |
11 /* | |
12 * All modern pthread mutex implementations try to acquire a lock | |
13 * atomically in userland before going to sleep in kernel. Some | |
14 * spins before the sleeping. | |
15 * | |
16 * In Solaris since version 8 all mutex types spin before sleeping. | |
17 * The default spin count is 1000. It can be overridden using | |
18 * _THREAD_ADAPTIVE_SPIN=100 environment variable. | |
19 * | |
20 * In MacOSX all mutex types spin to acquire a lock protecting a mutex's | |
21 * internals. If the mutex is busy, thread calls Mach semaphore_wait(). | |
22 * | |
23 * | |
24 * PTHREAD_MUTEX_NORMAL lacks deadlock detection and is the fastest | |
25 * mutex type. | |
26 * | |
27 * Linux: No spinning. The internal name PTHREAD_MUTEX_TIMED_NP | |
28 * remains from the times when pthread_mutex_timedlock() was | |
29 * non-standard extension. Alias name: PTHREAD_MUTEX_FAST_NP. | |
30 * FreeBSD: No spinning. | |
31 * | |
32 * | |
33 * PTHREAD_MUTEX_ERRORCHECK is usually as fast as PTHREAD_MUTEX_NORMAL | |
34 * yet has lightweight deadlock detection. | |
35 * | |
36 * Linux: No spinning. The internal name: PTHREAD_MUTEX_ERRORCHECK_NP. | |
37 * FreeBSD: No spinning. | |
38 * | |
39 * | |
40 * PTHREAD_MUTEX_RECURSIVE allows recursive locking. | |
41 * | |
42 * Linux: No spinning. The internal name: PTHREAD_MUTEX_RECURSIVE_NP. | |
43 * FreeBSD: No spinning. | |
44 * | |
45 * | |
46 * PTHREAD_MUTEX_ADAPTIVE_NP spins on SMP systems before sleeping. | |
47 * | |
48 * Linux: No deadlock detection. Dynamically changes a spin count | |
49 * for each mutex from 10 to 100 based on spin count taken | |
50 * previously. | |
51 * FreeBSD: Deadlock detection. The default spin count is 2000. | |
52 * It can be overriden using LIBPTHREAD_SPINLOOPS environment | |
53 * variable or by pthread_mutex_setspinloops_np(). If a lock | |
54 * is still busy, sched_yield() can be called on both UP and | |
55 * SMP systems. The default yield loop count is zero, but | |
56 * it can be set by LIBPTHREAD_YIELDLOOPS environment | |
57 * variable or by pthread_mutex_setyieldloops_np(). | |
58 * Solaris: No PTHREAD_MUTEX_ADAPTIVE_NP. | |
59 * MacOSX: No PTHREAD_MUTEX_ADAPTIVE_NP. | |
60 * | |
61 * | |
62 * PTHREAD_MUTEX_ELISION_NP is a Linux extension to elide locks using | |
63 * Intel Restricted Transactional Memory. It is the most suitable for | |
64 * rwlock pattern access because it allows simultaneous reads without lock. | |
65 * Supported since glibc 2.18. | |
66 * | |
67 * | |
68 * PTHREAD_MUTEX_DEFAULT is default mutex type. | |
69 * | |
70 * Linux: PTHREAD_MUTEX_NORMAL. | |
71 * FreeBSD: PTHREAD_MUTEX_ERRORCHECK. | |
72 * Solaris: PTHREAD_MUTEX_NORMAL. | |
73 * MacOSX: PTHREAD_MUTEX_NORMAL. | |
74 */ | |
75 | |
76 | |
77 ngx_int_t | |
78 ngx_thread_mutex_create(ngx_thread_mutex_t *mtx, ngx_log_t *log) | |
79 { | |
80 ngx_err_t err; | |
81 pthread_mutexattr_t attr; | |
82 | |
83 err = pthread_mutexattr_init(&attr); | |
84 if (err != 0) { | |
85 ngx_log_error(NGX_LOG_EMERG, log, err, | |
86 "pthread_mutexattr_init() failed"); | |
87 return NGX_ERROR; | |
88 } | |
89 | |
90 err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); | |
91 if (err != 0) { | |
92 ngx_log_error(NGX_LOG_EMERG, log, err, | |
93 "pthread_mutexattr_settype" | |
94 "(PTHREAD_MUTEX_ERRORCHECK) failed"); | |
95 return NGX_ERROR; | |
96 } | |
97 | |
98 err = pthread_mutex_init(mtx, &attr); | |
99 if (err != 0) { | |
100 ngx_log_error(NGX_LOG_EMERG, log, err, | |
101 "pthread_mutex_init() failed"); | |
102 return NGX_ERROR; | |
103 } | |
104 | |
105 err = pthread_mutexattr_destroy(&attr); | |
106 if (err != 0) { | |
107 ngx_log_error(NGX_LOG_ALERT, log, err, | |
108 "pthread_mutexattr_destroy() failed"); | |
109 } | |
110 | |
111 ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, | |
112 "pthread_mutex_init(%p)", mtx); | |
113 return NGX_OK; | |
114 } | |
115 | |
116 | |
117 ngx_int_t | |
118 ngx_thread_mutex_destroy(ngx_thread_mutex_t *mtx, ngx_log_t *log) | |
119 { | |
120 ngx_err_t err; | |
121 | |
122 err = pthread_mutex_destroy(mtx); | |
123 if (err != 0) { | |
124 ngx_log_error(NGX_LOG_ALERT, log, err, | |
125 "pthread_mutex_destroy() failed"); | |
126 return NGX_ERROR; | |
127 } | |
128 | |
129 ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, | |
130 "pthread_mutex_destroy(%p)", mtx); | |
131 return NGX_OK; | |
132 } | |
133 | |
134 | |
135 ngx_int_t | |
136 ngx_thread_mutex_lock(ngx_thread_mutex_t *mtx, ngx_log_t *log) | |
137 { | |
138 ngx_err_t err; | |
139 | |
140 ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, | |
141 "pthread_mutex_lock(%p) enter", mtx); | |
142 | |
143 err = pthread_mutex_lock(mtx); | |
144 if (err == 0) { | |
145 return NGX_OK; | |
146 } | |
147 | |
148 ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_mutex_lock() failed"); | |
149 | |
150 return NGX_ERROR; | |
151 } | |
152 | |
153 | |
154 ngx_int_t | |
155 ngx_thread_mutex_unlock(ngx_thread_mutex_t *mtx, ngx_log_t *log) | |
156 { | |
157 ngx_err_t err; | |
158 | |
159 err = pthread_mutex_unlock(mtx); | |
160 | |
161 #if 0 | |
162 ngx_time_update(); | |
163 #endif | |
164 | |
165 if (err == 0) { | |
166 ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, | |
167 "pthread_mutex_unlock(%p) exit", mtx); | |
168 return NGX_OK; | |
169 } | |
170 | |
171 ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_mutex_unlock() failed"); | |
172 | |
173 return NGX_ERROR; | |
174 } |