varnish-cache/bin/varnishd/cache/cache_lck.c
1
/*-
2
 * Copyright (c) 2008-2011 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 *
28
 * The geniuses who came up with pthreads did not think operations like
29
 * pthread_assert_mutex_held() were important enough to include them in
30
 * the API.
31
 *
32
 * Build our own locks on top of pthread mutexes and hope that the next
33
 * civilization is better at such crucial details than this one.
34
 */
35
36
#include "config.h"
37
38
#include "cache_varnishd.h"
39
40
#include <errno.h>
41
#include <stdlib.h>
42
#include <stdio.h>
43
44
#include "VSC_lck.h"
45
46
struct ilck {
47
        unsigned                magic;
48
#define ILCK_MAGIC              0x7b86c8a5
49
        int                     held;
50
        pthread_mutex_t         mtx;
51
        pthread_t               owner;
52
        const char              *w;
53
        struct VSC_lck          *stat;
54
};
55
56
static pthread_mutexattr_t attr;
57
58
/*--------------------------------------------------------------------*/
59
60
static void
61 483
Lck_Witness_Lock(const struct ilck *il, const char *p, int l, const char *try)
62
{
63
        char *q, t[10];
64
        int emit;
65
66 483
        AN(p);
67 483
        q = pthread_getspecific(witness_key);
68 483
        if (q == NULL) {
69 46
                q = calloc(1, 1024);
70 46
                AN(q);
71 46
                AZ(pthread_setspecific(witness_key, q));
72
        }
73 483
        emit = *q != '\0';
74 483
        strcat(q, " ");
75 483
        strcat(q, il->w);
76 483
        strcat(q, try);
77 483
        strcat(q, ",");
78 483
        strcat(q, p);
79 483
        strcat(q, ",");
80 483
        bprintf(t, "%d", l);
81 483
        strcat(q, t);
82 483
        if (emit)
83 16
                VSL(SLT_Witness, 0, "%s", q);
84 483
}
85
86
static void
87 487
Lck_Witness_Unlock(const struct ilck *il)
88
{
89
        char *q, *r;
90
91 487
        q = pthread_getspecific(witness_key);
92 487
        if (q == NULL)
93 24
                return;
94 463
        r = strrchr(q, ' ');
95 463
        if (r == NULL)
96 0
                r = q;
97
        else
98 463
                *r++ = '\0';
99 463
        if (memcmp(r, il->w, strlen(il->w)))
100 0
                VSL(SLT_Witness, 0, "Unlock %s @ %s <%s>", il->w, r, q);
101
        else
102 463
                *r = '\0';
103
}
104
105
/*--------------------------------------------------------------------*/
106
107
void v_matchproto_()
108 481029
Lck__Lock(struct lock *lck, const char *p, int l)
109
{
110
        struct ilck *ilck;
111
112 481029
        CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
113 481029
        if (DO_DEBUG(DBG_WITNESS))
114 383
                Lck_Witness_Lock(ilck, p, l, "");
115 480926
        AZ(pthread_mutex_lock(&ilck->mtx));
116 481100
        AZ(ilck->held);
117 481100
        ilck->stat->locks++;
118 481100
        ilck->owner = pthread_self();
119 481016
        ilck->held = 1;
120 481016
}
121
122
void v_matchproto_()
123 528627
Lck__Unlock(struct lock *lck, const char *p, int l)
124
{
125
        struct ilck *ilck;
126
127
        (void)p;
128
        (void)l;
129
130 528627
        CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
131 528627
        assert(pthread_equal(ilck->owner, pthread_self()));
132 528691
        AN(ilck->held);
133 528691
        ilck->held = 0;
134
        /*
135
         * #ifdef POSIX_STUPIDITY:
136
         * The pthread_t type has no defined assignment or comparison
137
         * operators, this is why pthread_equal() is necessary.
138
         * Unfortunately POSIX forgot to define a NULL value for pthread_t
139
         * so you can never unset a pthread_t variable.
140
         * We hack it and fill it with zero bits, hoping for sane
141
         * implementations of pthread.
142
         * #endif
143
         */
144 528691
        memset(&ilck->owner, 0, sizeof ilck->owner);
145 528691
        AZ(pthread_mutex_unlock(&ilck->mtx));
146 528743
        if (DO_DEBUG(DBG_WITNESS))
147 487
                Lck_Witness_Unlock(ilck);
148 528647
}
149
150
int v_matchproto_()
151 77952
Lck__Trylock(struct lock *lck, const char *p, int l)
152
{
153
        struct ilck *ilck;
154
        int r;
155
156 77952
        CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
157 77952
        if (DO_DEBUG(DBG_WITNESS))
158 100
                Lck_Witness_Lock(ilck, p, l, "?");
159 77985
        r = pthread_mutex_trylock(&ilck->mtx);
160 78009
        assert(r == 0 || r == EBUSY);
161 78009
        if (r == 0) {
162 78008
                AZ(ilck->held);
163 78008
                ilck->held = 1;
164 78008
                ilck->stat->locks++;
165 78008
                ilck->owner = pthread_self();
166
        }
167 77893
        return (r);
168
}
169
170
int
171 33212
Lck__Held(const struct lock *lck)
172
{
173
        struct ilck *ilck;
174
175 33212
        CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
176 33212
        return (ilck->held);
177
}
178
179
int
180 33212
Lck__Owned(const struct lock *lck)
181
{
182
        struct ilck *ilck;
183
184 33212
        CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
185 33212
        AN(ilck->held);
186 33212
        return (pthread_equal(ilck->owner, pthread_self()));
187
}
188
189
int v_matchproto_()
190 126456
Lck_CondWait(pthread_cond_t *cond, struct lock *lck, vtim_real when)
191
{
192
        struct ilck *ilck;
193
        struct timespec ts;
194
        double t;
195
196 126456
        CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
197 126456
        AN(ilck->held);
198 126456
        assert(pthread_equal(ilck->owner, pthread_self()));
199 126456
        ilck->held = 0;
200 126456
        if (when == 0) {
201 98499
                errno = pthread_cond_wait(cond, &ilck->mtx);
202 75333
                AZ(errno);
203
        } else {
204 27957
                assert(when > 1e9);
205 27957
                ts.tv_nsec = (long)(modf(when, &t) * 1e9);
206 27957
                ts.tv_sec = (long)t;
207 27957
                errno = pthread_cond_timedwait(cond, &ilck->mtx, &ts);
208 20770
                assert(errno == 0 ||
209
                    errno == ETIMEDOUT ||
210
                    errno == EINTR);
211
        }
212 96104
        AZ(ilck->held);
213 96104
        ilck->held = 1;
214 96104
        ilck->owner = pthread_self();
215 96102
        return (errno);
216
}
217
218
void
219 50365
Lck__New(struct lock *lck, struct VSC_lck *st, const char *w)
220
{
221
        struct ilck *ilck;
222
223 50365
        AN(st);
224 50365
        AN(w);
225 50365
        AZ(lck->priv);
226 50365
        ALLOC_OBJ(ilck, ILCK_MAGIC);
227 50365
        AN(ilck);
228 50365
        ilck->w = w;
229 50365
        ilck->stat = st;
230 50365
        ilck->stat->creat++;
231 50365
        AZ(pthread_mutex_init(&ilck->mtx, &attr));
232 50365
        lck->priv = ilck;
233 50365
}
234
235
void
236 6942
Lck_Delete(struct lock *lck)
237
{
238
        struct ilck *ilck;
239
240 6942
        CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
241 6942
        ilck->stat->destroy++;
242 6942
        lck->priv = NULL;
243 6942
        AZ(pthread_mutex_destroy(&ilck->mtx));
244 6942
        FREE_OBJ(ilck);
245 6942
}
246
247
struct VSC_lck *
248 27584
Lck_CreateClass(struct vsc_seg **sg, const char *name)
249
{
250 27584
        return(VSC_lck_New(NULL, sg, name));
251
}
252
253
void
254 0
Lck_DestroyClass(struct vsc_seg **sg)
255
{
256 0
        VSC_lck_Destroy(sg);
257 0
}
258
259
#define LOCK(nam) struct VSC_lck *lck_##nam;
260
#include "tbl/locks.h"
261
262
void
263 1376
LCK_Init(void)
264
{
265
266 1376
        AZ(pthread_mutexattr_init(&attr));
267 1376
        AZ(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK));
268
#define LOCK(nam)       lck_##nam = Lck_CreateClass(NULL, #nam);
269
#include "tbl/locks.h"
270 1376
}