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

📄 mpid_win_lock.c

📁 fortran并行计算包
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  (C)Copyright IBM Corp.  2007, 2008  *//** * \file src/onesided/mpid_win_lock.c * \brief MPI-DCMF MPI_Win_lock/unlock functionality */#include "mpid_onesided.h"/** * \brief Progress (advance) spin to acquire lock locally * * Adds a local waiter to the lock wait queue, to ensure that * we will eventually get a chance. This special waiter (ack[0].w0 == 0) * will result in the \e my_sync_done flag getting set, breaking us * out of the loop. At this point, we will have acquired the lock * (possibly shared with others). * * Called from MPID_Win_lock when the \e dest rank is ourself (local). * * \param[in] win	Pointer to MPID_Win object * \param[in] rank	Our rank (convenience) * \param[in] type	Lock type * \return nothing */#define MPIDU_Spin_lock_acquire(win, rank, type) {		\        if (local_lock(win, rank, type) == 0) {			\                (win)->_dev.my_sync_done = 0;			\                MPIDU_add_waiter(win, rank, type, NULL);	\                MPIDU_Progress_spin((win)->_dev.my_sync_done == 0);\        }							\}/* * * * * * Win Locks and Lock wait queue * * * * * *//** * \page lock_wait_design Lock Wait Queue Design * * When a lock cannot be immediately granted, the caller * specifics (rank, lock request type, DCMF ack info) is added * to the bottom of the lock wait queue. A lock may not be * granted for the following reasons: * * - Window is involved in some other type of epoch. * - Lock is in an incompatible state with request type. * - Lock and request are shared, but the lock wait queue * is not empty. This request must be queued to avoid * starvation of the waiter(s). * * When ever a lock is released, the top of the lock wait queue * is examined to see if the waiter is requesting a lock type * that is compatible with the current lock status. * * - Lock is free: any waiter can be granted * - Lock is shared: only a share waiter can be granted * - Lock is exclusive: no waiter can be granted * - Waiter is "dummy" requesting lock type 0, in which case * subsequent waiters are left waiting so that another type * of epoch can begin. * * The third case cannot happen since an unlock cannot result * in the lock (still) being locked exclusive. * * The second case would probably only find a waiter of type * exclusive, since any shared requests that came along would * have been granted. * * \ref unlk_wait_design *//** * \brief Shortcut for accessing the lock waiter queue * object in the window structure. */#define MPIDU_WIN_LOCK_QUEUE(w) ((struct mpid_qhead *)(w)->_dev._lock_queue)/** \brief Test whether lock queue has no waiters */#define MPIDU_LOCK_QUEUE_EMPTY(w) \        (MPIDU_WIN_LOCK_QUEUE(w)->blocks == NULL ||	\        MPIDU_WIN_LOCK_QUEUE(w)->blocks->next_used == NULL)/** \brief Test if lock is unlocked */#define MPID_LOCK_IS_FREE(w)	((w)->_dev.lock_granted == 0)/** \brief Test if lock is locked exclusive */#define MPID_LOCK_IS_EXCL(w)	((w)->_dev.lock_granted & INT_MSB)/** \brief Test if lock is locked shared */#define MPID_LOCK_IS_SHARE(w)	((w)->_dev.lock_granted &&	\                                !((w)->_dev.lock_granted & INT_MSB))/** \brief Test if lock is locked exclusive by rank 'r' */#define MPID_LOCK_ISMY_EXCL(w, r)	\                                ((w)->_dev.lock_granted == ((r) | INT_MSB))/** \brief Test if lock is locked shared by rank 'r' \note Can't tell who's locked shared */#define MPID_LOCK_ISMY_SHARE(w, r)	\                                ((w)->_dev.lock_granted &&	\                                !((w)->_dev.lock_granted & INT_MSB))/** \brief Test if lock is OK to lock exclusive */#define MPID_LOCK_OK_EXCL(w)	((w)->_dev.lock_granted == 0)/** \brief Test if lock is OK to lock shared */#define MPID_LOCK_OK_SHARE(w)	(!((w)->_dev.lock_granted & INT_MSB))/** \brief Lock the lock in exclusive mode */#define MPID_LOCK_EXCL(w, r)	((w)->_dev.lock_granted = (r) | INT_MSB)/** \brief Unlock the lock (from exclusive mode) */#define MPID_UNLOCK_EXCL(w, r)	((w)->_dev.lock_granted = 0)/** \brief Lock the lock in shared mode */#define MPID_LOCK_SHARE(w, r)	(++(w)->_dev.lock_granted)/** \brief Unlock the lock (from shared mode) */#define MPID_UNLOCK_SHARE(w, r)	(--(w)->_dev.lock_granted)/** * \brief Examine local lock and return current lock type. * * \param[in] win	Window object containing lock in question * \return Lock type (status): *	- \e MPI_LOCK_EXCLUSIVE - locked in exclusive mode. *	- \e MPI_LOCK_SHARED - locked by one or more nodes in shared mode. *	- \e 0 - not locked. * * \ref rsrc_design\n * \ref lock_wait_design */static int local_lock_type(MPID_Win *win) {        MPID_assert_debug(MPI_LOCK_EXCLUSIVE != 0 &&                        MPI_LOCK_SHARED != 0);        if (MPID_LOCK_IS_FREE(win)) {                return 0;        } else if (MPID_LOCK_IS_EXCL(win)) {                return MPI_LOCK_EXCLUSIVE;        } else /* MPID_LOCK_IS_SHARE(win) */ {                return MPI_LOCK_SHARED;        }}/** * \brief Local lock routine. * * Called from lock receive callback. * Also sets epoch_rma_ok if lock is acquired. * * \param[in] win	Pointer to MPID_Win structure * \param[in] orig	Rank of origin (locker) * \param[in] type	Type of lock being requested * \return 1 if the lock was granted, or *	0 if the lock was refused (caller must wait). * * \ref lock_design\n * \ref rsrc_design\n * \ref lock_wait_design */static unsigned local_lock(MPID_Win *win, int orig, int type) {        if (type == MPI_LOCK_EXCLUSIVE) {                if (MPID_LOCK_OK_EXCL(win)) {                        MPID_LOCK_EXCL(win, orig);                        return 1;                }        } else /* type == MPI_LOCK_SHARED */ {                if (MPID_LOCK_OK_SHARE(win)) {                        MPID_LOCK_SHARE(win, orig);                        MPID_assert_debug(MPID_LOCK_OK_SHARE(win));                        return 1;                }        }        return 0;}/** * \brief Local unlock routine. * * Called from unlock receive callback. * Gets origin (unlocker) rank, (expected) lock type, and origin RMA * ops count (number of RMA ops that node originated to this node). * Returns -1 if the lock is not in appropriate state to be unlocked * (by the calling node and expected lock type). * Clears epoch_rma_ok if lock is released (completely - i.e. last * shared lock release). * * \param[in] win	Pointer to MPID_Win structure * \param[in] orig	Rank of origin (locker) * \return 1 if the lock was released, or *	0 if the lock was "busy". * * \ref lock_design\n * \ref rsrc_design\n * \ref lock_wait_design */static unsigned local_unlock(MPID_Win *win, int orig) {        MPID_assert_debug(!MPID_LOCK_IS_FREE(win));        if (MPID_LOCK_IS_EXCL(win)) {                MPID_UNLOCK_EXCL(win, orig);        } else if (MPID_LOCK_IS_SHARE(win)) {                MPID_UNLOCK_SHARE(win, orig);                MPID_assert_debug(MPID_LOCK_OK_SHARE(win));        }        return 1;}/** \brief Number of Lock Wait Queue elements per allocation block */#define MPIDU_NUM_ALLOC_WAITERS	7/** * \brief Lock Wait Queue Element * * \ref rsrc_design\n * \ref lock_wait_design */struct mpid_lock_waiter {        struct mpid_lock_waiter *next;	/**< next used or next free */        int waiter_rank;	/**< rank requesting lock */        int lock_type;		/**< lock type requested */        int *_pad;		/**< pad to even fraction of cacheline */        MPIDU_Onesided_ctl_t ackinfo;	/**< dcmf context (opaque) info.                                 * Not directly used in communications. */};/** \brief Padding for  Lock Wait Queue Element resource block header */#define MPIDU_PAD_ALLOC_WAITERS	\(sizeof(struct mpid_lock_waiter) - sizeof(struct mpid_resource))/** * \brief Setup a lock wait queue entry. * * Adds a new waiter to the (end of the) wait queue. * Saves rank, type, and ackinfo in the wait object. * Typically called from lock receive callback. * * A lock type of 0 (none) is used as a "break-point" to * ensure non-lock epoch starts will eventually succeed. * * \param[in] win	Pointer to MPID_Win structure * \param[in] rank	Rank of origin (locker) * \param[in] type	Type of lock being requested * \param[in] ackinfo	Additional info to save on queue (may be NULL) * \return nothing * * \ref rsrc_design\n * \ref lock_wait_design */static void MPIDU_add_waiter(MPID_Win *win, int rank, int type,                                        MPIDU_Onesided_ctl_t *ackinfo) {        struct mpid_lock_waiter wp;        wp.waiter_rank = rank;        wp.lock_type = type;        if (ackinfo) {                wp.ackinfo = *ackinfo;        } else {                memset(&wp.ackinfo, 0, sizeof(wp.ackinfo));        }        (void)MPIDU_add_element(MPIDU_WIN_LOCK_QUEUE(win), &wp);}/** * \brief Conditionally pops next waiter off lock wait queue. * * Returns the next waiter on the window lock, provided its desired * lock type is compatible with the current lock status. * Fills in rank, type, and ackinfo with pertinent data, * on success. Called by unlock (recv callback). If lock status * (after the unlock) is (still) shared, then the next waiter must * want shared (probably not a likely scenario since it should have * been granted the lock when requested). However, this check ensures * that an exclusive lock waiter cannot grab a lock that is still in * shared mode. Typically called from unlock receive callback. * * \param[in] win	Pointer to MPID_Win structure * \param[out] rank	Rank of origin (locker) * \param[out] type	Type of lock being requested * \param[out] ackinfo	Additional info from original lock call (may be NULL) * \return 0 if lock waiter was popped, or *	1 if the queue was empty or next waiter incompatible * * \ref lock_design\n * \ref rsrc_design\n * \ref lock_wait_design */static int MPIDU_pop_waiter(MPID_Win *win, int *rank, int *type,                                        MPIDU_Onesided_ctl_t *ackinfo) {        struct mpid_lock_waiter wp;        struct mpid_resource *lq = MPIDU_WIN_LOCK_QUEUE(win)->blocks;        int lt;        if (lq == NULL || lq->next_used == NULL) {                return 1; /* no one waiting */        }        if (MPIDU_peek_element(MPIDU_WIN_LOCK_QUEUE(win), &wp)) {                return 1; /* no one waiting */        }        if (!rank && !type && wp.lock_type != 0) {                return 1;	/* not our marker... */        }        lt = local_lock_type(win);        if (lt == MPI_LOCK_EXCLUSIVE ||                        (lt != 0 && lt != wp.lock_type)) {                return 1; /* not a compatible waiter */        }        (void)MPIDU_pop_element(MPIDU_WIN_LOCK_QUEUE(win), NULL);        if (rank) {                *rank = wp.waiter_rank;        }        if (type) {                *type = wp.lock_type;        }        if (ackinfo) {                *ackinfo = wp.ackinfo;        }        return 0;

⌨️ 快捷键说明

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