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

📄 mpid_win_lock.c

📁 fortran并行计算包
💻 C
📖 第 1 页 / 共 3 页
字号:
}/** * \brief Progress (advance) wait for window lock to be released * * Adds a dummy waiter to the lock wait queue, so ensure that * unlock will eventually give us a chance. * * Called from various epoch-start code to ensure no other node is * accessing our window while we are in another epoch. * * \todo Probably sohuld assert that the popped waiter, * if any, was our NULL one. * * \param[in] win       Pointer to MPID_Win object * \return nothing */void MPIDU_Spin_lock_free(MPID_Win *win) {        MPIDU_add_waiter(win, 0, 0, NULL);        MPIDU_Progress_spin(!MPID_LOCK_IS_FREE(win));        MPIDU_pop_waiter(win, NULL, NULL, NULL);}int MPIDU_is_lock_free(MPID_Win *win) {        return MPID_LOCK_IS_FREE(win);}/* * * * * * Unlock wait queue * * * * * *//** * \page unlk_wait_design Unlock Wait Queue Design * * The Unlock Wait Queue is used to delay unlocking of a * window until all outstanding RMA operations have completed. * * Each unlock request includes the number of RMA operations * that were initiated by that origin. When the unlock is attempted, * this number is compared to the count of RMA ops received from that * origin and if the numbers do not match the unlock request is queued. * * Whenever an RMA operation is processed, the routine \e rma_recvs_cb() * is called and the unlock wait queue is checked for an entry from that * origin node, and that the counts now match. If so, the unlock is dequeued * and the lock released (acknowledge message sent to origin). * * Note that this unlock may include granting of the lock to other * nodes (i.e. processing of the lock wait queue). * * \ref lock_wait_design *//** * \brief Shortcut for accessing the lock waiter queue * object in the window structure. */#define MPIDU_WIN_UNLK_QUEUE(w) ((struct mpid_qhead *)(w)->_dev._unlk_queue)/** \brief Number of Unlock Wait Queue elements per allocation block */#define MPIDU_NUM_UNLK_ENTRIES	7/** * \brief Unlock Wait Queue Element */struct mpid_unlk_entry {        struct mpid_unlk_entry *next;	/**< next used or next free */        int rank;		/**< origin rank (unlocker) */        int rmas;		/**< number of rmas sent by origin */        int _pad;		/**< pad to power of 2 size */};/** \brief Padding for Datatype Cache Element resource block header */#define MPIDU_PAD_UNLK_ENTRIES	0void mpidu_init_lock(MPID_Win *win) {        MPIDU_INIT_QHEAD(MPIDU_WIN_LOCK_QUEUE(win),                MPIDU_NUM_ALLOC_WAITERS,                sizeof(struct mpid_lock_waiter),                MPIDU_PAD_ALLOC_WAITERS);        MPIDU_INIT_QHEAD(MPIDU_WIN_UNLK_QUEUE(win),                MPIDU_NUM_UNLK_ENTRIES,                sizeof(struct mpid_unlk_entry),                MPIDU_PAD_UNLK_ENTRIES);}void mpidu_free_lock(MPID_Win *win) {        MPID_assert_debug(MPIDU_WIN_LOCK_QUEUE(win)->blocks == NULL ||                MPIDU_WIN_LOCK_QUEUE(win)->blocks->next_used == NULL);        MPIDU_free_resource(MPIDU_WIN_LOCK_QUEUE(win));        MPIDU_free_resource(MPIDU_WIN_UNLK_QUEUE(win));}/** * \brief Callback function to match unlock wait queue entry * * 'v1' is a struct mpid_unlk_entry with rank and rmas filled in with *      desired origin rank and current RMA ops count from origin. * 'v2' is the (currrent) struct mpid_unlk_entry being examined as *      a potential match. * * Returns success (match) if an unlock element exists with origin rank * and the expected RMA ops count from that rank has been reached. * * \param[in] v1	Desired unlock queue pseudo-element * \param[in] v2	Unlock queue element to compare with 'v1' * \param[in] v3	not used * \return boolean indicating if 'v2' matches 'v1'. * * \ref unlk_wait_design */static int mpid_match_unlk(void *v1, void *v2, void *v3) {        struct mpid_unlk_entry *w1 = (struct mpid_unlk_entry *)v1;        struct mpid_unlk_entry *w2 = (struct mpid_unlk_entry *)v2;        return (w1->rank != w2->rank || w1->rmas < w2->rmas);}/** * \brief Locate the desired unlocker if it is waiting * * Does not return success unless the RMA ops counters match. * * \param[in] win	Pointer to window * \param[in] rank	Origin rank (unlocker) * \param[out] ctl	Reconstructed UNLOCK message, if unlocker found * * \ref unlk_wait_design * \ref msginfo_usage */static struct mpid_unlk_entry *MPIDU_locate_unlk(MPID_Win *win, int rank, MPIDU_Onesided_ctl_t *ctl) {        struct mpid_unlk_entry el, *ep;        struct mpid_element *pp = NULL;        el.rank = rank;        el.rmas = win->_dev.coll_info[rank].rma_sends;        ep = MPIDU_find_element(MPIDU_WIN_UNLK_QUEUE(win), mpid_match_unlk, NULL, &el, &pp);        if (ep) {                if (ctl) {                        ctl->mpid_ctl_w0 = MPID_MSGTYPE_UNLOCK;                        ctl->mpid_ctl_w1 = win->handle;                        ctl->mpid_ctl_w2 = ep->rank;                        ctl->mpid_ctl_w3 = ep->rmas;                }                MPIDU_free_element(MPIDU_WIN_UNLK_QUEUE(win), ep, pp);        }        return ep;}/** * \brief Add an (unsuccessful) unlocker to the wait queue * * Decomposes the UNLOCK message to save needed data. * * \param[in] win	Pointer to window * \param[in] rank	Origin rank (unlocker) * \param[in] ctl	UNLOCK message * * \ref unlk_wait_design * \ref msginfo_usage */static void MPIDU_add_unlk(MPID_Win *win, int rank, const MPIDU_Onesided_ctl_t *ctl) {        struct mpid_unlk_entry wp;        MPID_assert_debug(ctl != NULL);        MPID_assert_debug(rank == ctl->mpid_ctl_w2);        wp.rank = rank;        wp.rmas = ctl->mpid_ctl_w3;        (void)MPIDU_add_element(MPIDU_WIN_UNLK_QUEUE(win), &wp);}/** * \brief Callback invoked to count an RMA operation received * * Increments window's \e my_rma_recvs counter. * If window lock is held, then also increment RMA counter * for specific origin node, and check whether this RMA op * completes the epoch and an unlock is waiting to be processed. * * We use \e rma_sends to count received RMA ops because we * know we won't be using that to count sent RMA ops since * we cannot be in an access epoch while in a LOCK exposure epoch. * * Called from both the "long message" completion callbacks and * the "short message" receive callback, in case of PUT or * ACCUMULATE only. * * \param[in] win	Pointer to MPID_Win object * \param[in] orig	Rank of originator of RMA operation * \param[in] lpid	lpid of originator of RMA operation * \return nothing */void rma_recvs_cb(MPID_Win *win, int orig, int lpid) {        ++win->_dev.my_rma_recvs;        if (!MPID_LOCK_IS_FREE(win)) {                struct mpid_unlk_entry *ep;                MPIDU_Onesided_ctl_t ctl;                ++win->_dev.coll_info[orig].rma_sends;                ep = MPIDU_locate_unlk(win, orig, &ctl);                if (ep) {                        unlk_cb(&ctl, lpid);                }        }}/** * \brief Lock receive callback. * * Attempts to acquire the lock. * On success, sends ACK to origin. * On failure to acquire lock, * adds caller to lock wait queue. * * Does not attempt to acquire lock (counted as failure) * if window is currently in some other epoch. * * \param[in] info	Pointer to msginfo from origin (locker) * \param[in] lpid	lpid of origin node (locker) * \return nothing * * \ref msginfo_usage\n * \ref lock_design */void lock_cb(const MPIDU_Onesided_ctl_t *info, int lpid){        MPID_Win *win;        int ret;        int orig, type;        MPIDU_Onesided_ctl_t ack;        MPID_assert_debug(info->mpid_ctl_w0 == MPID_MSGTYPE_LOCK);        MPID_Win_get_ptr((MPI_Win)info->mpid_ctl_w1, win);        MPID_assert_debug(win != NULL);        orig = info->mpid_ctl_w2;        type = info->mpid_ctl_w3;        ack.mpid_ctl_w0 = MPID_MSGTYPE_LOCKACK;        ack.mpid_ctl_w1 = win->_dev.coll_info[orig].win_handle;        ack.mpid_ctl_w2 = lpid;        ack.mpid_ctl_w3 = 0;        ret = (win->_dev.epoch_type == MPID_EPOTYPE_NONE &&                                        local_lock(win, orig, type));        if (!ret) {                MPIDU_add_waiter(win, orig, type, &ack);        } else {                win->_dev.epoch_rma_ok = 1;                (void) DCMF_Control(&bg1s_ct_proto, win->_dev.my_cstcy, lpid, &ack.ctl);        }}/** * \brief Epoch End callback. * * Called whenever epoch_type is set to MPID_EPOTYPE_NONE, i.e. an * access/exposure epoch ends. Also called when the window lock is * released (by the origin node). * * This is used to prevent locks from being acquired while some other * access/exposure epoch is active on a window, and queues the lock * attempt until such time as the epoch has ended. * * \param[in] win	Pointer to MPID_Win whose epoch has ended */void epoch_end_cb(MPID_Win *win) {        int rank, type, lpid;        MPIDU_Onesided_ctl_t info;        int ret;        /*         * Wake up any waiting lockers.         *         * This works in the case of a shared-lock release when not all         * lockers have released (no compatible waiter will be found).         *         * This also works in the case of non-lock epochs ending.         *         * An epoch-start call will spin waiting for lock to be released.         * Before spinning, it will queue a waiter with lock type 0 (none),         * so that this loop will not block progress indefinitely.         */        while (MPIDU_pop_waiter(win, &rank, &type, &info) == 0 &&                                                        type != 0) {                /* compatible waiter found */                ret = local_lock(win, rank, type);                MPID_assert_debug(ret != 0);                if (info.mpid_ctl_w0 == 0) {	/* local request */                        ++win->_dev.my_sync_done;                } else {                        win->_dev.epoch_rma_ok = 1;                        lpid = info.mpid_ctl_w2;                        (void) DCMF_Control(&bg1s_ct_proto, win->_dev.my_cstcy, lpid, &info.ctl);                }        }}/** * \brief Unlock receive callback. * * Attempts to release the lock. * If the lock cannot be released (due to outstanding RMA ops not * yet received) then the unlocker is placed on a queue where its * request will be re-evaluated when RMA ops are received. * If lock can be released, any lock waiters are woken up in * \e epoch_end_cb() and an MPID_MSGTYPE_UNLOCKACK is sent to the unlocker. * * \param[in] info	Pointer to msginfo from origin (unlocker) * \param[in] lpid	lpid of origin node (unlocker) * \return nothing

⌨️ 快捷键说明

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