Remove definition of builtin function
[platform/upstream/db4.git] / mutex / mut_method.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996-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_pp --
15  *      Allocate a mutex, application method.
16  *
17  * PUBLIC: int __mutex_alloc_pp __P((DB_ENV *, u_int32_t, db_mutex_t *));
18  */
19 int
20 __mutex_alloc_pp(dbenv, flags, indxp)
21         DB_ENV *dbenv;
22         u_int32_t flags;
23         db_mutex_t *indxp;
24 {
25         DB_THREAD_INFO *ip;
26         ENV *env;
27         int ret;
28
29         env = dbenv->env;
30
31         if ((ret = __db_fchk(env, "DB_ENV->mutex_alloc",
32             flags, DB_MUTEX_PROCESS_ONLY | DB_MUTEX_SELF_BLOCK)) != 0)
33                 return (ret);
34
35         ENV_ENTER(env, ip);
36         ret = __mutex_alloc(env, MTX_APPLICATION, flags, indxp);
37         ENV_LEAVE(env, ip);
38
39         return (ret);
40 }
41
42 /*
43  * __mutex_free_pp --
44  *      Destroy a mutex, application method.
45  *
46  * PUBLIC: int __mutex_free_pp __P((DB_ENV *, db_mutex_t));
47  */
48 int
49 __mutex_free_pp(dbenv, indx)
50         DB_ENV *dbenv;
51         db_mutex_t indx;
52 {
53         DB_THREAD_INFO *ip;
54         ENV *env;
55         int ret;
56
57         env = dbenv->env;
58
59         if (indx == MUTEX_INVALID)
60                 return (EINVAL);
61
62         /*
63          * Internally Berkeley DB passes around the db_mutex_t address on
64          * free, because we want to make absolutely sure the slot gets
65          * overwritten with MUTEX_INVALID.  We don't export MUTEX_INVALID,
66          * so we don't export that part of the API, either.
67          */
68         ENV_ENTER(env, ip);
69         ret = __mutex_free(env, &indx);
70         ENV_LEAVE(env, ip);
71
72         return (ret);
73 }
74
75 /*
76  * __mutex_lock --
77  *      Lock a mutex, application method.
78  *
79  * PUBLIC: int __mutex_lock_pp __P((DB_ENV *, db_mutex_t));
80  */
81 int
82 __mutex_lock_pp(dbenv, indx)
83         DB_ENV *dbenv;
84         db_mutex_t indx;
85 {
86         DB_THREAD_INFO *ip;
87         ENV *env;
88         int ret;
89
90         env = dbenv->env;
91
92         if (indx == MUTEX_INVALID)
93                 return (EINVAL);
94
95         ENV_ENTER(env, ip);
96         ret = __mutex_lock(env, indx);
97         ENV_LEAVE(env, ip);
98         return (ret);
99 }
100
101 /*
102  * __mutex_unlock --
103  *      Unlock a mutex, application method.
104  *
105  * PUBLIC: int __mutex_unlock_pp __P((DB_ENV *, db_mutex_t));
106  */
107 int
108 __mutex_unlock_pp(dbenv, indx)
109         DB_ENV *dbenv;
110         db_mutex_t indx;
111 {
112         DB_THREAD_INFO *ip;
113         ENV *env;
114         int ret;
115
116         env = dbenv->env;
117
118         if (indx == MUTEX_INVALID)
119                 return (EINVAL);
120
121         ENV_ENTER(env, ip);
122         ret = __mutex_unlock(env, indx);
123         ENV_LEAVE(env, ip);
124         return (ret);
125 }
126
127 /*
128  * __mutex_get_align --
129  *      DB_ENV->mutex_get_align.
130  *
131  * PUBLIC: int __mutex_get_align __P((DB_ENV *, u_int32_t *));
132  */
133 int
134 __mutex_get_align(dbenv, alignp)
135         DB_ENV *dbenv;
136         u_int32_t *alignp;
137 {
138         ENV *env;
139
140         env = dbenv->env;
141
142         if (MUTEX_ON(env)) {
143                 /* Cannot be set after open, no lock required to read. */
144                 *alignp = ((DB_MUTEXREGION *)
145                     env->mutex_handle->reginfo.primary)->stat.st_mutex_align;
146         } else
147                 *alignp = dbenv->mutex_align;
148         return (0);
149 }
150
151 /*
152  * __mutex_set_align --
153  *      DB_ENV->mutex_set_align.
154  *
155  * PUBLIC: int __mutex_set_align __P((DB_ENV *, u_int32_t));
156  */
157 int
158 __mutex_set_align(dbenv, align)
159         DB_ENV *dbenv;
160         u_int32_t align;
161 {
162         ENV *env;
163
164         env = dbenv->env;
165
166         ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_mutex_align");
167
168         if (align == 0 || !POWER_OF_TWO(align)) {
169                 __db_errx(env,
170     "DB_ENV->mutex_set_align: alignment value must be a non-zero power-of-two");
171                 return (EINVAL);
172         }
173
174         dbenv->mutex_align = align;
175         return (0);
176 }
177
178 /*
179  * __mutex_get_increment --
180  *      DB_ENV->mutex_get_increment.
181  *
182  * PUBLIC: int __mutex_get_increment __P((DB_ENV *, u_int32_t *));
183  */
184 int
185 __mutex_get_increment(dbenv, incrementp)
186         DB_ENV *dbenv;
187         u_int32_t *incrementp;
188 {
189         /*
190          * We don't maintain the increment in the region (it just makes
191          * no sense).  Return whatever we have configured on this handle,
192          * nobody is ever going to notice.
193          */
194         *incrementp = dbenv->mutex_inc;
195         return (0);
196 }
197
198 /*
199  * __mutex_set_increment --
200  *      DB_ENV->mutex_set_increment.
201  *
202  * PUBLIC: int __mutex_set_increment __P((DB_ENV *, u_int32_t));
203  */
204 int
205 __mutex_set_increment(dbenv, increment)
206         DB_ENV *dbenv;
207         u_int32_t increment;
208 {
209         ENV *env;
210
211         env = dbenv->env;
212
213         ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_mutex_increment");
214
215         dbenv->mutex_cnt = 0;
216         dbenv->mutex_inc = increment;
217         return (0);
218 }
219
220 /*
221  * __mutex_get_max --
222  *      DB_ENV->mutex_get_max.
223  *
224  * PUBLIC: int __mutex_get_max __P((DB_ENV *, u_int32_t *));
225  */
226 int
227 __mutex_get_max(dbenv, maxp)
228         DB_ENV *dbenv;
229         u_int32_t *maxp;
230 {
231         ENV *env;
232
233         env = dbenv->env;
234
235         if (MUTEX_ON(env)) {
236                 /* Cannot be set after open, no lock required to read. */
237                 *maxp = ((DB_MUTEXREGION *)
238                     env->mutex_handle->reginfo.primary)->stat.st_mutex_cnt;
239         } else
240                 *maxp = dbenv->mutex_cnt;
241         return (0);
242 }
243
244 /*
245  * __mutex_set_max --
246  *      DB_ENV->mutex_set_max.
247  *
248  * PUBLIC: int __mutex_set_max __P((DB_ENV *, u_int32_t));
249  */
250 int
251 __mutex_set_max(dbenv, max)
252         DB_ENV *dbenv;
253         u_int32_t max;
254 {
255         ENV *env;
256
257         env = dbenv->env;
258
259         ENV_ILLEGAL_AFTER_OPEN(env, "DB_ENV->set_mutex_max");
260
261         dbenv->mutex_cnt = max;
262         dbenv->mutex_inc = 0;
263         return (0);
264 }
265
266 /*
267  * __mutex_get_tas_spins --
268  *      DB_ENV->mutex_get_tas_spins.
269  *
270  * PUBLIC: int __mutex_get_tas_spins __P((DB_ENV *, u_int32_t *));
271  */
272 int
273 __mutex_get_tas_spins(dbenv, tas_spinsp)
274         DB_ENV *dbenv;
275         u_int32_t *tas_spinsp;
276 {
277         ENV *env;
278
279         env = dbenv->env;
280
281         if (MUTEX_ON(env)) {
282                 /* Cannot be set after open, no lock required to read. */
283                 *tas_spinsp = ((DB_MUTEXREGION *)env->
284                     mutex_handle->reginfo.primary)->stat.st_mutex_tas_spins;
285         } else
286                 *tas_spinsp = dbenv->mutex_tas_spins;
287         return (0);
288 }
289
290 /*
291  * __mutex_set_tas_spins --
292  *      DB_ENV->mutex_set_tas_spins.
293  *
294  * PUBLIC: int __mutex_set_tas_spins __P((DB_ENV *, u_int32_t));
295  */
296 int
297 __mutex_set_tas_spins(dbenv, tas_spins)
298         DB_ENV *dbenv;
299         u_int32_t tas_spins;
300 {
301         ENV *env;
302
303         env = dbenv->env;
304
305         /*
306          * Bound the value -- less than 1 makes no sense, greater than 1M
307          * makes no sense.
308          */
309         if (tas_spins == 0)
310                 tas_spins = 1;
311         else if (tas_spins > 1000000)
312                 tas_spins = 1000000;
313
314         /*
315          * There's a theoretical race here, but I'm not interested in locking
316          * the test-and-set spin count.  The worst possibility is a thread
317          * reads out a bad spin count and spins until it gets the lock, but
318          * that's awfully unlikely.
319          */
320         if (MUTEX_ON(env))
321                 ((DB_MUTEXREGION *)env->mutex_handle
322                     ->reginfo.primary)->stat.st_mutex_tas_spins = tas_spins;
323         else
324                 dbenv->mutex_tas_spins = tas_spins;
325         return (0);
326 }
327
328 #if !defined(HAVE_ATOMIC_SUPPORT) && defined(HAVE_MUTEX_SUPPORT)
329 /*
330  * Provide atomic operations for platforms which have mutexes yet do not have
331  * native atomic operations configured. They are emulated by protected the
332  * operation with a mutex.  The address of the atomic value selects which
333  * mutex to use.
334  */
335 /*
336  * atomic_get_mutex -
337  *      Map an address to the mutex to use to atomically modify it
338  */
339 static inline db_mutex_t atomic_get_mutex(env, v)
340         ENV *env;
341         db_atomic_t *v;
342 {
343         u_int   index;
344         DB_MUTEXREGION *mtxreg;
345
346         if (!MUTEX_ON(env))
347                 return (MUTEX_INVALID);
348         index = (u_int)(((uintptr_t) (v)) >> 6) % MAX_ATOMIC_MUTEXES;
349         mtxreg = (DB_MUTEXREGION *)env->mutex_handle->reginfo.primary;
350         return (mtxreg->mtx_atomic[index]);
351 }
352
353 /*
354  * __atomic_inc
355  *      Use a mutex to provide an atomic increment function
356  *
357  * PUBLIC: #if !defined(HAVE_ATOMIC_SUPPORT) && defined(HAVE_MUTEX_SUPPORT)
358  * PUBLIC: atomic_value_t __atomic_inc __P((ENV *, db_atomic_t *));
359  * PUBLIC: #endif
360  */
361 atomic_value_t
362 __atomic_inc(env, v)
363         ENV *env;
364         db_atomic_t *v;
365 {
366         db_mutex_t mtx;
367         int ret;
368
369         mtx = atomic_get_mutex(env, v);
370         MUTEX_LOCK(env, mtx);
371         ret = ++v->value;
372         MUTEX_UNLOCK(env, mtx);
373
374         return (ret);
375 }
376
377 /*
378  * __atomic_dec
379  *      Use a mutex to provide an atomic decrement function
380  *
381  * PUBLIC: #if !defined(HAVE_ATOMIC_SUPPORT) && defined(HAVE_MUTEX_SUPPORT)
382  * PUBLIC: atomic_value_t __atomic_dec __P((ENV *, db_atomic_t *));
383  * PUBLIC: #endif
384  */
385 atomic_value_t
386 __atomic_dec(env, v)
387         ENV *env;
388         db_atomic_t *v;
389 {
390         db_mutex_t mtx;
391         int ret;
392
393         mtx = atomic_get_mutex(env, v);
394         MUTEX_LOCK(env, mtx);
395         ret = --v->value;
396         MUTEX_UNLOCK(env, mtx);
397
398         return (ret);
399 }
400
401 /*
402  * atomic_compare_exchange
403  *      Use a mutex to provide an atomic decrement function
404  *
405  * PRIVATE: int atomic_compare_exchange
406  * PRIVATE:     __P((ENV *, db_atomic_t *, atomic_value_t, atomic_value_t));
407  *      Returns 1 if the *v was equal to oldval, else 0
408  *
409  *      Side Effect:
410  *              Sets the value to newval if and only if returning 1
411  */
412 int
413 atomic_compare_exchange(env, v, oldval, newval)
414         ENV *env;
415         db_atomic_t *v;
416         atomic_value_t oldval;
417         atomic_value_t newval;
418 {
419         db_mutex_t mtx;
420         int ret;
421
422         if (atomic_read(v) != oldval)
423                 return (0);
424
425         mtx = atomic_get_mutex(env, v);
426         MUTEX_LOCK(env, mtx);
427         ret = atomic_read(v) == oldval;
428         if (ret)
429                 atomic_init(v, newval);
430         MUTEX_UNLOCK(env, mtx);
431
432         return (ret);
433 }
434 #endif