Bug Summary

File:thread/rwlock.c
Warning:line 405, column 9
Value stored to 'busy' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name rwlock.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/isvv/naviserver/nsthread -resource-dir /usr/local/lib/clang/15.0.0 -D _FORTIFY_SOURCE=2 -D NDEBUG -D SYSTEM_MALLOC -I ../include -I /usr/include/tcl8.6 -D HAVE_CONFIG_H -internal-isystem /usr/local/lib/clang/15.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/11/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -std=c99 -fdebug-compilation-dir=/home/isvv/naviserver/nsthread -ferror-limit 19 -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker alpha -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-07-23-130959-11103-1 -x c rwlock.c
1/*
2 * The contents of this file are subject to the Mozilla Public License
3 * Version 1.1 (the "License"); you may not use this file except in
4 * compliance with the License. You may obtain a copy of the License at
5 * http://mozilla.org/.
6 *
7 * Software distributed under the License is distributed on an "AS IS"
8 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9 * the License for the specific language governing rights and limitations
10 * under the License.
11 *
12 * The Original Code is AOLserver Code and related documentation
13 * distributed by AOL.
14 *
15 * The Initial Developer of the Original Code is America Online,
16 * Inc. Portions created by AOL are Copyright (C) 1999 America Online,
17 * Inc. All Rights Reserved.
18 *
19 * Alternatively, the contents of this file may be used under the terms
20 * of the GNU General Public License (the "GPL"), in which case the
21 * provisions of GPL are applicable instead of those above. If you wish
22 * to allow use of your version of this file only under the terms of the
23 * GPL and not to allow others to use your version of this file under the
24 * License, indicate your decision by deleting the provisions above and
25 * replace them with the notice and other provisions required by the GPL.
26 * If you do not delete the provisions above, a recipient may use your
27 * version of this file under either the License or the GPL.
28 */
29
30/*
31 * rwlock.c --
32 *
33 * Routines for read/write locks. Read/write locks differ from a mutex
34 * in that multiple threads can acquire the read lock until a single
35 * thread acquires a write lock. This code is adapted from that in
36 * Steven's Unix Network Programming, Volume 3.
37 *
38 * Note: Read/write locks are not often a good idea. The reason
39 * is, like critical sections, the number of actual lock operations
40 * is doubled which makes them more expensive to use. Cases where the
41 * overhead are justified are then often subject to read locks being
42 * held longer than writer threads can wait and/or writer threads holding
43 * the lock so long that many reader threads back up. In these cases,
44 * specific reference counting techniques (e.g., the management of
45 * the Req structures in op.c) normally work better.
46 */
47
48#include "thread.h"
49
50/*
51 * This file contains two different implementations of read/write locks:
52 *
53 * a) a POSIX pthread based implementation (when HAVE_PTHREAD is defined)
54 * b) a "hand-written implementation based on a mutex and condition variables,
55 * which is defined since ages in NaviServer.
56 *
57 * Variant (b) is used typically on WINDOWS, unless one integrtion the windows
58 * pthread library.
59 *
60 */
61
62
63#ifdef HAVE_PTHREAD1
64
65/* ----------------------------------------------------------------------
66 * POSIX rwlock
67 *----------------------------------------------------------------------
68 */
69#include <pthread.h>
70
71/*
72 * Use MUTEX_TIMING to activate/deactivate timing statistics from locks. for
73 * RWLOCKS, we measure just the write locks, which also guarantee exclusive
74 * access. The name MUTEX_TIMING is kept as it used as well in mutex.c.
75 */
76//#define NS_NO_MUTEX_TIMING 1
77
78/*
79 * The following structure defines a read/write lock including a mutex
80 * to protect access to the structure and condition variables for waiting
81 * reader and writer threads.
82 */
83
84typedef struct RwLock {
85 pthread_rwlock_t rwlock;
86 unsigned long nlock;
87 unsigned long nrlock;
88 unsigned long nwlock;
89 unsigned long nbusy;
90 struct RwLock *nextPtr;
91 uintptr_t id;
92 Ns_Time start_time;
93 Ns_Time total_waiting_time;
94 Ns_Time max_waiting_time;
95 Ns_Time total_lock_time;
96 NS_RW rw;
97 char name[NS_THREAD_NAMESIZE64+1];
98} RwLock;
99
100static RwLock *GetRwLock(Ns_RWLock *rwPtr)
101 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_RETURNS_NONNULL;
102
103
104static RwLock *firstRwlockPtr = NULL((void*)0);
105
106/*
107 *----------------------------------------------------------------------
108 *
109 * Ns_RWLockList --
110 *
111 * Append info on each lock to Tcl_DString.
112 *
113 * Results:
114 * None.
115 *
116 * Side effects:
117 * None.
118 *
119 *----------------------------------------------------------------------
120 */
121
122void
123Ns_RWLockList(Tcl_DString *dsPtr)
124{
125 RwLock *rwlockPtr;
126 char buf[200];
127
128 Ns_MasterLock();
129 for (rwlockPtr = firstRwlockPtr; rwlockPtr != NULL((void*)0); rwlockPtr = rwlockPtr->nextPtr) {
130 Tcl_DStringStartSublist(dsPtr);
131 Tcl_DStringAppendElement(dsPtr, rwlockPtr->name);
132 Tcl_DStringAppendElement(dsPtr, ""); /* unused? */
133#ifndef NS_NO_MUTEX_TIMING
134 snprintf(buf, (int)sizeof(buf),__builtin___snprintf_chk (buf, (int)sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), " %" "l" "u" " %lu %lu " "%" "l" "d" ".%06ld"
" " "%" "l" "d" ".%06ld" " " "%" "l" "d" ".%06ld" " %lu %lu"
, rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy
, (int64_t)rwlockPtr->total_waiting_time.sec, rwlockPtr->
total_waiting_time.usec, (int64_t)rwlockPtr->max_waiting_time
.sec, rwlockPtr->max_waiting_time.usec, (int64_t)rwlockPtr
->total_lock_time.sec, rwlockPtr->total_lock_time.usec,
rwlockPtr->nrlock, rwlockPtr->nwlock)
135 " %" PRIuPTR " %lu %lu " NS_TIME_FMT " " NS_TIME_FMT " " NS_TIME_FMT__builtin___snprintf_chk (buf, (int)sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), " %" "l" "u" " %lu %lu " "%" "l" "d" ".%06ld"
" " "%" "l" "d" ".%06ld" " " "%" "l" "d" ".%06ld" " %lu %lu"
, rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy
, (int64_t)rwlockPtr->total_waiting_time.sec, rwlockPtr->
total_waiting_time.usec, (int64_t)rwlockPtr->max_waiting_time
.sec, rwlockPtr->max_waiting_time.usec, (int64_t)rwlockPtr
->total_lock_time.sec, rwlockPtr->total_lock_time.usec,
rwlockPtr->nrlock, rwlockPtr->nwlock)
136 " %lu %lu" ,__builtin___snprintf_chk (buf, (int)sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), " %" "l" "u" " %lu %lu " "%" "l" "d" ".%06ld"
" " "%" "l" "d" ".%06ld" " " "%" "l" "d" ".%06ld" " %lu %lu"
, rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy
, (int64_t)rwlockPtr->total_waiting_time.sec, rwlockPtr->
total_waiting_time.usec, (int64_t)rwlockPtr->max_waiting_time
.sec, rwlockPtr->max_waiting_time.usec, (int64_t)rwlockPtr
->total_lock_time.sec, rwlockPtr->total_lock_time.usec,
rwlockPtr->nrlock, rwlockPtr->nwlock)
137 rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy,__builtin___snprintf_chk (buf, (int)sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), " %" "l" "u" " %lu %lu " "%" "l" "d" ".%06ld"
" " "%" "l" "d" ".%06ld" " " "%" "l" "d" ".%06ld" " %lu %lu"
, rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy
, (int64_t)rwlockPtr->total_waiting_time.sec, rwlockPtr->
total_waiting_time.usec, (int64_t)rwlockPtr->max_waiting_time
.sec, rwlockPtr->max_waiting_time.usec, (int64_t)rwlockPtr
->total_lock_time.sec, rwlockPtr->total_lock_time.usec,
rwlockPtr->nrlock, rwlockPtr->nwlock)
138 (int64_t)rwlockPtr->total_waiting_time.sec, rwlockPtr->total_waiting_time.usec,__builtin___snprintf_chk (buf, (int)sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), " %" "l" "u" " %lu %lu " "%" "l" "d" ".%06ld"
" " "%" "l" "d" ".%06ld" " " "%" "l" "d" ".%06ld" " %lu %lu"
, rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy
, (int64_t)rwlockPtr->total_waiting_time.sec, rwlockPtr->
total_waiting_time.usec, (int64_t)rwlockPtr->max_waiting_time
.sec, rwlockPtr->max_waiting_time.usec, (int64_t)rwlockPtr
->total_lock_time.sec, rwlockPtr->total_lock_time.usec,
rwlockPtr->nrlock, rwlockPtr->nwlock)
139 (int64_t)rwlockPtr->max_waiting_time.sec, rwlockPtr->max_waiting_time.usec,__builtin___snprintf_chk (buf, (int)sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), " %" "l" "u" " %lu %lu " "%" "l" "d" ".%06ld"
" " "%" "l" "d" ".%06ld" " " "%" "l" "d" ".%06ld" " %lu %lu"
, rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy
, (int64_t)rwlockPtr->total_waiting_time.sec, rwlockPtr->
total_waiting_time.usec, (int64_t)rwlockPtr->max_waiting_time
.sec, rwlockPtr->max_waiting_time.usec, (int64_t)rwlockPtr
->total_lock_time.sec, rwlockPtr->total_lock_time.usec,
rwlockPtr->nrlock, rwlockPtr->nwlock)
140 (int64_t)rwlockPtr->total_lock_time.sec, rwlockPtr->total_lock_time.usec,__builtin___snprintf_chk (buf, (int)sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), " %" "l" "u" " %lu %lu " "%" "l" "d" ".%06ld"
" " "%" "l" "d" ".%06ld" " " "%" "l" "d" ".%06ld" " %lu %lu"
, rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy
, (int64_t)rwlockPtr->total_waiting_time.sec, rwlockPtr->
total_waiting_time.usec, (int64_t)rwlockPtr->max_waiting_time
.sec, rwlockPtr->max_waiting_time.usec, (int64_t)rwlockPtr
->total_lock_time.sec, rwlockPtr->total_lock_time.usec,
rwlockPtr->nrlock, rwlockPtr->nwlock)
141 rwlockPtr->nrlock, rwlockPtr->nwlock)__builtin___snprintf_chk (buf, (int)sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), " %" "l" "u" " %lu %lu " "%" "l" "d" ".%06ld"
" " "%" "l" "d" ".%06ld" " " "%" "l" "d" ".%06ld" " %lu %lu"
, rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy
, (int64_t)rwlockPtr->total_waiting_time.sec, rwlockPtr->
total_waiting_time.usec, (int64_t)rwlockPtr->max_waiting_time
.sec, rwlockPtr->max_waiting_time.usec, (int64_t)rwlockPtr
->total_lock_time.sec, rwlockPtr->total_lock_time.usec,
rwlockPtr->nrlock, rwlockPtr->nwlock)
;
142#else
143 snprintf(buf, (int)sizeof(buf),__builtin___snprintf_chk (buf, (int)sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), " %" "l" "u" " %lu %lu " "%" "l" "d" ".%06ld"
" " "%" "l" "d" ".%06ld" " " "%" "l" "d" ".%06ld" " %lu %lu"
, rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy
, (int64_t)0, (long)0, (int64_t)0, (long)0, (int64_t)0, (long
)0, rwlockPtr->nrlock, rwlockPtr->nwlock)
144 " %" PRIuPTR " %lu %lu " NS_TIME_FMT " " NS_TIME_FMT " " NS_TIME_FMT__builtin___snprintf_chk (buf, (int)sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), " %" "l" "u" " %lu %lu " "%" "l" "d" ".%06ld"
" " "%" "l" "d" ".%06ld" " " "%" "l" "d" ".%06ld" " %lu %lu"
, rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy
, (int64_t)0, (long)0, (int64_t)0, (long)0, (int64_t)0, (long
)0, rwlockPtr->nrlock, rwlockPtr->nwlock)
145 " %lu %lu" ,__builtin___snprintf_chk (buf, (int)sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), " %" "l" "u" " %lu %lu " "%" "l" "d" ".%06ld"
" " "%" "l" "d" ".%06ld" " " "%" "l" "d" ".%06ld" " %lu %lu"
, rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy
, (int64_t)0, (long)0, (int64_t)0, (long)0, (int64_t)0, (long
)0, rwlockPtr->nrlock, rwlockPtr->nwlock)
146 rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy,__builtin___snprintf_chk (buf, (int)sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), " %" "l" "u" " %lu %lu " "%" "l" "d" ".%06ld"
" " "%" "l" "d" ".%06ld" " " "%" "l" "d" ".%06ld" " %lu %lu"
, rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy
, (int64_t)0, (long)0, (int64_t)0, (long)0, (int64_t)0, (long
)0, rwlockPtr->nrlock, rwlockPtr->nwlock)
147 (int64_t)0, (long)0,__builtin___snprintf_chk (buf, (int)sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), " %" "l" "u" " %lu %lu " "%" "l" "d" ".%06ld"
" " "%" "l" "d" ".%06ld" " " "%" "l" "d" ".%06ld" " %lu %lu"
, rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy
, (int64_t)0, (long)0, (int64_t)0, (long)0, (int64_t)0, (long
)0, rwlockPtr->nrlock, rwlockPtr->nwlock)
148 (int64_t)0, (long)0,__builtin___snprintf_chk (buf, (int)sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), " %" "l" "u" " %lu %lu " "%" "l" "d" ".%06ld"
" " "%" "l" "d" ".%06ld" " " "%" "l" "d" ".%06ld" " %lu %lu"
, rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy
, (int64_t)0, (long)0, (int64_t)0, (long)0, (int64_t)0, (long
)0, rwlockPtr->nrlock, rwlockPtr->nwlock)
149 (int64_t)0, (long)0,__builtin___snprintf_chk (buf, (int)sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), " %" "l" "u" " %lu %lu " "%" "l" "d" ".%06ld"
" " "%" "l" "d" ".%06ld" " " "%" "l" "d" ".%06ld" " %lu %lu"
, rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy
, (int64_t)0, (long)0, (int64_t)0, (long)0, (int64_t)0, (long
)0, rwlockPtr->nrlock, rwlockPtr->nwlock)
150 rwlockPtr->nrlock, rwlockPtr->nwlock)__builtin___snprintf_chk (buf, (int)sizeof(buf), 2 - 1, __builtin_object_size
(buf, 2 > 1), " %" "l" "u" " %lu %lu " "%" "l" "d" ".%06ld"
" " "%" "l" "d" ".%06ld" " " "%" "l" "d" ".%06ld" " %lu %lu"
, rwlockPtr->id, rwlockPtr->nlock, rwlockPtr->nbusy
, (int64_t)0, (long)0, (int64_t)0, (long)0, (int64_t)0, (long
)0, rwlockPtr->nrlock, rwlockPtr->nwlock)
;
151#endif
152 Tcl_DStringAppend(dsPtr, buf, -1);
153 Tcl_DStringEndSublist(dsPtr);
154 }
155 Ns_MasterUnlock();
156}
157
158
159
160
161
162/*
163 *----------------------------------------------------------------------
164 *
165 * Ns_RWLockInit --
166 *
167 * Initialize a read/write lock.
168 *
169 * Results:
170 * None.
171 *
172 * Side effects:
173 * Lock memory is allocated from the heap and initialized.
174 *
175 *----------------------------------------------------------------------
176 */
177
178void
179Ns_RWLockInit(Ns_RWLock *rwPtr)
180{
181 RwLock *lockPtr;
182 static uintptr_t nextid = 0;
183
184 NS_NONNULL_ASSERT(rwPtr != NULL)((void) (0));
185
186 lockPtr = ns_calloc(1u, sizeof(RwLock));
187
188 Ns_MasterLock();
189 lockPtr->nextPtr = firstRwlockPtr;
190 firstRwlockPtr = lockPtr;
191 lockPtr->id = nextid++;
192 lockPtr->name[0] = 'r';
193 lockPtr->name[1] = 'w';
194 (void) ns_uint64toa(&lockPtr->name[2], (uint64_t)lockPtr->id);
195 Ns_MasterUnlock();
196
197 lockPtr->rw = NS_READ;
198 {
199 int err;
200#if (defined(_XOPEN_SOURCE700) && _XOPEN_SOURCE700 >= 500) || (defined(_POSIX_C_SOURCE200809L) && _POSIX_C_SOURCE200809L >= 200809L)
201 pthread_rwlockattr_t attr;
202 pthread_rwlockattr_setkind_np(&attr,
203 PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
204 err = pthread_rwlock_init(&lockPtr->rwlock, &attr);
205#else
206 err = pthread_rwlock_init(&lockPtr->rwlock, NULL((void*)0));
207#endif
208 if (err != 0) {
209 NsThreadFatal("Ns_RWLockInit", "pthread_rwlock_init", err);
210 }
211 }
212 *rwPtr = (Ns_RWLock) lockPtr;
213}
214
215/*
216 *----------------------------------------------------------------------
217 *
218 * Ns_RWLockSetName2 --
219 *
220 * Update the string name of a rwlock. Ns_RWLockSetName2 uses
221 * Ns_MutexSetName2 to set a name based on the two string components and
222 * concatenates these with a colon (":").
223 *
224 * Results:
225 * None.
226 *
227 * Side effects:
228 * None.
229 *
230 *----------------------------------------------------------------------
231 */
232
233void
234Ns_RWLockSetName2(Ns_RWLock *rwPtr, const char *prefix, const char *name)
235{
236 RwLock *lockPtr;
237 size_t prefixLength, nameLength;
238 char *p;
239
240 NS_NONNULL_ASSERT(rwPtr != NULL)((void) (0));
241 NS_NONNULL_ASSERT(prefix != NULL)((void) (0));
242
243 prefixLength = strlen(prefix);
244 if (prefixLength > NS_THREAD_NAMESIZE64 - 1) {
245 prefixLength = NS_THREAD_NAMESIZE64 - 1;
246 nameLength = 0u;
247 } else if (name != NULL((void*)0)) {
248 nameLength = strlen(name);
249 if ((nameLength + prefixLength + 1) > NS_THREAD_NAMESIZE64) {
250 nameLength = NS_THREAD_NAMESIZE64 - prefixLength - 1;
251 }
252 } else {
253 nameLength = 0u;
254 }
255
256 lockPtr = GetRwLock(rwPtr);
257
258 Ns_MasterLock();
259 p = lockPtr->name;
260 memcpy(p, prefix, prefixLength + 1u);
261 if (name != NULL((void*)0)) {
262 p += prefixLength;
263 *p++ = ':';
264 assert(name != NULL)((void) (0));
265 memcpy(p, name, nameLength + 1u);
266 }
267 Ns_MasterUnlock();
268}
269
270
271/*
272 *----------------------------------------------------------------------
273 *
274 * Ns_RWLockDestroy --
275 *
276 * Destroy a read/write lock if it was previously initialized.
277 *
278 * Results:
279 * None.
280 *
281 * Side effects:
282 * Read/write lock objects are destroy and the lock memory is
283 * returned to the heap.
284 *
285 *----------------------------------------------------------------------
286 */
287
288void
289Ns_RWLockDestroy(Ns_RWLock *rwPtr)
290{
291 RwLock *lockPtr = (RwLock *) *rwPtr;
292
293 if (lockPtr != NULL((void*)0)) {
294 RwLock **rwlockPtrPtr;
295 int err = pthread_rwlock_destroy(&lockPtr->rwlock);
296
297 if (unlikely(err != 0)(__builtin_expect((err != 0), 0))) {
298 NsThreadFatal("Ns_RWLockDestroy", "pthread_rwlock_destroy", err);
299 }
300 /*
301 * Remove lock from linked list of rwlocks.
302 */
303 Ns_MasterLock();
304 rwlockPtrPtr = &firstRwlockPtr;
305 while ((*rwlockPtrPtr) != lockPtr) {
306 rwlockPtrPtr = &(*rwlockPtrPtr)->nextPtr;
307 }
308 *rwlockPtrPtr = lockPtr->nextPtr;
309 Ns_MasterUnlock();
310
311 *rwPtr = NULL((void*)0);
312 }
313}
314
315
316/*
317 *----------------------------------------------------------------------
318 *
319 * Ns_RWLockRdLock --
320 *
321 * Acquire a read lock.
322 *
323 * Results:
324 * None.
325 *
326 * Side effects:
327 * Thread may wait on a condition variable if the read/write lock
328 * currently has a write lock.
329 *
330 *----------------------------------------------------------------------
331 */
332
333void
334Ns_RWLockRdLock(Ns_RWLock *rwPtr)
335{
336 RwLock *lockPtr;
337 int err;
338 bool_Bool busy;
339
340 NS_NONNULL_ASSERT(rwPtr != NULL)((void) (0));
341
342 lockPtr = GetRwLock(rwPtr);
343
344 err = pthread_rwlock_tryrdlock(&lockPtr->rwlock);
345 if (unlikely(err == EBUSY)(__builtin_expect((err == 16), 0))) {
346 busy = NS_TRUE1;
347 } else if (unlikely(err != 0)(__builtin_expect((err != 0), 0))) {
348 busy = NS_FALSE0;
349 NsThreadFatal("Ns_RWLockRdLock", "pthread_rwlock_tryrdlock", err);
350 } else {
351 busy = NS_FALSE0;
352 }
353
354 if (busy) {
355 err = pthread_rwlock_rdlock(&lockPtr->rwlock);
356 if (err != 0) {
357 NsThreadFatal("Ns_RWLockRdLock", "pthread_rwlock_rdlock", err);
358 }
359 lockPtr->nbusy++;
360 }
361 lockPtr->nlock++;
362 lockPtr->nrlock++;
363}
364
365
366/*
367 *----------------------------------------------------------------------
368 *
369 * Ns_RWLockWrLock --
370 *
371 * Acquire a write lock.
372 *
373 * Results:
374 * None.
375 *
376 * Side effects:
377 * Thread may wait on the write condition if other threads either
378 * have the lock read or write locked.
379 *
380 *----------------------------------------------------------------------
381 */
382
383void
384Ns_RWLockWrLock(Ns_RWLock *rwPtr)
385{
386 RwLock *lockPtr;
387 int err;
388 bool_Bool busy;
389#ifndef NS_NO_MUTEX_TIMING
390 Ns_Time end, diff, startTime;
391#endif
392
393 NS_NONNULL_ASSERT(rwPtr != NULL)((void) (0));
394
395 lockPtr = GetRwLock(rwPtr);
396
397#ifndef NS_NO_MUTEX_TIMING
398 Ns_GetTime(&startTime);
399#endif
400
401 err = pthread_rwlock_trywrlock(&lockPtr->rwlock);
402 if (unlikely(err == EBUSY)(__builtin_expect((err == 16), 0))) {
403 busy = NS_TRUE1;
404 } else if (unlikely(err != 0)(__builtin_expect((err != 0), 0))) {
405 busy = NS_FALSE0;
Value stored to 'busy' is never read
406 NsThreadFatal("Ns_RWLockWrLock", "pthread_rwlock_trywrlock", err);
407 } else {
408 busy = NS_FALSE0;
409 }
410
411 if (busy) {
412 err = pthread_rwlock_wrlock(&lockPtr->rwlock);
413 if (err != 0) {
414 NsThreadFatal("Ns_RWLockWrLock", "pthread_rwlock_wrlock", err);
415 }
416 lockPtr->nbusy ++;
417
418#ifndef NS_NO_MUTEX_TIMING
419 /*
420 * Measure total and max waiting time for busy rwlock locks.
421 */
422 Ns_GetTime(&end);
423 Ns_DiffTime(&end, &startTime, &diff);
424 Ns_IncrTime(&lockPtr->total_waiting_time, diff.sec, diff.usec);
425#endif
426 }
427#ifndef NS_NO_MUTEX_TIMING
428 lockPtr->rw = NS_WRITE;
429 lockPtr->start_time = startTime;
430#endif
431 lockPtr->nlock ++;
432 lockPtr->nwlock++;
433}
434
435
436/*
437 *----------------------------------------------------------------------
438 *
439 * Ns_RWLockUnlock --
440 *
441 * Unlock a read/write lock.
442 *
443 * Results:
444 * None.
445 *
446 * Side effects:
447 * Read or write condition may be signaled.
448 *
449 *----------------------------------------------------------------------
450 */
451
452void
453Ns_RWLockUnlock(Ns_RWLock *rwPtr)
454{
455 RwLock *lockPtr = (RwLock *) *rwPtr;
456 int err;
457
458#ifndef NS_NO_MUTEX_TIMING
459 /*
460 * Measure block times etc only in writer case, which guarantees exclusive
461 * access and blocking).
462 */
463 if (lockPtr->rw == NS_WRITE) {
464 Ns_Time end, diff;
465
466 lockPtr->rw = NS_READ;
467 Ns_GetTime(&end);
468 Ns_DiffTime(&end, &lockPtr->start_time, &diff);
469 Ns_IncrTime(&lockPtr->total_lock_time, diff.sec, diff.usec);
470 }
471#endif
472
473 err = pthread_rwlock_unlock(&lockPtr->rwlock);
474 if (err != 0) {
475 NsThreadFatal("Ns_RWLockUnlock", "pthread_rwlock_unlock", err);
476 }
477}
478
479
480/*
481 *----------------------------------------------------------------------
482 *
483 * GetRwLock --
484 *
485 * Return the read/write lock structure, initializing it if needed.
486 *
487 * Results:
488 * Pointer to lock.
489 *
490 * Side effects:
491 * Lock may be initialized.
492 *
493 *----------------------------------------------------------------------
494 */
495
496static RwLock *
497GetRwLock(Ns_RWLock *rwPtr)
498{
499 NS_NONNULL_ASSERT(rwPtr != NULL)((void) (0));
500
501 if (*rwPtr == NULL((void*)0)) {
502 Ns_MasterLock();
503 if (*rwPtr == NULL((void*)0)) {
504 Ns_RWLockInit(rwPtr);
505 }
506 Ns_MasterUnlock();
507 }
508 return (RwLock *) *rwPtr;
509}
510
511#else /* NOT HAVE_PTHREAD */
512
513/*
514 * The following structure defines a read/write lock including a mutex
515 * to protect access to the structure and condition variables for waiting
516 * reader and writer threads.
517 */
518
519typedef struct RwLock {
520 Ns_Mutex mutex; /* Mutex guarding lock structure. */
521 Ns_Cond rcond; /* Condition variable for waiting readers. */
522 Ns_Cond wcond; /* condition variable for waiting writers. */
523 int nreaders; /* Number of readers waiting for lock. */
524 int nwriters; /* Number of writers waiting for lock. */
525 int lockcnt; /* Lock count, > 0 indicates # of shared
526 * readers, -1 indicates exclusive writer. */
527} RwLock;
528
529static RwLock *GetRwLock(Ns_RWLock *rwPtr)
530 NS_GNUC_NONNULL(1)__attribute__((__nonnull__(1))) NS_GNUC_RETURNS_NONNULL;
531
532
533/*
534 *----------------------------------------------------------------------
535 *
536 * Ns_RWLockList --
537 *
538 * Append info on each lock to Tcl_DString. Since the rwlock emulation is
539 * based on mutexes, the information on these locks is included in
540 * Ns_MutexList().
541 *
542 * Results:
543 * None.
544 *
545 * Side effects:
546 * None.
547 *
548 *----------------------------------------------------------------------
549 */
550void
551Ns_RWLockList(Tcl_DString *UNUSED(dsPtr)UNUSED_dsPtr __attribute__((__unused__)))
552{
553}
554
555
556/*
557 *----------------------------------------------------------------------
558 *
559 * Ns_RWLockInit --
560 *
561 * Initialize a read/write lock.
562 *
563 * Results:
564 * None.
565 *
566 * Side effects:
567 * Lock memory is allocated from the heap and initialized.
568 *
569 *----------------------------------------------------------------------
570 */
571
572void
573Ns_RWLockInit(Ns_RWLock *rwPtr)
574{
575 RwLock *lockPtr;
576 static uintptr_t nextid = 0;
577
578 NS_NONNULL_ASSERT(rwPtr != NULL)((void) (0));
579
580 lockPtr = ns_calloc(1u, sizeof(RwLock));
581 NsMutexInitNext(&lockPtr->mutex, "rw", &nextid);
582 Ns_CondInit(&lockPtr->rcond);
583 Ns_CondInit(&lockPtr->wcond);
584 lockPtr->nreaders = 0;
585 lockPtr->nwriters = 0;
586 lockPtr->lockcnt = 0;
587 *rwPtr = (Ns_RWLock) lockPtr;
588}
589
590/*
591 *----------------------------------------------------------------------
592 *
593 * Ns_RWLockSetName2 --
594 *
595 * Update the string name of a mutex. Ns_RWLockSetName2 uses
596 * Ns_MutexSetName2 to set a name based on the two string components and
597 * concatenates these with a colon (":").
598 *
599 * Results:
600 * None.
601 *
602 * Side effects:
603 * None.
604 *
605 *----------------------------------------------------------------------
606 */
607
608void
609Ns_RWLockSetName2(Ns_RWLock *rwPtr, const char *prefix, const char *name)
610{
611 RwLock *lockPtr = (RwLock *)*rwPtr;
612
613 Ns_MutexSetName2(&lockPtr->mutex, prefix, name);
614
615}
616
617
618
619/*
620 *----------------------------------------------------------------------
621 *
622 * Ns_RWLockDestroy --
623 *
624 * Destroy a read/write lock if it was previously initialized.
625 *
626 * Results:
627 * None.
628 *
629 * Side effects:
630 * Read/write lock objects are destroy and the lock memory is
631 * returned to the heap.
632 *
633 *----------------------------------------------------------------------
634 */
635
636void
637Ns_RWLockDestroy(Ns_RWLock *rwPtr)
638{
639 RwLock *lockPtr = (RwLock *) *rwPtr;
640
641 if (lockPtr != NULL((void*)0)) {
642 Ns_MutexDestroy(&lockPtr->mutex);
643 Ns_CondDestroy(&lockPtr->rcond);
644 Ns_CondDestroy(&lockPtr->wcond);
645 ns_free(lockPtr);
646 *rwPtr = NULL((void*)0);
647 }
648}
649
650
651/*
652 *----------------------------------------------------------------------
653 *
654 * Ns_RWLockRdLock --
655 *
656 * Acquire a read lock.
657 *
658 * Results:
659 * None.
660 *
661 * Side effects:
662 * Thread may wait on a condition variable if the read/write lock
663 * currently has a write lock.
664 *
665 *----------------------------------------------------------------------
666 */
667
668void
669Ns_RWLockRdLock(Ns_RWLock *rwPtr)
670{
671 RwLock *lockPtr;
672
673 NS_NONNULL_ASSERT(rwPtr != NULL)((void) (0));
674
675 lockPtr = GetRwLock(rwPtr);
676 Ns_MutexLock(&lockPtr->mutex);
677
678 /*
679 * Wait on the read condition while the lock is write-locked or
680 * some other thread is waiting for a write lock.
681 */
682
683 while (lockPtr->lockcnt < 0 || lockPtr->nwriters > 0) {
684 lockPtr->nreaders++;
685 Ns_CondWait(&lockPtr->rcond, &lockPtr->mutex);
686 lockPtr->nreaders--;
687 }
688
689 lockPtr->lockcnt++;
690 Ns_MutexUnlock(&lockPtr->mutex);
691}
692
693
694/*
695 *----------------------------------------------------------------------
696 *
697 * Ns_RWLockWrLock --
698 *
699 * Acquire a write lock.
700 *
701 * Results:
702 * None.
703 *
704 * Side effects:
705 * Thread may wait on the write condition if other threads either
706 * have the lock read or write locked.
707 *
708 *----------------------------------------------------------------------
709 */
710
711void
712Ns_RWLockWrLock(Ns_RWLock *rwPtr)
713{
714 RwLock *lockPtr;
715
716 NS_NONNULL_ASSERT(rwPtr != NULL)((void) (0));
717
718 lockPtr = GetRwLock(rwPtr);
719
720 Ns_MutexLock(&lockPtr->mutex);
721 while (lockPtr->lockcnt != 0) {
722 lockPtr->nwriters++;
723 Ns_CondWait(&lockPtr->wcond, &lockPtr->mutex);
724 lockPtr->nwriters--;
725 }
726 lockPtr->lockcnt = -1;
727 Ns_MutexUnlock(&lockPtr->mutex);
728}
729
730
731/*
732 *----------------------------------------------------------------------
733 *
734 * Ns_RWLockUnlock --
735 *
736 * Unlock a read/write lock.
737 *
738 * Results:
739 * None.
740 *
741 * Side effects:
742 * Read or write condition may be signaled.
743 *
744 *----------------------------------------------------------------------
745 */
746
747void
748Ns_RWLockUnlock(Ns_RWLock *rwPtr)
749{
750 RwLock *lockPtr;
751
752 NS_NONNULL_ASSERT(rwPtr != NULL)((void) (0));
753 lockPtr = (RwLock *) *rwPtr;
754
755 Ns_MutexLock(&lockPtr->mutex);
756 if (--lockPtr->lockcnt < 0) {
757 lockPtr->lockcnt = 0;
758 }
759 if (lockPtr->nwriters != 0) {
760 Ns_CondSignal(&lockPtr->wcond);
761 } else if (lockPtr->nreaders != 0) {
762 Ns_CondBroadcast(&lockPtr->rcond);
763 }
764 Ns_MutexUnlock (&lockPtr->mutex);
765}
766
767
768/*
769 *----------------------------------------------------------------------
770 *
771 * GetRwLock --
772 *
773 * Return the read/write lock structure, initializing it if needed.
774 *
775 * Results:
776 * Pointer to lock.
777 *
778 * Side effects:
779 * Lock may be initialized.
780 *
781 *----------------------------------------------------------------------
782 */
783
784static RwLock *
785GetRwLock(Ns_RWLock *rwPtr)
786{
787 NS_NONNULL_ASSERT(rwPtr != NULL)((void) (0));
788
789 if (*rwPtr == NULL((void*)0)) {
790 Ns_MasterLock();
791 if (*rwPtr == NULL((void*)0)) {
792 Ns_RWLockInit(rwPtr);
793 }
794 Ns_MasterUnlock();
795 }
796 return (RwLock *) *rwPtr;
797}
798
799#endif /* HAVE_PTHREAD */
800/*
801 * Local Variables:
802 * mode: c
803 * c-basic-offset: 4
804 * fill-column: 78
805 * indent-tabs-mode: nil
806 * End:
807 */