vinyl-cache/bin/vinyld/cache/cache_lck.c
0
/*-
1
 * Copyright (c) 2008-2011 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 * The geniuses who came up with pthreads did not think operations like
30
 * pthread_assert_mutex_held() were important enough to include them in
31
 * the API.
32
 *
33
 * Build our own locks on top of pthread mutexes and hope that the next
34
 * civilization is better at such crucial details than this one.
35
 */
36
37
#include "config.h"
38
39
#include "cache_int.h"
40
41
#include <stdlib.h>
42
#include <stdio.h>
43
44
#include "vtim.h"
45
46
#include "VSC_lck.h"
47
48
struct ilck {
49
        unsigned                magic;
50
#define ILCK_MAGIC              0x7b86c8a5
51
        int                     held;
52
        pthread_mutex_t         mtx;
53
        pthread_t               owner;
54
#ifdef ENABLE_WITNESS
55
        const char              *w;
56
#endif
57
        struct VSC_lck          *stat;
58
};
59
60
/*--------------------------------------------------------------------*/
61
62
#ifdef ENABLE_WITNESS
63
static void
64 9364
Lck_Witness_Lock(const struct ilck *il, const char *p, int l,
65
    const char *attempt)
66
{
67
        char *q, t[10]; //lint !e429
68
        int emit;
69
70 9364
        AN(p);
71 9364
        q = pthread_getspecific(witness_key);
72 9364
        if (q == NULL) {
73 1218
                q = calloc(1, 1024);
74 1218
                AN(q);
75 1218
                PTOK(pthread_setspecific(witness_key, q));
76 1218
        }
77 9364
        emit = *q != '\0';
78 9364
        strcat(q, " ");
79 9364
        strcat(q, il->w);
80 9364
        strcat(q, attempt);
81 9364
        strcat(q, ",");
82 9364
        strcat(q, p);
83 9364
        strcat(q, ",");
84 9364
        bprintf(t, "%d", l);
85 9364
        strcat(q, t);
86 9364
        if (emit)
87 592
                VSL(SLT_Witness, NO_VXID, "%s", q);
88 9364
}
89
90
static void
91 10278
Lck_Witness_Unlock(const struct ilck *il)
92
{
93
        char *q, *r;
94
95 10278
        q = pthread_getspecific(witness_key);
96 10278
        if (q == NULL)
97 924
                return;
98 9354
        r = strrchr(q, ' ');
99 9354
        if (r == NULL)
100 0
                r = q;
101
        else
102 9354
                *r++ = '\0';
103 9354
        if (vmemcmp(r, il->w, vstrlen(il->w)))
104 0
                VSL(SLT_Witness, NO_VXID, "Unlock %s @ %s <%s>", il->w, r, q);
105
        else
106 9354
                *r = '\0';
107 10278
}
108
#endif
109
110
/*--------------------------------------------------------------------*/
111
112
void v_matchproto_()
113 9722368
Lck__Lock(struct lock *lck, const char *p, int l)
114
{
115
        struct ilck *ilck;
116 9722368
        int r = EINVAL;
117
118 9722368
        AN(lck);
119 9722368
        CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
120
#ifdef ENABLE_WITNESS
121 9722368
        if (DO_DEBUG(DBG_WITNESS))
122 9141
                Lck_Witness_Lock(ilck, p, l, "");
123
#else
124
        (void)p;
125
        (void)l;
126
#endif
127 9722368
        if (DO_DEBUG(DBG_LCK)) {
128 0
                r = pthread_mutex_trylock(&ilck->mtx);
129 0
                assert(r == 0 || r == EBUSY);
130 0
        }
131 9722368
        if (r)
132 9721882
                PTOK(pthread_mutex_lock(&ilck->mtx));
133 9722368
        AZ(ilck->held);
134 9722368
        if (r == EBUSY)
135 0
                ilck->stat->dbg_busy++;
136 9722368
        ilck->stat->locks++;
137 9722368
        ilck->owner = pthread_self();
138 9722368
        ilck->held = 1;
139 9722368
}
140
141
void v_matchproto_()
142 10843311
Lck__Unlock(struct lock *lck, const char *p, int l)
143
{
144
        struct ilck *ilck;
145
146 10843311
        (void)p;
147 10843311
        (void)l;
148
149 10843311
        AN(lck);
150 10843311
        CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
151 10843311
        assert(pthread_equal(ilck->owner, pthread_self()));
152 10843311
        AN(ilck->held);
153 10843311
        ilck->held = 0;
154
        /*
155
         * #ifdef POSIX_STUPIDITY:
156
         * The pthread_t type has no defined assignment or comparison
157
         * operators, this is why pthread_equal() is necessary.
158
         * Unfortunately POSIX forgot to define a NULL value for pthread_t
159
         * so you can never unset a pthread_t variable.
160
         * We hack it and fill it with zero bits, hoping for sane
161
         * implementations of pthread.
162
         * #endif
163
         */
164
#ifdef PTHREAD_NULL
165
        ilck->owner = PTHREAD_NULL;
166
#else
167 10843311
        memset(&ilck->owner, 0, sizeof ilck->owner);
168
#endif
169 10843311
        PTOK(pthread_mutex_unlock(&ilck->mtx));
170
#ifdef ENABLE_WITNESS
171 10843311
        if (DO_DEBUG(DBG_WITNESS))
172 10272
                Lck_Witness_Unlock(ilck);
173
#endif
174 10843311
}
175
176
int v_matchproto_()
177 1152591
Lck__Trylock(struct lock *lck, const char *p, int l)
178
{
179
        struct ilck *ilck;
180
        int r;
181
182 1152591
        AN(lck);
183 1152591
        CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
184
#ifdef ENABLE_WITNESS
185 1152591
        if (DO_DEBUG(DBG_WITNESS))
186 216
                Lck_Witness_Lock(ilck, p, l, "?");
187
#else
188
        (void)p;
189
        (void)l;
190
#endif
191 1152591
        r = pthread_mutex_trylock(&ilck->mtx);
192 1152591
        assert(r == 0 || r == EBUSY);
193 1152591
        if (r == 0) {
194 1152587
                AZ(ilck->held);
195 1152587
                ilck->held = 1;
196 1152587
                ilck->stat->locks++;
197 1152587
                ilck->owner = pthread_self();
198 1152591
        } else if (DO_DEBUG(DBG_LCK))
199 0
                ilck->stat->dbg_try_fail++;
200 1152591
        return (r);
201
}
202
203
int
204 1667268
Lck__Held(const struct lock *lck)
205
{
206
        struct ilck *ilck;
207
208 1667268
        AN(lck);
209 1667268
        CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
210 1667268
        return (ilck->held);
211
}
212
213
int
214 1667321
Lck__Owned(const struct lock *lck)
215
{
216
        struct ilck *ilck;
217
218 1667321
        AN(lck);
219 1667321
        CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
220 1667321
        AN(ilck->held);
221 1667321
        return (pthread_equal(ilck->owner, pthread_self()));
222
}
223
224
int v_matchproto_()
225 617229
Lck_CondWait(pthread_cond_t *cond, struct lock *lck)
226
{
227 617229
       return (Lck_CondWaitUntil(cond, lck, INFINITY));
228
}
229
230
int v_matchproto_()
231 231105
Lck_CondWaitTimeout(pthread_cond_t *cond, struct lock *lck, vtim_dur timeout)
232
{
233
234 231105
        if (isinf(timeout))
235 0
                return (Lck_CondWaitUntil(cond, lck, INFINITY));
236
237 231105
        assert(timeout >= 0);
238 231105
        assert(timeout <= 3600);
239 231105
        timeout = vmax(timeout, 1e-3);
240 231105
        return (Lck_CondWaitUntil(cond, lck, VTIM_real() + timeout));
241 231105
}
242
243
int v_matchproto_()
244 1510264
Lck_CondWaitUntil(pthread_cond_t *cond, struct lock *lck, vtim_real when)
245
{
246
        struct ilck *ilck;
247
        struct timespec ts;
248
249 1510264
        AN(lck);
250 1510264
        CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
251 1510264
        AN(ilck->held);
252 1510264
        assert(pthread_equal(ilck->owner, pthread_self()));
253 1510264
        ilck->held = 0;
254 1510264
        if (isinf(when)) {
255 1142822
                errno = pthread_cond_wait(cond, &ilck->mtx);
256 1142822
                AZ(errno);
257 1142822
        } else {
258 367442
                assert(when > 1e9);
259 367442
                ts = VTIM_timespec(when);
260 367442
                assert(ts.tv_nsec >= 0 && ts.tv_nsec <= 999999999);
261 367442
                errno = pthread_cond_timedwait(cond, &ilck->mtx, &ts);
262
#if defined (__APPLE__)
263
                /*
264
                 * I hate woo-doo programming in all it's forms and all it's
265
                 * manifestations, but for reasons I utterly fail to isolate,
266
                 * OSX sometimes throws an EINVAL.
267
                 *
268
                 * I have tried very hard to determine if any of the three
269
                 * arguments are in fact invalid, and found nothing which
270
                 * even hints that it might be the case.
271
                 *
272
                 * So far I have yet to see a failure if the exact same
273
                 * call is repeated after a very short sleep.
274
                 *
275
                 * Calling pthread_yield_np() instead of sleeping /mostly/
276
                 * works as well, but still fails sometimes.
277
                 *
278
                 * Env:
279
                 *      Darwin Kernel Version 20.5.0:
280
                 *      Sat May  8 05:10:31 PDT 2021;
281
                 *      root:xnu-7195.121.3~9/RELEASE_ARM64_T8101 arm64
282
                 *
283
                 * 20220329 /phk
284
                 */
285
                if (errno == EINVAL) {
286
                        VTIM_sleep(0.0001);
287
                        errno = pthread_cond_timedwait(cond, &ilck->mtx, &ts);
288
                }
289
#endif
290
                /* We should never observe EINTR, but we have in the past. For
291
                 * example when sanitizers are enabled.
292
                 */
293 367442
                assert(errno == 0 ||
294
                    errno == ETIMEDOUT ||
295
                    errno == EINTR);
296
        }
297 1510264
        AZ(ilck->held);
298 1510264
        ilck->held = 1;
299 1510264
        ilck->owner = pthread_self();
300 1510264
        return (errno);
301
}
302
303
void
304 3475460
Lck__New(struct lock *lck, struct VSC_lck *st, const char *w)
305
{
306
        struct ilck *ilck;
307
308 3475460
        AN(st);
309 3475460
        AN(w);
310 3475460
        AN(lck);
311 3475460
        AZ(lck->priv);
312 3475460
        ALLOC_OBJ(ilck, ILCK_MAGIC);
313 3475460
        AN(ilck);
314
#ifdef ENABLE_WITNESS
315 3475460
        ilck->w = w;
316
#else
317
        (void)w;
318
#endif
319 3475460
        ilck->stat = st;
320 3475460
        ilck->stat->creat++;
321 3475460
        PTOK(pthread_mutex_init(&ilck->mtx, &mtxattr_errorcheck));
322 3475460
        lck->priv = ilck;
323 3475460
}
324
325
void
326 224175
Lck_Delete(struct lock *lck)
327
{
328
        struct ilck *ilck;
329
330 224175
        AN(lck);
331 224175
        TAKE_OBJ_NOTNULL(ilck, &lck->priv, ILCK_MAGIC);
332 224175
        ilck->stat->destroy++;
333 224175
        PTOK(pthread_mutex_destroy(&ilck->mtx));
334 224175
        FREE_OBJ(ilck);
335 224175
}
336
337
struct VSC_lck *
338 501959
Lck_CreateClass(struct vsc_seg **sg, const char *name)
339
{
340 501959
        return (VSC_lck_New(NULL, sg, name));
341
}
342
343
void
344 0
Lck_DestroyClass(struct vsc_seg **sg)
345
{
346 0
        VSC_lck_Destroy(sg);
347 0
}
348
349
#define LOCK(nam) struct VSC_lck *lck_##nam;
350
#include "tbl/locks.h"
351
352
void
353 20888
LCK_Init(void)
354
{
355
356
#define LOCK(nam)       lck_##nam = Lck_CreateClass(NULL, #nam);
357
#include "tbl/locks.h"
358
}