1 /*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996, 1997, 1998, 1999
5 * Sleepycat Software. All rights reserved.
6 */
7
8 #include "db_config.h"
9
10 #ifdef HAVE_MUTEX_FCNTL
11
12 #ifndef lint
13 static const char sccsid[] = "@(#)mut_fcntl.c 11.1 (Sleepycat) 7/25/99";
14 #endif /* not lint */
15
16 #ifndef NO_SYSTEM_INCLUDES
17 #include <sys/types.h>
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #endif
25
26 #include "db_int.h"
27
28 /*
29 * CDB___db_fcntl_mutex_init --
30 * Initialize a DB mutex structure.
31 *
32 * PUBLIC: int CDB___db_fcntl_mutex_init __P((DB_ENV *, MUTEX *, u_int32_t));
33 */
34 int
CDB___db_fcntl_mutex_init(dbenv,mutexp,offset)35 CDB___db_fcntl_mutex_init(dbenv, mutexp, offset)
36 DB_ENV *dbenv;
37 MUTEX *mutexp;
38 u_int32_t offset;
39 {
40 memset(mutexp, 0, sizeof(*mutexp));
41
42 /*
43 * This is where we decide to ignore locks we don't need to set -- if
44 * the application is private, we don't need any locks.
45 */
46 if (F_ISSET(dbenv, DB_ENV_PRIVATE)) {
47 F_SET(mutexp, MUTEX_IGNORE);
48 return (0);
49 }
50
51 mutexp->off = offset;
52
53 return (0);
54 }
55
56 /*
57 * CDB___db_fcntl_mutex_lock
58 * Lock on a mutex, blocking if necessary.
59 *
60 * PUBLIC: int CDB___db_fcntl_mutex_lock __P((MUTEX *, DB_FH *));
61 */
62 int
CDB___db_fcntl_mutex_lock(mutexp,fhp)63 CDB___db_fcntl_mutex_lock(mutexp, fhp)
64 MUTEX *mutexp;
65 DB_FH *fhp;
66 {
67 struct flock k_lock;
68 int locked, ms, waited;
69
70 if (!DB_GLOBAL(db_mutexlocks))
71 return (0);
72
73 /* Initialize the lock. */
74 k_lock.l_whence = SEEK_SET;
75 k_lock.l_start = mutexp->off;
76 k_lock.l_len = 1;
77
78 for (locked = waited = 0;;) {
79 /*
80 * Wait for the lock to become available; wait 1ms initially,
81 * up to 1 second.
82 */
83 for (ms = 1; mutexp->pid != 0;) {
84 waited = 1;
85 CDB___os_yield(ms * USEC_PER_MS);
86 if ((ms <<= 1) > MS_PER_SEC)
87 ms = MS_PER_SEC;
88 }
89
90 /* Acquire an exclusive kernel lock. */
91 k_lock.l_type = F_WRLCK;
92 if (fcntl(fhp->fd, F_SETLKW, &k_lock))
93 return (CDB___os_get_errno());
94
95 /* If the resource is still available, it's ours. */
96 if (mutexp->pid == 0) {
97 locked = 1;
98 mutexp->pid = (u_int32_t)getpid();
99 }
100
101 /* Release the kernel lock. */
102 k_lock.l_type = F_UNLCK;
103 if (fcntl(fhp->fd, F_SETLK, &k_lock))
104 return (CDB___os_get_errno());
105
106 /*
107 * If we got the resource lock we're done.
108 *
109 * !!!
110 * We can't check to see if the lock is ours, because we may
111 * be trying to block ourselves in the lock manager, and so
112 * the holder of the lock that's preventing us from getting
113 * the lock may be us! (Seriously.)
114 */
115 if (locked)
116 break;
117 }
118
119 if (waited)
120 ++mutexp->mutex_set_wait;
121 else
122 ++mutexp->mutex_set_nowait;
123 return (0);
124 }
125
126 /*
127 * CDB___db_fcntl_mutex_unlock --
128 * Release a lock.
129 *
130 * PUBLIC: int CDB___db_fcntl_mutex_unlock __P((MUTEX *));
131 */
132 int
CDB___db_fcntl_mutex_unlock(mutexp)133 CDB___db_fcntl_mutex_unlock(mutexp)
134 MUTEX *mutexp;
135 {
136 if (!DB_GLOBAL(db_mutexlocks))
137 return (0);
138
139 #ifdef DIAGNOSTIC
140 #define MSG "mutex_unlock: ERROR: released lock that was unlocked\n"
141 #ifndef STDERR_FILENO
142 #define STDERR_FILENO 2
143 #endif
144 if (mutexp->pid == 0)
145 write(STDERR_FILENO, MSG, sizeof(MSG) - 1);
146 #endif
147
148 /*
149 * Release the resource. We don't have to acquire any locks because
150 * processes trying to acquire the lock are checking for a pid set to
151 * 0/non-0, not to any specific value.
152 */
153 mutexp->pid = 0;
154
155 return (0);
156 }
157
158 #endif /* HAVE_MUTEX_FCNTL */
159