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