⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lock.c

📁 这是linux下运行的mysql软件包,可用于linux 下安装 php + mysql + apach 的网络配置
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (run_dd)		(void)dbenv->lock_detect(dbenv, 0, region->detect, &did_abort);	if (ret != 0 && elistp != NULL)		*elistp = &list[i - 1];	return (ret);}/* * Lock acquisition routines.  There are two library interfaces: * * __lock_get -- *	original lock get interface that takes a locker id. * * All the work for lock_get (and for the GET option of lock_vec) is done * inside of lock_get_internal. * * PUBLIC: int __lock_get __P((DB_ENV *, * PUBLIC:     u_int32_t, u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *)); */int__lock_get(dbenv, locker, flags, obj, lock_mode, lock)	DB_ENV *dbenv;	u_int32_t locker, flags;	const DBT *obj;	db_lockmode_t lock_mode;	DB_LOCK *lock;{	int ret;	PANIC_CHECK(dbenv);	ENV_REQUIRES_CONFIG(dbenv,	    dbenv->lk_handle, "DB_ENV->lock_get", DB_INIT_LOCK);	if (IS_RECOVERING(dbenv)) {		LOCK_INIT(*lock);		return (0);	}	/* Validate arguments. */	if ((ret = __db_fchk(dbenv, "DB_ENV->lock_get", flags,	    DB_LOCK_NOWAIT | DB_LOCK_UPGRADE | DB_LOCK_SWITCH)) != 0)		return (ret);	LOCKREGION(dbenv, (DB_LOCKTAB *)dbenv->lk_handle);	ret = __lock_get_internal(dbenv->lk_handle,	    locker, flags, obj, lock_mode, 0, lock);	UNLOCKREGION(dbenv, (DB_LOCKTAB *)dbenv->lk_handle);	return (ret);}static int__lock_get_internal(lt, locker, flags, obj, lock_mode, timeout, lock)	DB_LOCKTAB *lt;	u_int32_t locker, flags;	const DBT *obj;	db_lockmode_t lock_mode;	db_timeout_t timeout;	DB_LOCK *lock;{	struct __db_lock *newl, *lp, *wwrite;	DB_ENV *dbenv;	DB_LOCKER *sh_locker;	DB_LOCKOBJ *sh_obj;	DB_LOCKREGION *region;	u_int32_t locker_ndx, obj_ndx;	int did_abort, ihold, on_locker_list, no_dd, ret;	dbenv = lt->dbenv;	region = lt->reginfo.primary;	on_locker_list = no_dd = ret = 0;	/* Check if locks have been globally turned off. */	if (F_ISSET(dbenv, DB_ENV_NOLOCKING))		return (0);	/*	 * If we are not going to reuse this lock, initialize the offset to	 * invalid so that if we fail it will not look like a valid lock.	 */	if (!LF_ISSET(DB_LOCK_UPGRADE | DB_LOCK_SWITCH))		LOCK_INIT(*lock);	/* Check that the lock mode is valid.  */	if ((u_int32_t)lock_mode >= region->stat.st_nmodes) {		__db_err(dbenv, "DB_ENV->lock_get: invalid lock mode %lu",		    (u_long)lock_mode);		return (EINVAL);	}	/* Allocate a new lock.  Optimize for the common case of a grant. */	region->stat.st_nrequests++;	if ((newl = SH_TAILQ_FIRST(&region->free_locks, __db_lock)) != NULL)		SH_TAILQ_REMOVE(&region->free_locks, newl, links, __db_lock);	if (newl == NULL) {		__db_err(dbenv, __db_lock_err, "locks");		return (ENOMEM);	}	if (++region->stat.st_nlocks > region->stat.st_maxnlocks)		region->stat.st_maxnlocks = region->stat.st_nlocks;	if (obj == NULL) {		DB_ASSERT(LOCK_ISSET(*lock));		lp = (struct __db_lock *)R_ADDR(&lt->reginfo, lock->off);		sh_obj = (DB_LOCKOBJ *) ((u_int8_t *)lp + lp->obj);	} else {		/* Allocate a shared memory new object. */		OBJECT_LOCK(lt, region, obj, lock->ndx);		if ((ret = __lock_getobj(lt, obj, lock->ndx, 1, &sh_obj)) != 0)			goto err;	}	/* Get the locker, we may need it to find our parent. */	LOCKER_LOCK(lt, region, locker, locker_ndx);	if ((ret = __lock_getlocker(lt, locker,	    locker_ndx, locker > DB_LOCK_MAXID ? 1 : 0, &sh_locker)) != 0) {		/*		 * XXX We cannot tell if we created the object or not,		 * so we don't kow if we should free it or not.		 */		goto err;	}	if (sh_locker == NULL) {		__db_err(dbenv, "Locker does not exist");		ret = EINVAL;		goto err;	}	/*	 * Now we have a lock and an object and we need to see if we should	 * grant the lock.  We use a FIFO ordering so we can only grant a	 * new lock if it does not conflict with anyone on the holders list	 * OR anyone on the waiters list.  The reason that we don't grant if	 * there's a conflict is that this can lead to starvation (a writer	 * waiting on a popularly read item will never be granted).  The	 * downside of this is that a waiting reader can prevent an upgrade	 * from reader to writer, which is not uncommon.	 *	 * There is one exception to the no-conflict rule.  If a lock is held	 * by the requesting locker AND the new lock does not conflict with	 * any other holders, then we grant the lock.  The most common place	 * this happens is when the holder has a WRITE lock and a READ lock	 * request comes in for the same locker.  If we do not grant the read	 * lock, then we guarantee deadlock.	 *	 * In case of conflict, we put the new lock on the end of the waiters	 * list, unless we are upgrading in which case the locker goes on the	 * front of the list.	 */	ihold = 0;	lp = NULL;	if (LF_ISSET(DB_LOCK_SWITCH))		goto put_lock;	wwrite = NULL;	for (lp = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock);	    lp != NULL;	    lp = SH_TAILQ_NEXT(lp, links, __db_lock)) {		if (locker == lp->holder) {			if (lp->mode == lock_mode &&			    lp->status == DB_LSTAT_HELD) {				if (LF_ISSET(DB_LOCK_UPGRADE))					goto upgrade;				/*				 * Lock is held, so we can increment the				 * reference count and return this lock.				 * We do not count reference increments				 * towards the locks held by the locker.				 */				lp->refcount++;				lock->off = R_OFFSET(&lt->reginfo, lp);				lock->gen = lp->gen;				lock->mode = lp->mode;				ret = 0;				goto done;			} else {				ihold = 1;				if (lock_mode == DB_LOCK_WRITE &&				    lp->mode == DB_LOCK_WWRITE)					wwrite = lp;			}		} else if (__lock_is_parent(lt, lp->holder, sh_locker))			ihold = 1;		else if (CONFLICTS(lt, region, lp->mode, lock_mode))			break;	}	/*	 * If we are looking to upgrade a WWRITE to a WRITE lock	 * and there were no conflicting locks then we can just	 * upgrade this lock to the one we want.	 */	if (wwrite != NULL && lp == NULL) {		lp = wwrite;		lp->mode = lock_mode;		lp->refcount++;		lock->off = R_OFFSET(&lt->reginfo, lp);		lock->gen = lp->gen;		lock->mode = lp->mode;		ret = 0;		goto done;	}	/*	 * Make the new lock point to the new object, initialize fields.	 *	 * This lock is not linked in anywhere, so we can muck with it	 * without holding any mutexes.	 */put_lock:	newl->holder = locker;	newl->refcount = 1;	newl->mode = lock_mode;	newl->obj = SH_PTR_TO_OFF(newl, sh_obj);	newl->status = DB_LSTAT_HELD;	/*	 * If we are upgrading, then there are two scenarios.  Either	 * we had no conflicts, so we can do the upgrade.  Or, there	 * is a conflict and we should wait at the HEAD of the waiters	 * list.	 */	if (LF_ISSET(DB_LOCK_UPGRADE)) {		if (lp == NULL)			goto upgrade;		/*		 * There was a conflict, wait.  If this is the first waiter,		 * add the object to the deadlock detector's list.		 */		if (SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock) == NULL)			SH_TAILQ_INSERT_HEAD(&region->dd_objs,			    sh_obj, dd_links, __db_lockobj);		SH_TAILQ_INSERT_HEAD(&sh_obj->waiters, newl, links, __db_lock);		goto llist;	}	if (lp == NULL && !ihold)		for (lp = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock);		    lp != NULL;		    lp = SH_TAILQ_NEXT(lp, links, __db_lock)) {			if (CONFLICTS(lt, region, lp->mode, lock_mode) &&			    locker != lp->holder)				break;		}	if (!LF_ISSET(DB_LOCK_SWITCH) && lp == NULL)		SH_TAILQ_INSERT_TAIL(&sh_obj->holders, newl, links);	else if (!LF_ISSET(DB_LOCK_NOWAIT)) {		/*		 * If this is the first waiter, add the object to the		 * deadlock detector's list.		 */		if (SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock) == NULL)			SH_TAILQ_INSERT_HEAD(&region->dd_objs,			    sh_obj, dd_links, __db_lockobj);		SH_TAILQ_INSERT_TAIL(&sh_obj->waiters, newl, links);	} else {		ret = DB_LOCK_NOTGRANTED;		if (SH_LIST_FIRST(&sh_locker->heldby, __db_lock) == NULL &&		    LF_ISSET(DB_LOCK_FREE_LOCKER))			__lock_freelocker(lt, region, sh_locker, locker_ndx);		region->stat.st_nnowaits++;		goto err;	}llist:	/*	 * Now, insert the lock onto its locker's list.  If the locker does	 * not currently hold any locks, there's no reason to run a deadlock	 * detector, save that information.	 */	on_locker_list = 1;	no_dd = sh_locker->master_locker == INVALID_ROFF &&	    SH_LIST_FIRST(&sh_locker->child_locker, __db_locker) == NULL &&	    SH_LIST_FIRST(&sh_locker->heldby, __db_lock) == NULL;	SH_LIST_INSERT_HEAD(&sh_locker->heldby, newl, locker_links, __db_lock);	if (LF_ISSET(DB_LOCK_SWITCH) || lp != NULL) {		if (LF_ISSET(DB_LOCK_SWITCH) &&		    (ret = __lock_put_nolock(dbenv,		    lock, &ihold, DB_LOCK_NOWAITERS)) != 0)			goto err;		/*		 * This is really a blocker for the thread.  It should be		 * initialized locked, so that when we try to acquire it, we		 * block.		 */		newl->status = DB_LSTAT_WAITING;		region->stat.st_nconflicts++;		region->need_dd = 1;		/*		 * First check to see if this txn has expired.		 * If not then see if the lock timeout is past		 * the expiration of the txn, if it is, use		 * the txn expiration time.  lk_expire is passed		 * to avoid an extra call to get the time.		 */		if (__lock_expired(dbenv,		    &sh_locker->lk_expire, &sh_locker->tx_expire)) {			newl->status = DB_LSTAT_ABORTED;			region->stat.st_ndeadlocks++;			region->stat.st_ntxntimeouts++;			/*			 * Remove the lock from the wait queue and if			 * this was the only lock on the wait queue remove			 * this object from the deadlock detector object			 * list.			 */			SH_LIST_REMOVE(newl, locker_links, __db_lock);			SH_TAILQ_REMOVE(			    &sh_obj->waiters, newl, links, __db_lock);			if (SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock) == NULL)				SH_TAILQ_REMOVE(&region->dd_objs,				    sh_obj, dd_links, __db_lockobj);			/* Clear the timeout, we are done. */			LOCK_SET_TIME_INVALID(&sh_locker->tx_expire);			goto expired;		}		/*		 * If a timeout was specified in this call then it		 * takes priority.  If a lock timeout has been specified		 * for this transaction then use that, otherwise use		 * the global timeout value.		 */		if (!LF_ISSET(DB_LOCK_SET_TIMEOUT)) {			if (F_ISSET(sh_locker, DB_LOCKER_TIMEOUT))				timeout = sh_locker->lk_timeout;			else				timeout = region->lk_timeout;		}		if (timeout != 0)			__lock_expires(dbenv, &sh_locker->lk_expire, timeout);		else			LOCK_SET_TIME_INVALID(&sh_locker->lk_expire);		if (LOCK_TIME_ISVALID(&sh_locker->tx_expire) &&			(timeout == 0 || __lock_expired(dbenv,			    &sh_locker->lk_expire, &sh_locker->tx_expire)))				sh_locker->lk_expire = sh_locker->tx_expire;		UNLOCKREGION(dbenv, (DB_LOCKTAB *)dbenv->lk_handle);		/*		 * We are about to wait; before waiting, see if the deadlock		 * detector should be run.		 */		if (region->detect != DB_LOCK_NORUN && !no_dd)			(void)dbenv->lock_detect(			    dbenv, 0, region->detect, &did_abort);		MUTEX_LOCK(dbenv, &newl->mutex);		LOCKREGION(dbenv, (DB_LOCKTAB *)dbenv->lk_handle);expired:	/* Turn off lock timeout. */		LOCK_SET_TIME_INVALID(&sh_locker->lk_expire);		if (newl->status != DB_LSTAT_PENDING) {			(void)__lock_checklocker(lt, newl, newl->holder, 0);			switch (newl->status) {				case DB_LSTAT_ABORTED:					on_locker_list = 0;					ret = DB_LOCK_DEADLOCK;					break;				case DB_LSTAT_NOTEXIST:					ret = DB_LOCK_NOTEXIST;					break;				case DB_LSTAT_EXPIRED:					SHOBJECT_LOCK(lt,					    region, sh_obj, obj_ndx);					if ((ret = __lock_put_internal(					    lt, newl, obj_ndx, 0) != 0))						goto err;					if (LOCK_TIME_EQUAL(					    &sh_locker->lk_expire,					    &sh_locker->tx_expire)) {						region->stat.st_ndeadlocks++;						region->stat.st_ntxntimeouts++;						return (DB_LOCK_DEADLOCK);					} else {						region->stat.st_nlocktimeouts++;						return (DB_LOCK_NOTGRANTED);					}				default:					ret = EINVAL;					break;			}			goto err;		} else if (LF_ISSET(DB_LOCK_UPGRADE)) {			/*			 * The lock that was just granted got put on the			 * holders list.  Since we're upgrading some other			 * lock, we've got to remove it here.			 */			SH_TAILQ_REMOVE(			    &sh_obj->holders, newl, links, __db_lock);			/*			 * Ensure that the object is not believed to be on			 * the object's lists, if we're traversing by locker.			 */			newl->links.stqe_prev = -1;			goto upgrade;		} else			newl->status = DB_LSTAT_HELD;	}	lock->off = R_OFFSET(&lt->reginfo, newl);	lock->gen = newl->gen;	lock->mode = newl->mode;	sh_locker->nlocks++;	if (IS_WRITELOCK(newl->mode))		sh_locker->nwrites++;	return (0);upgrade:/*	 * This was an upgrade, so return the new lock to the free list and	 * upgrade the mode of the original lock.	 */	lp = (struct __db_lock *)R_ADDR(&lt->reginfo, lock->off);	if (IS_WRITELOCK(lock_mode) && !IS_WRITELOCK(lp->mode))		sh_locker->nwrites++;	lp->mode = lock_mode;	ret = 0;	/* FALLTHROUGH */done:err:	newl->status = DB_LSTAT_FREE;	region->stat.st_nlocks--;	if (on_locker_list) {		SH_LIST_REMOVE(newl, locker_links, __db_lock);	}	SH_TAILQ_INSERT_HEAD(&region->free_locks, newl, links, __db_lock);	return (ret);}/* * Lock release routines. * * The user callable one is lock_put and the three we use internally are * __lock_put_nolock, __lock_put_internal and __lock_downgrade. * * PUBLIC: int  __lock_put __P((DB_ENV *, DB_LOCK *)); */int__lock_put(dbenv, lock)	DB_ENV *dbenv;	DB_LOCK *lock;{	DB_LOCKTAB *lt;	int ret, run_dd;	PANIC_CHECK(dbenv);	ENV_REQUIRES_CONFIG(dbenv,	    dbenv->lk_handle, "DB_LOCK->lock_put", DB_INIT_LOCK);	if (IS_RECOVERING(dbenv))		return (0);	lt = dbenv->lk_handle;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -