📄 mutex.h
字号:
}#define MUTEX_UNSET(tsl) (*(tsl) = 0)#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)#endif#endif/********************************************************************* * SCO/cc assembly. *********************************************************************/#ifdef HAVE_MUTEX_SCO_X86_CC_ASSEMBLYtypedef unsigned char tsl_t;#ifdef LOAD_ACTUAL_MUTEX_CODE/* * UnixWare has threads in libthread, but OpenServer doesn't (yet). */#define MUTEX_SET_TEST 1 /* cc/x86: 0 is clear, 1 is set. */#if defined(__USLC__)asm int_tsl_set(void *tsl){%mem tsl movl tsl, %ecx movl $1, %eax lock xchgb (%ecx),%al xorl $1,%eax}#endif#define MUTEX_SET(tsl) _tsl_set(tsl)#define MUTEX_UNSET(tsl) (*(tsl) = 0)#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)#endif#endif/********************************************************************* * Sparc/gcc assembly. *********************************************************************/#ifdef HAVE_MUTEX_SPARC_GCC_ASSEMBLYtypedef unsigned char tsl_t;#ifdef LOAD_ACTUAL_MUTEX_CODE/* * * The ldstub instruction takes the location specified by its first argument * (a register containing a memory address) and loads its contents into its * second argument (a register) and atomically sets the contents the location * specified by its first argument to a byte of 1s. (The value in the second * argument is never read, but only overwritten.) * * The stbar is needed for v8, and is implemented as membar #sync on v9, * so is functional there as well. For v7, stbar may generate an illegal * instruction and we have no way to tell what we're running on. Some * operating systems notice and skip this instruction in the fault handler. */#define MUTEX_SET_TEST 1 /* gcc/sparc: 0 is clear, 1 is set. */#define MUTEX_SET(tsl) ({ \ register tsl_t *__l = (tsl); \ register tsl_t __r; \ __asm__ volatile \ ("ldstub [%1],%0; stbar" \ : "=r"( __r) : "r" (__l)); \ !__r; \})#define MUTEX_UNSET(tsl) (*(tsl) = 0)#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)#endif#endif/********************************************************************* * UTS/cc assembly. *********************************************************************/#ifdef HAVE_MUTEX_UTS_CC_ASSEMBLYtypedef int tsl_t;#ifndef MUTEX_ALIGN#define MUTEX_ALIGN sizeof(int)#endif#ifdef LOAD_ACTUAL_MUTEX_CODE#define MUTEX_INIT(x) 0#define MUTEX_SET(x) (!uts_lock(x, 1))#define MUTEX_UNSET(x) (*(x) = 0)#endif#endif/********************************************************************* * x86/gcc assembly. *********************************************************************/#ifdef HAVE_MUTEX_X86_GCC_ASSEMBLYtypedef unsigned char tsl_t;#ifdef LOAD_ACTUAL_MUTEX_CODE#define MUTEX_SET_TEST 1 /* gcc/x86: 0 is clear, 1 is set. */#define MUTEX_SET(tsl) ({ \ register tsl_t *__l = (tsl); \ int __r; \ asm volatile("movl $1,%%eax; lock; xchgb %1,%%al; xorl $1,%%eax"\ : "=&a" (__r), "=m" (*__l) \ : "1" (*__l) \ ); \ __r & 1; \})#define MUTEX_UNSET(tsl) (*(tsl) = 0)#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)/* * From Intel's performance tuning documentation (and see SR #6975): * ftp://download.intel.com/design/perftool/cbts/appnotes/sse2/w_spinlock.pdf * * "For this reason, it is highly recommended that you insert the PAUSE * instruction into all spin-wait code immediately. Using the PAUSE * instruction does not affect the correctness of programs on existing * platforms, and it improves performance on Pentium 4 processor platforms." */#define MUTEX_PAUSE asm volatile ("rep; nop" : : );#endif#endif/* * Mutex alignment defaults to one byte. * * !!! * Various systems require different alignments for mutexes (the worst we've * seen so far is 16-bytes on some HP architectures). Malloc(3) is assumed * to return reasonable alignment, all other mutex users must ensure proper * alignment locally. */#ifndef MUTEX_ALIGN#define MUTEX_ALIGN 1#endif/* * Mutex destruction defaults to a no-op. */#ifdef LOAD_ACTUAL_MUTEX_CODE#ifndef MUTEX_DESTROY#define MUTEX_DESTROY(x)#endif#endif/* * !!! * The flag arguments for __db_mutex_setup (and the underlying initialization * function for the mutex type, for example, __db_tas_mutex_init), and flags * stored in the DB_MUTEX structure are combined, and may not overlap. Flags * to __db_mutex_setup: * * MUTEX_ALLOC: * Use when the mutex to initialize needs to be allocated. The 'ptr' * arg to __db_mutex_setup should be a DB_MUTEX ** whenever you use * this flag. If this flag is not set, the 'ptr' arg is a DB_MUTEX *. * MUTEX_NO_RECORD: * Explicitly do not record the mutex in the region. Otherwise the * mutex will be recorded by default. If you set this you need to * understand why you don't need it recorded. The *only* ones not * recorded are those that are part of region structures that only * get destroyed when the regions are destroyed. * MUTEX_NO_RLOCK: * Explicitly do not lock the given region otherwise the region will * be locked by default. * MUTEX_SELF_BLOCK: * Set if self blocking mutex. * MUTEX_THREAD: * Set if mutex is a thread-only mutex. */#define MUTEX_ALLOC 0x0001 /* Allocate and init a mutex */#define MUTEX_IGNORE 0x0002 /* Ignore, no lock required. */#define MUTEX_INITED 0x0004 /* Mutex is successfully initialized */#define MUTEX_LOGICAL_LOCK 0x0008 /* Mutex backs database lock. */#define MUTEX_MPOOL 0x0010 /* Allocated from mpool. */#define MUTEX_NO_RECORD 0x0020 /* Do not record lock */#define MUTEX_NO_RLOCK 0x0040 /* Do not acquire region lock */#define MUTEX_SELF_BLOCK 0x0080 /* Must block self. */#define MUTEX_THREAD 0x0100 /* Thread-only mutex. *//* Mutex. */struct __mutex_t {#ifdef HAVE_MUTEX_THREADS#ifdef MUTEX_FIELDS MUTEX_FIELDS#else tsl_t tas; /* Test and set. */#endif u_int32_t locked; /* !0 if locked. */#else u_int32_t off; /* Byte offset to lock. */ u_int32_t pid; /* Lock holder: 0 or process pid. */#endif u_int32_t mutex_set_wait; /* Granted after wait. */ u_int32_t mutex_set_nowait; /* Granted without waiting. */ u_int32_t mutex_set_spin; /* Granted without spinning. */ u_int32_t mutex_set_spins; /* Total number of spins. */#ifdef HAVE_MUTEX_SYSTEM_RESOURCES roff_t reg_off; /* Shared lock info offset. */#endif /* * Flags should be an unsigned integer even if it's not required by * the possible flags values, getting a single byte on some machines * is expensive, and the mutex structure is a MP hot spot. */ u_int32_t flags; /* MUTEX_XXX */};/* Macro to clear mutex statistics. */#define MUTEX_CLEAR(mp) { \ (mp)->mutex_set_wait = (mp)->mutex_set_nowait = 0; \}/* Redirect calls to the correct functions. */#ifdef HAVE_MUTEX_THREADS#if defined(HAVE_MUTEX_PTHREADS) || \ defined(HAVE_MUTEX_SOLARIS_LWP) || \ defined(HAVE_MUTEX_UI_THREADS)#define __db_mutex_init_int(a, b, c, d) __db_pthread_mutex_init(a, b, d)#define __db_mutex_lock(a, b) __db_pthread_mutex_lock(a, b)#define __db_mutex_unlock(a, b) __db_pthread_mutex_unlock(a, b)#define __db_mutex_destroy(a) __db_pthread_mutex_destroy(a)#else#if defined(HAVE_MUTEX_WIN32) || defined(HAVE_MUTEX_WIN32_GCC)#define __db_mutex_init_int(a, b, c, d) __db_win32_mutex_init(a, b, d)#define __db_mutex_lock(a, b) __db_win32_mutex_lock(a, b)#define __db_mutex_unlock(a, b) __db_win32_mutex_unlock(a, b)#define __db_mutex_destroy(a) __db_win32_mutex_destroy(a)#else#define __db_mutex_init_int(a, b, c, d) __db_tas_mutex_init(a, b, d)#define __db_mutex_lock(a, b) __db_tas_mutex_lock(a, b)#define __db_mutex_unlock(a, b) __db_tas_mutex_unlock(a, b)#define __db_mutex_destroy(a) __db_tas_mutex_destroy(a)#endif#endif#else#define __db_mutex_init_int(a, b, c, d) __db_fcntl_mutex_init(a, b, c)#define __db_mutex_lock(a, b) __db_fcntl_mutex_lock(a, b)#define __db_mutex_unlock(a, b) __db_fcntl_mutex_unlock(a, b)#define __db_mutex_destroy(a) __db_fcntl_mutex_destroy(a)#endif/* Redirect system resource calls to correct functions */#ifdef HAVE_MUTEX_SYSTEM_RESOURCES#define __db_maintinit(a, b, c) __db_shreg_maintinit(a, b, c)#define __db_shlocks_clear(a, b, c) __db_shreg_locks_clear(a, b, c)#define __db_shlocks_destroy(a, b) __db_shreg_locks_destroy(a, b)#define __db_mutex_init(a, b, c, d, e, f) \ __db_shreg_mutex_init(a, b, c, d, e, f)#else#define __db_maintinit(a, b, c)#define __db_shlocks_clear(a, b, c)#define __db_shlocks_destroy(a, b)#define __db_mutex_init(a, b, c, d, e, f) __db_mutex_init_int(a, b, c, d)#endif/* * Lock/unlock a mutex. If the mutex was marked as uninteresting, the thread * of control can proceed without it. * * If the lock is for threads-only, then it was optionally not allocated and * file handles aren't necessary, as threaded applications aren't supported by * fcntl(2) locking. */#ifdef DIAGNOSTIC /* * XXX * We want to switch threads as often as possible. Yield every time * we get a mutex to ensure contention. */#define MUTEX_LOCK(dbenv, mp) \ if (!F_ISSET((mp), MUTEX_IGNORE)) \ DB_ASSERT(__db_mutex_lock(dbenv, mp) == 0); \ if (F_ISSET(dbenv, DB_ENV_YIELDCPU)) \ __os_yield(NULL, 1);#else#define MUTEX_LOCK(dbenv, mp) \ if (!F_ISSET((mp), MUTEX_IGNORE)) \ (void)__db_mutex_lock(dbenv, mp);#endif#define MUTEX_UNLOCK(dbenv, mp) \ if (!F_ISSET((mp), MUTEX_IGNORE)) \ (void)__db_mutex_unlock(dbenv, mp);#define MUTEX_THREAD_LOCK(dbenv, mp) \ if (mp != NULL) \ MUTEX_LOCK(dbenv, mp)#define MUTEX_THREAD_UNLOCK(dbenv, mp) \ if (mp != NULL) \ MUTEX_UNLOCK(dbenv, mp)/* * We use a single file descriptor for fcntl(2) locking, and (generally) the * object's offset in a shared region as the byte that we're locking. So, * there's a (remote) possibility that two objects might have the same offsets * such that the locks could conflict, resulting in deadlock. To avoid this * possibility, we offset the region offset by a small integer value, using a * different offset for each subsystem's locks. Since all region objects are * suitably aligned, the offset guarantees that we don't collide with another * region's objects. */#define DB_FCNTL_OFF_GEN 0 /* Everything else. */#define DB_FCNTL_OFF_LOCK 1 /* Lock subsystem offset. */#define DB_FCNTL_OFF_MPOOL 2 /* Mpool subsystem offset. */#ifdef HAVE_MUTEX_SYSTEM_RESOURCES/* * When the underlying mutexes require library (most likely heap) or system * resources, we have to clean up when we discard mutexes (for the library * resources) and both when discarding mutexes and after application failure * (for the mutexes requiring system resources). This violates the rule that * we never look at a shared region after application failure, but we've no * other choice. In those cases, the #define HAVE_MUTEX_SYSTEM_RESOURCES is * set. * * To support mutex release after application failure, allocate thread-handle * mutexes in shared memory instead of in the heap. The number of slots we * allocate for this purpose isn't configurable, but this tends to be an issue * only on embedded systems where we don't expect large server applications. */#define DB_MAX_HANDLES 100 /* Mutex slots for handles. */#endif#endif /* !_DB_MUTEX_H_ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -