1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
|
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1999-2006
* Oracle Corporation. All rights reserved.
*
* $Id: mut_alloc.c,v 12.15 2006/08/24 14:46:16 bostic Exp $
*/
#include "db_config.h"
#include "db_int.h"
#include "dbinc/mutex_int.h"
/*
* __mutex_alloc --
* Allocate a mutex from the mutex region.
*
* PUBLIC: int __mutex_alloc __P((DB_ENV *, int, u_int32_t, db_mutex_t *));
*/
int
__mutex_alloc(dbenv, alloc_id, flags, indxp)
DB_ENV *dbenv;
int alloc_id;
u_int32_t flags;
db_mutex_t *indxp;
{
int ret;
/* The caller may depend on us to initialize. */
*indxp = MUTEX_INVALID;
/*
* If this is not an application lock, and we've turned off locking,
* or the DB_ENV handle isn't thread-safe, and this is a thread lock
* or the environment isn't multi-process by definition, there's no
* need to mutex at all.
*/
if (alloc_id != MTX_APPLICATION &&
(F_ISSET(dbenv, DB_ENV_NOLOCKING) ||
(!F_ISSET(dbenv, DB_ENV_THREAD) &&
(LF_ISSET(DB_MUTEX_PROCESS_ONLY) ||
F_ISSET(dbenv, DB_ENV_PRIVATE)))))
return (0);
/*
* If we have a region in which to allocate the mutexes, lock it and
* do the allocation.
*/
if (MUTEX_ON(dbenv))
return (__mutex_alloc_int(dbenv, 1, alloc_id, flags, indxp));
/*
* We have to allocate some number of mutexes before we have a region
* in which to allocate them. We handle this by saving up the list of
* flags and allocating them as soon as we have a handle.
*
* The list of mutexes to alloc is maintained in pairs: first the
* alloc_id argument, second the flags passed in by the caller.
*/
if (dbenv->mutex_iq == NULL) {
dbenv->mutex_iq_max = 50;
if ((ret = __os_calloc(dbenv, dbenv->mutex_iq_max,
sizeof(dbenv->mutex_iq[0]), &dbenv->mutex_iq)) != 0)
return (ret);
} else if (dbenv->mutex_iq_next == dbenv->mutex_iq_max - 1) {
dbenv->mutex_iq_max *= 2;
if ((ret = __os_realloc(dbenv,
dbenv->mutex_iq_max * sizeof(dbenv->mutex_iq[0]),
&dbenv->mutex_iq)) != 0)
return (ret);
}
*indxp = dbenv->mutex_iq_next + 1; /* Correct for MUTEX_INVALID. */
dbenv->mutex_iq[dbenv->mutex_iq_next].alloc_id = alloc_id;
dbenv->mutex_iq[dbenv->mutex_iq_next].flags = flags;
++dbenv->mutex_iq_next;
return (0);
}
/*
* __mutex_alloc_int --
* Internal routine to allocate a mutex.
*
* PUBLIC: int __mutex_alloc_int
* PUBLIC: __P((DB_ENV *, int, int, u_int32_t, db_mutex_t *));
*/
int
__mutex_alloc_int(dbenv, locksys, alloc_id, flags, indxp)
DB_ENV *dbenv;
int locksys, alloc_id;
u_int32_t flags;
db_mutex_t *indxp;
{
DB_MUTEX *mutexp;
DB_MUTEXMGR *mtxmgr;
DB_MUTEXREGION *mtxregion;
int ret;
mtxmgr = dbenv->mutex_handle;
mtxregion = mtxmgr->reginfo.primary;
ret = 0;
/*
* If we're not initializing the mutex region, then lock the region to
* allocate new mutexes. Drop the lock before initializing the mutex,
* mutex initialization may require a system call.
*/
if (locksys)
MUTEX_SYSTEM_LOCK(dbenv);
if (mtxregion->mutex_next == MUTEX_INVALID) {
__db_errx(dbenv,
"unable to allocate memory for mutex; resize mutex region");
if (locksys)
MUTEX_SYSTEM_UNLOCK(dbenv);
return (ENOMEM);
}
*indxp = mtxregion->mutex_next;
mutexp = MUTEXP_SET(*indxp);
mtxregion->mutex_next = mutexp->mutex_next_link;
--mtxregion->stat.st_mutex_free;
++mtxregion->stat.st_mutex_inuse;
if (mtxregion->stat.st_mutex_inuse > mtxregion->stat.st_mutex_inuse_max)
mtxregion->stat.st_mutex_inuse_max =
mtxregion->stat.st_mutex_inuse;
if (locksys)
MUTEX_SYSTEM_UNLOCK(dbenv);
/* Initialize the mutex. */
memset(mutexp, 0, sizeof(*mutexp));
F_SET(mutexp, DB_MUTEX_ALLOCATED |
LF_ISSET(DB_MUTEX_LOGICAL_LOCK | DB_MUTEX_PROCESS_ONLY));
/*
* If the mutex is associated with a single process, set the process
* ID. If the application ever calls DbEnv::failchk, we'll need the
* process ID to know if the mutex is still in use.
*/
if (LF_ISSET(DB_MUTEX_PROCESS_ONLY))
dbenv->thread_id(dbenv, &mutexp->pid, NULL);
#ifdef HAVE_STATISTICS
mutexp->alloc_id = alloc_id;
#else
COMPQUIET(alloc_id, 0);
#endif
if ((ret = __mutex_init(dbenv, *indxp, flags)) != 0)
(void)__mutex_free_int(dbenv, locksys, indxp);
return (ret);
}
/*
* __mutex_free --
* Free a mutex.
*
* PUBLIC: int __mutex_free __P((DB_ENV *, db_mutex_t *));
*/
int
__mutex_free(dbenv, indxp)
DB_ENV *dbenv;
db_mutex_t *indxp;
{
/*
* There is no explicit ordering in how the regions are cleaned up
* up and/or discarded when an environment is destroyed (either a
* private environment is closed or a public environment is removed).
* The way we deal with mutexes is to clean up all remaining mutexes
* when we close the mutex environment (because we have to be able to
* do that anyway, after a crash), which means we don't have to deal
* with region cleanup ordering on normal environment destruction.
* All that said, what it really means is we can get here without a
* mpool region. It's OK, the mutex has been, or will be, destroyed.
*
* If the mutex has never been configured, we're done.
*/
if (!MUTEX_ON(dbenv) || *indxp == MUTEX_INVALID)
return (0);
return (__mutex_free_int(dbenv, 1, indxp));
}
/*
* __mutex_free_int --
* Internal routine to free a mutex.
*
* PUBLIC: int __mutex_free_int __P((DB_ENV *, int, db_mutex_t *));
*/
int
__mutex_free_int(dbenv, locksys, indxp)
DB_ENV *dbenv;
int locksys;
db_mutex_t *indxp;
{
DB_MUTEX *mutexp;
DB_MUTEXMGR *mtxmgr;
DB_MUTEXREGION *mtxregion;
db_mutex_t mutex;
int ret;
mutex = *indxp;
*indxp = MUTEX_INVALID;
mtxmgr = dbenv->mutex_handle;
mtxregion = mtxmgr->reginfo.primary;
mutexp = MUTEXP_SET(mutex);
DB_ASSERT(dbenv, F_ISSET(mutexp, DB_MUTEX_ALLOCATED));
F_CLR(mutexp, DB_MUTEX_ALLOCATED);
ret = __mutex_destroy(dbenv, mutex);
if (locksys)
MUTEX_SYSTEM_LOCK(dbenv);
/* Link the mutex on the head of the free list. */
mutexp->mutex_next_link = mtxregion->mutex_next;
mtxregion->mutex_next = mutex;
++mtxregion->stat.st_mutex_free;
--mtxregion->stat.st_mutex_inuse;
if (locksys)
MUTEX_SYSTEM_UNLOCK(dbenv);
return (ret);
}
|