00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 1996, 1997, 1998, 1999, 2000 00005 * Sleepycat Software. All rights reserved. 00006 */ 00007 00008 #include "config.h" 00009 00010 #ifdef HAVE_MUTEX_FCNTL 00011 00012 #ifndef lint 00013 static const char revid[] = "$Id: mut__fcntl_8c-source.html,v 1.1 2008年06月08日 10:20:55 sebdiaz Exp $"; 00014 #endif /* not lint */ 00015 00016 #ifndef NO_SYSTEM_INCLUDES 00017 #include <sys/types.h> 00018 00019 #include <errno.h> 00020 #include <fcntl.h> 00021 #include <stdlib.h> 00022 #include <string.h> 00023 #include <unistd.h> 00024 #endif 00025 00026 #include "db_int.h" 00027 00028 /* 00029 * __db_fcntl_mutex_init -- 00030 * Initialize a DB mutex structure. 00031 * 00032 * PUBLIC: int __db_fcntl_mutex_init __P((DB_ENV *, MUTEX *, u_int32_t)); 00033 */ 00034 int 00035 __db_fcntl_mutex_init(dbenv, mutexp, offset) 00036 DB_ENV *dbenv; 00037 MUTEX *mutexp; 00038 u_int32_t offset; 00039 { 00040 memset(mutexp, 0, sizeof(*mutexp)); 00041 00042 /* 00043 * This is where we decide to ignore locks we don't need to set -- if 00044 * the application is private, we don't need any locks. 00045 */ 00046 if (F_ISSET(dbenv, DB_ENV_PRIVATE)) { 00047 F_SET(mutexp, MUTEX_IGNORE); 00048 return (0); 00049 } 00050 00051 mutexp->off = offset; 00052 00053 return (0); 00054 } 00055 00056 /* 00057 * __db_fcntl_mutex_lock 00058 * Lock on a mutex, blocking if necessary. 00059 * 00060 * PUBLIC: int __db_fcntl_mutex_lock __P((MUTEX *, DB_FH *)); 00061 */ 00062 int 00063 __db_fcntl_mutex_lock(mutexp, fhp) 00064 MUTEX *mutexp; 00065 DB_FH *fhp; 00066 { 00067 struct flock k_lock; 00068 int locked, ms, waited; 00069 00070 if (!DB_GLOBAL(db_mutexlocks)) 00071 return (0); 00072 00073 /* Initialize the lock. */ 00074 k_lock.l_whence = SEEK_SET; 00075 k_lock.l_start = mutexp->off; 00076 k_lock.l_len = 1; 00077 00078 for (locked = waited = 0;;) { 00079 /* 00080 * Wait for the lock to become available; wait 1ms initially, 00081 * up to 1 second. 00082 */ 00083 for (ms = 1; mutexp->pid != 0;) { 00084 waited = 1; 00085 CDB___os_yield(NULL, ms * USEC_PER_MS); 00086 if ((ms <<= 1) > MS_PER_SEC) 00087 ms = MS_PER_SEC; 00088 } 00089 00090 /* Acquire an exclusive kernel lock. */ 00091 k_lock.l_type = F_WRLCK; 00092 if (fcntl(fhp->fd, F_SETLKW, &k_lock)) 00093 return (CDB___os_get_errno()); 00094 00095 /* If the resource is still available, it's ours. */ 00096 if (mutexp->pid == 0) { 00097 locked = 1; 00098 mutexp->pid = (u_int32_t)getpid(); 00099 } 00100 00101 /* Release the kernel lock. */ 00102 k_lock.l_type = F_UNLCK; 00103 if (fcntl(fhp->fd, F_SETLK, &k_lock)) 00104 return (CDB___os_get_errno()); 00105 00106 /* 00107 * If we got the resource lock we're done. 00108 * 00109 * !!! 00110 * We can't check to see if the lock is ours, because we may 00111 * be trying to block ourselves in the lock manager, and so 00112 * the holder of the lock that's preventing us from getting 00113 * the lock may be us! (Seriously.) 00114 */ 00115 if (locked) 00116 break; 00117 } 00118 00119 if (waited) 00120 ++mutexp->mutex_set_wait; 00121 else 00122 ++mutexp->mutex_set_nowait; 00123 return (0); 00124 } 00125 00126 /* 00127 * __db_fcntl_mutex_unlock -- 00128 * Release a lock. 00129 * 00130 * PUBLIC: int __db_fcntl_mutex_unlock __P((MUTEX *)); 00131 */ 00132 int 00133 __db_fcntl_mutex_unlock(mutexp) 00134 MUTEX *mutexp; 00135 { 00136 if (!DB_GLOBAL(db_mutexlocks)) 00137 return (0); 00138 00139 #ifdef DIAGNOSTIC 00140 #define MSG "mutex_unlock: ERROR: released lock that was unlocked\n" 00141 #ifndef STDERR_FILENO 00142 #define STDERR_FILENO 2 00143 #endif 00144 if (mutexp->pid == 0) 00145 write(STDERR_FILENO, MSG, sizeof(MSG) - 1); 00146 #endif 00147 00148 /* 00149 * Release the resource. We don't have to acquire any locks because 00150 * processes trying to acquire the lock are checking for a pid set to 00151 * 0/non-0, not to any specific value. 00152 */ 00153 mutexp->pid = 0; 00154 00155 return (0); 00156 } 00157 00158 #endif /* HAVE_MUTEX_FCNTL */