示例#1
0
static int psmx2_domain_close(fid_t fid)
{
	struct psmx2_fid_domain *domain;

	domain = container_of(fid, struct psmx2_fid_domain,
			      util_domain.domain_fid.fid);

	FI_INFO(&psmx2_prov, FI_LOG_DOMAIN, "refcnt=%d\n",
		ofi_atomic_get32(&domain->util_domain.ref));

	if (ofi_domain_close(&domain->util_domain))
		return 0;

	if (domain->progress_thread_enabled)
		psmx2_domain_stop_progress(domain);

	fastlock_destroy(&domain->sep_lock);
	fastlock_destroy(&domain->mr_lock);
	rbtDelete(domain->mr_map);

	psmx2_lock(&domain->fabric->domain_lock, 1);
	dlist_remove(&domain->entry);
	psmx2_unlock(&domain->fabric->domain_lock, 1);
	psmx2_fabric_release(domain->fabric);

	free(domain);
	return 0;
}
示例#2
0
static int psmx2_domain_close(fid_t fid)
{
	struct psmx2_fid_domain *domain;

	domain = container_of(fid, struct psmx2_fid_domain,
			      util_domain.domain_fid.fid);

	FI_INFO(&psmx2_prov, FI_LOG_DOMAIN, "refcnt=%d\n",
		ofi_atomic_get32(&domain->util_domain.ref));

	psmx2_domain_release(domain);

	if (ofi_domain_close(&domain->util_domain))
		return 0;

	if (domain->progress_thread_enabled)
		psmx2_domain_stop_progress(domain);

	fastlock_destroy(&domain->sep_lock);

	fastlock_destroy(&domain->vl_lock);
	rbtDelete(domain->mr_map);
	fastlock_destroy(&domain->mr_lock);

	psmx2_trx_ctxt_free(domain->base_trx_ctxt);
	domain->fabric->active_domain = NULL;
	free(domain);

	psmx2_atomic_global_fini();
	psmx2_am_global_fini();
	return 0;
}
示例#3
0
static int psmx2_fabric_close(fid_t fid)
{
	struct psmx2_fid_fabric *fabric;

	fabric = container_of(fid, struct psmx2_fid_fabric,
			      util_fabric.fabric_fid.fid);

	psmx2_fabric_release(fabric);

	FI_INFO(&psmx2_prov, FI_LOG_CORE, "refcnt=%d\n",
		ofi_atomic_get32(&fabric->util_fabric.ref));

	if (ofi_fabric_close(&fabric->util_fabric))
		return 0;

	if (psmx2_env.name_server)
		ofi_ns_stop_server(&fabric->name_server);

	fastlock_destroy(&fabric->domain_lock);
	assert(fabric == psmx2_active_fabric);
	psmx2_active_fabric = NULL;
	free(fabric);

	psmx2_atomic_global_fini();
	return 0;
}
示例#4
0
static int util_eq_close(struct fid *fid)
{
	struct util_eq *eq;
	struct slist_entry *entry;
	struct util_event *event;

	eq = container_of(fid, struct util_eq, eq_fid.fid);
	if (ofi_atomic_get32(&eq->ref))
		return -FI_EBUSY;

	while (!slist_empty(&eq->list)) {
		entry = slist_remove_head(&eq->list);
		event = container_of(entry, struct util_event, entry);
		free(event);
	}

	if (eq->wait) {
		fi_poll_del(&eq->wait->pollset->poll_fid,
			    &eq->eq_fid.fid, 0);
		if (eq->internal_wait)
			fi_close(&eq->wait->wait_fid.fid);
	}

	fastlock_destroy(&eq->lock);
	ofi_atomic_dec32(&eq->fabric->ref);
	free(eq);
	return 0;
}
示例#5
0
static int
usdf_domain_close(fid_t fid)
{
	struct usdf_domain *udp;
	int ret;

	USDF_TRACE_SYS(DOMAIN, "\n");

	udp = container_of(fid, struct usdf_domain, dom_fid.fid);
	if (ofi_atomic_get32(&udp->dom_refcnt) > 0) {
		return -FI_EBUSY;
	}

	if (udp->dom_dev != NULL) {
		ret = usd_close(udp->dom_dev);
		if (ret != 0) {
			return ret;
		}
	}
	usdf_dom_rdc_free_data(udp);

	if (udp->dom_eq != NULL) {
		ofi_atomic_dec32(&udp->dom_eq->eq_refcnt);
	}
	ofi_atomic_dec32(&udp->dom_fabric->fab_refcnt);
	LIST_REMOVE(udp, dom_link);
	fi_freeinfo(udp->dom_info);
	free(udp);

	return 0;
}
示例#6
0
static int psmx2_sep_close(fid_t fid)
{
	struct psmx2_fid_sep *sep;
	struct psmx2_ep_name ep_name;
	int i;

	sep = container_of(fid, struct psmx2_fid_sep, ep.fid);

	if (ofi_atomic_get32(&sep->ref))
		return -FI_EBUSY;

	for (i = 0; i < sep->ctxt_cnt; i++) {
		if (sep->ctxts[i].ep && ofi_atomic_get32(&sep->ctxts[i].ep->ref))
			return -FI_EBUSY;
	}

	ep_name.epid = sep->ctxts[0].trx_ctxt->psm2_epid;
	ep_name.sep_id = sep->id;
	ep_name.type = sep->type;

	ofi_ns_del_local_name(&sep->domain->fabric->name_server,
			      &sep->service, &ep_name);

	for (i = 0; i < sep->ctxt_cnt; i++) {
		psmx2_lock(&sep->domain->trx_ctxt_lock, 1);
		dlist_remove(&sep->ctxts[i].trx_ctxt->entry);
		psmx2_unlock(&sep->domain->trx_ctxt_lock, 1);

		if (sep->ctxts[i].ep)
			psmx2_ep_close_internal(sep->ctxts[i].ep);

		psmx2_trx_ctxt_free(sep->ctxts[i].trx_ctxt);
	}

	psmx2_lock(&sep->domain->sep_lock, 1);
	dlist_remove(&sep->entry);
	psmx2_unlock(&sep->domain->sep_lock, 1);

	psmx2_domain_release(sep->domain);
	free(sep);
	return 0;
}
示例#7
0
static int psmx_domain_close(fid_t fid)
{
	struct psmx_fid_domain *domain;
	int err;

	domain = container_of(fid, struct psmx_fid_domain,
			      util_domain.domain_fid.fid);

	FI_INFO(&psmx_prov, FI_LOG_DOMAIN, "refcnt=%d\n",
		ofi_atomic_get32(&domain->util_domain.ref));

	psmx_domain_release(domain);

	if (ofi_domain_close(&domain->util_domain))
		return 0;

	if (domain->progress_thread_enabled)
		psmx_domain_stop_progress(domain);

	if (domain->am_initialized)
		psmx_am_fini(domain);

	fastlock_destroy(&domain->poll_lock);
	rbtDelete(domain->mr_map);
	fastlock_destroy(&domain->mr_lock);

#if 0
	/* AM messages could arrive after MQ is finalized, causing segfault
	 * when trying to dereference the MQ pointer. There is no mechanism
	 * to properly shutdown AM. The workaround is to keep MQ valid.
	 */
	psm_mq_finalize(domain->psm_mq);
#endif

	/* workaround for:
	 * Assertion failure at psm_ep.c:1059: ep->mctxt_master == ep
	 */
	sleep(psmx_env.delay);

	if (psmx_env.timeout)
		err = psm_ep_close(domain->psm_ep, PSM_EP_CLOSE_GRACEFUL,
				   (int64_t) psmx_env.timeout * 1000000000LL);
	else
		err = PSM_EP_CLOSE_TIMEOUT;

	if (err != PSM_OK)
		psm_ep_close(domain->psm_ep, PSM_EP_CLOSE_FORCE, 0);

	domain->fabric->active_domain = NULL;

	free(domain);
	return 0;
}
示例#8
0
int fi_wait_cleanup(struct util_wait *wait)
{
	int ret;

	if (ofi_atomic_get32(&wait->ref))
		return -FI_EBUSY;

	ret = fi_close(&wait->pollset->poll_fid.fid);
	if (ret)
		return ret;

	ofi_atomic_dec32(&wait->fabric->ref);
	return 0;
}
示例#9
0
int ofi_domain_close(struct util_domain *domain)
{
	if (ofi_atomic_get32(&domain->ref))
		return -FI_EBUSY;

	fastlock_acquire(&domain->fabric->lock);
	dlist_remove(&domain->list_entry);
	fastlock_release(&domain->fabric->lock);

	free(domain->name);
	fastlock_destroy(&domain->lock);
	ofi_atomic_dec32(&domain->fabric->ref);
	return 0;
}
示例#10
0
static int psmx2_stx_close(fid_t fid)
{
	struct psmx2_fid_stx *stx;

	stx = container_of(fid, struct psmx2_fid_stx, stx.fid);

	if (ofi_atomic_get32(&stx->ref))
		return -FI_EBUSY;

	psmx2_lock(&stx->domain->trx_ctxt_lock, 1);
	dlist_remove(&stx->tx->entry);
	psmx2_unlock(&stx->domain->trx_ctxt_lock, 1);

	psmx2_trx_ctxt_free(stx->tx);
	psmx2_domain_release(stx->domain);
	free(stx);
	return 0;
}
示例#11
0
ssize_t fi_ibv_send(struct fi_ibv_msg_ep *ep, struct ibv_send_wr *wr, size_t len,
		    int count, void *context)
{
	struct ibv_send_wr *bad_wr;
	int ret;

	assert(ep->scq);
	wr->num_sge = count;
	wr->wr_id = (uintptr_t) context;

	if (wr->send_flags & IBV_SEND_SIGNALED) {
		assert((wr->wr_id & ep->scq->wr_id_mask) != ep->scq->send_signal_wr_id);
		ofi_atomic_set32(&ep->unsignaled_send_cnt, 0);
	} else {
		if (VERBS_SIGNAL_SEND(ep)) {
			ret = fi_ibv_signal_send(ep, wr);
			if (ret)
				return ret;
		} else {
			ofi_atomic_inc32(&ep->unsignaled_send_cnt);

			if (ofi_atomic_get32(&ep->unsignaled_send_cnt) >=
					VERBS_SEND_COMP_THRESH(ep)) {
				ret = fi_ibv_reap_comp(ep);
				if (ret)
					return ret;
			}
		}
	}

	ret = ibv_post_send(ep->id->qp, wr, &bad_wr);
	switch (ret) {
	case ENOMEM:
		return -FI_EAGAIN;
	case -1:
		/* Deal with non-compliant libibverbs drivers which set errno
		 * instead of directly returning the error value */
		return (errno == ENOMEM) ? -FI_EAGAIN : -errno;
	default:
		return -ret;
	}
}
示例#12
0
/**
 * This function will return a block of id's starting at id through nids
 *
 * @param domain  gnix domain
 * @param nids    number of id's
 * @param id      if -1 return an id based on the counter and seed
 */
int _gnix_get_new_cdm_id_set(struct gnix_fid_domain *domain, int nids,
			     uint32_t *id)
{
	uint32_t cdm_id;
	int v;

	if (*id == -1) {
		v = ofi_atomic_add32(&gnix_id_counter, nids);
		cdm_id = ((domain->cdm_id_seed & 0xFFF) << 12) | v;
		*id = cdm_id;
	} else {
		/*
		 * asking for a block starting at a chosen base
		 * TODO: sanity check that requested base is reasonable
		 */
		if (*id <= ofi_atomic_get32(&gnix_id_counter))
			return -FI_ENOSPC;
		ofi_atomic_set32(&gnix_id_counter, (*(int *)id + nids));
	}
	return FI_SUCCESS;
}
示例#13
0
static int
usdf_fabric_close(fid_t fid)
{
	struct usdf_fabric *fp;
	int ret;
	void *rv;

	USDF_TRACE("\n");

	fp = fab_fidtou(fid);
	if (ofi_atomic_get32(&fp->fab_refcnt) > 0) {
		return -FI_EBUSY;
	}
	/* Tell progression thread to exit */
	fp->fab_exit = 1;

	free(fp->fab_attr.name);
	free(fp->fab_attr.prov_name);

	if (fp->fab_thread) {
		ret = usdf_fabric_wake_thread(fp);
		if (ret != 0) {
			return ret;
		}
		pthread_join(fp->fab_thread, &rv);
	}
	usdf_timer_deinit(fp);
	if (fp->fab_epollfd != -1) {
		close(fp->fab_epollfd);
	}
	if (fp->fab_eventfd != -1) {
		close(fp->fab_eventfd);
	}
	if (fp->fab_arp_sockfd != -1) {
		close(fp->fab_arp_sockfd);
	}

	free(fp);
	return 0;
}
示例#14
0
static int sock_cq_close(struct fid *fid)
{
	struct sock_cq *cq;

	cq = container_of(fid, struct sock_cq, cq_fid.fid);
	if (ofi_atomic_get32(&cq->ref))
		return -FI_EBUSY;

	if (cq->signal && cq->attr.wait_obj == FI_WAIT_MUTEX_COND)
		sock_wait_close(&cq->waitset->fid);

	ofi_rbfree(&cq->addr_rb);
	ofi_rbfree(&cq->cqerr_rb);
	ofi_rbfdfree(&cq->cq_rbfd);

	fastlock_destroy(&cq->lock);
	fastlock_destroy(&cq->list_lock);
	ofi_atomic_dec32(&cq->domain->ref);

	free(cq);
	return 0;
}
示例#15
0
static int psmx_ep_close(fid_t fid)
{
	struct psmx_fid_ep *ep;

	ep = container_of(fid, struct psmx_fid_ep, ep.fid);

	if (ep->base_ep) {
		ofi_atomic_dec32(&ep->base_ep->ref);
		return 0;
	}

	if (ofi_atomic_get32(&ep->ref))
		return -FI_EBUSY;

	ofi_ns_del_local_name(&ep->domain->fabric->name_server,
			      &ep->service, &ep->domain->psm_epid);
	psmx_domain_disable_ep(ep->domain, ep);
	psmx_domain_release(ep->domain);
	free(ep);

	return 0;
}
示例#16
0
static int fi_ibv_reap_comp(struct fi_ibv_msg_ep *ep)
{
	struct fi_ibv_wce *wce = NULL;
	int got_wc = 0;
	int ret = 0;

	fastlock_acquire(&ep->scq->lock);
	while (ofi_atomic_get32(&ep->comp_pending) > 0) {
		if (!wce) {
			wce = util_buf_alloc(ep->scq->wce_pool);
			if (!wce) {
				fastlock_release(&ep->scq->lock);
				return -FI_ENOMEM;
			}
			memset(wce, 0, sizeof(*wce));
		}
		ret = fi_ibv_poll_cq(ep->scq, &wce->wc);
		if (ret < 0) {
			VERBS_WARN(FI_LOG_EP_DATA,
				   "Failed to read completion for signaled send\n");
			util_buf_release(ep->scq->wce_pool, wce);
			fastlock_release(&ep->scq->lock);
			return ret;
		} else if (ret > 0) {
			slist_insert_tail(&wce->entry, &ep->scq->wcq);
			got_wc = 1;
			wce = NULL;
		}
	}
	if (wce)
		util_buf_release(ep->scq->wce_pool, wce);

	if (got_wc && ep->scq->channel)
		ret = fi_ibv_cq_signal(&ep->scq->cq_fid);

	fastlock_release(&ep->scq->lock);
	return ret;
}
示例#17
0
static int psmx2_ep_close(fid_t fid)
{
	struct psmx2_fid_ep *ep;
	struct psmx2_ep_name ep_name;
	struct psmx2_trx_ctxt *trx_ctxt;

	ep = container_of(fid, struct psmx2_fid_ep, ep.fid);

	if (ep->base_ep) {
		ofi_atomic_dec32(&ep->base_ep->ref);
		return 0;
	}

	if (ofi_atomic_get32(&ep->ref))
		return -FI_EBUSY;

	if (ep->stx)
		ofi_atomic_dec32(&ep->stx->ref);

	if (ep->rx) {
		ep_name.epid = ep->rx->psm2_epid;

		ofi_ns_del_local_name(&ep->domain->fabric->name_server,
				      &ep->service, &ep_name);
	}

	if (ep->rx) {
		psmx2_lock(&ep->domain->trx_ctxt_lock, 1);
		dlist_remove(&ep->rx->entry);
		psmx2_unlock(&ep->domain->trx_ctxt_lock, 1);
	}

	trx_ctxt = ep->rx;
	psmx2_ep_close_internal(ep);
	psmx2_trx_ctxt_free(trx_ctxt);
	return 0;
}
示例#18
0
static void
usdf_dom_rdc_free_data(struct usdf_domain *udp)
{
	struct usdf_rdm_connection *rdc;
	int i;

	if (udp->dom_rdc_hashtab != NULL) {

		pthread_spin_lock(&udp->dom_progress_lock);
		for (i = 0; i < USDF_RDM_HASH_SIZE; ++i) {
			rdc = udp->dom_rdc_hashtab[i];
			while (rdc != NULL) {
				usdf_timer_reset(udp->dom_fabric,
						rdc->dc_timer, 0);
				rdc = rdc->dc_hash_next;
			}
		}
		pthread_spin_unlock(&udp->dom_progress_lock);

		/* XXX probably want a timeout here... */
		while (ofi_atomic_get32(&udp->dom_rdc_free_cnt) <
		       (int)udp->dom_rdc_total) {
			pthread_yield();
		}

		free(udp->dom_rdc_hashtab);
		udp->dom_rdc_hashtab = NULL;
	}

	while (!SLIST_EMPTY(&udp->dom_rdc_free)) {
		rdc = SLIST_FIRST(&udp->dom_rdc_free);
		SLIST_REMOVE_HEAD(&udp->dom_rdc_free, dc_addr_link);
		usdf_timer_free(udp->dom_fabric, rdc->dc_timer);
		free(rdc);
	}
}
示例#19
0
static int sock_ep_close(struct fid *fid)
{
	struct sock_ep *sock_ep;
	char c = 0;

	switch (fid->fclass) {
	case FI_CLASS_EP:
		sock_ep = container_of(fid, struct sock_ep, ep.fid);
		break;

	case FI_CLASS_SEP:
		sock_ep = container_of(fid, struct sock_ep, ep.fid);
		break;

	default:
		return -FI_EINVAL;
	}

	if (sock_ep->is_alias) {
		ofi_atomic_dec32(&sock_ep->attr->ref);
		return 0;
	}
	if (ofi_atomic_get32(&sock_ep->attr->ref) ||
	    ofi_atomic_get32(&sock_ep->attr->num_rx_ctx) ||
	    ofi_atomic_get32(&sock_ep->attr->num_tx_ctx))
		return -FI_EBUSY;

	if (sock_ep->attr->ep_type == FI_EP_MSG) {
		sock_ep->attr->cm.do_listen = 0;
		if (ofi_write_socket(sock_ep->attr->cm.signal_fds[0], &c, 1) != 1)
			SOCK_LOG_DBG("Failed to signal\n");

		if (sock_ep->attr->cm.listener_thread &&
			pthread_join(sock_ep->attr->cm.listener_thread, NULL)) {
			SOCK_LOG_ERROR("pthread join failed (%d)\n",
				       ofi_syserr());
		}
		ofi_close_socket(sock_ep->attr->cm.signal_fds[0]);
		ofi_close_socket(sock_ep->attr->cm.signal_fds[1]);
	} else {
		if (sock_ep->attr->av)
			ofi_atomic_dec32(&sock_ep->attr->av->ref);
	}
	if (sock_ep->attr->av) {
		fastlock_acquire(&sock_ep->attr->av->list_lock);
		fid_list_remove(&sock_ep->attr->av->ep_list,
				&sock_ep->attr->lock, &sock_ep->ep.fid);
		fastlock_release(&sock_ep->attr->av->list_lock);
	}

	pthread_mutex_lock(&sock_ep->attr->domain->pe->list_lock);
	if (sock_ep->attr->tx_shared) {
		fastlock_acquire(&sock_ep->attr->tx_ctx->lock);
		dlist_remove(&sock_ep->attr->tx_ctx_entry);
		fastlock_release(&sock_ep->attr->tx_ctx->lock);
	}

	if (sock_ep->attr->rx_shared) {
		fastlock_acquire(&sock_ep->attr->rx_ctx->lock);
		dlist_remove(&sock_ep->attr->rx_ctx_entry);
		fastlock_release(&sock_ep->attr->rx_ctx->lock);
	}
	pthread_mutex_unlock(&sock_ep->attr->domain->pe->list_lock);

	if (sock_ep->attr->conn_handle.do_listen) {
		fastlock_acquire(&sock_ep->attr->domain->conn_listener.signal_lock);
		fi_epoll_del(sock_ep->attr->domain->conn_listener.emap,
		             sock_ep->attr->conn_handle.sock);
		fastlock_release(&sock_ep->attr->domain->conn_listener.signal_lock);
		ofi_close_socket(sock_ep->attr->conn_handle.sock);
		sock_ep->attr->conn_handle.do_listen = 0;
	}

	fastlock_destroy(&sock_ep->attr->cm.lock);

	if (sock_ep->attr->eq) {
		fastlock_acquire(&sock_ep->attr->eq->lock);
		sock_ep_clear_eq_list(&sock_ep->attr->eq->list,
				      &sock_ep->ep);
		/* Any err_data if present would be freed by
		 * sock_eq_clean_err_data_list when EQ is closed */
		sock_ep_clear_eq_list(&sock_ep->attr->eq->err_list,
				      &sock_ep->ep);
		fastlock_release(&sock_ep->attr->eq->lock);
	}

	if (sock_ep->attr->fclass != FI_CLASS_SEP) {
		if (!sock_ep->attr->tx_shared)
			sock_pe_remove_tx_ctx(sock_ep->attr->tx_array[0]);

		sock_tx_ctx_close(sock_ep->attr->tx_array[0]);
		sock_tx_ctx_free(sock_ep->attr->tx_array[0]);
	}

	if (sock_ep->attr->fclass != FI_CLASS_SEP) {
		if (!sock_ep->attr->rx_shared)
			sock_pe_remove_rx_ctx(sock_ep->attr->rx_array[0]);

		sock_rx_ctx_close(sock_ep->attr->rx_array[0]);
		sock_rx_ctx_free(sock_ep->attr->rx_array[0]);
	}

	free(sock_ep->attr->tx_array);
	free(sock_ep->attr->rx_array);

	if (sock_ep->attr->src_addr)
		free(sock_ep->attr->src_addr);
	if (sock_ep->attr->dest_addr)
		free(sock_ep->attr->dest_addr);

	fastlock_acquire(&sock_ep->attr->domain->pe->lock);
	ofi_idm_reset(&sock_ep->attr->av_idm);
	sock_conn_map_destroy(sock_ep->attr);
	fastlock_release(&sock_ep->attr->domain->pe->lock);

	ofi_atomic_dec32(&sock_ep->attr->domain->ref);
	fastlock_destroy(&sock_ep->attr->lock);
	free(sock_ep->attr);
	free(sock_ep);
	return 0;
}
示例#20
0
void ofi_monitor_cleanup(struct ofi_mem_monitor *monitor)
{
	assert(ofi_atomic_get32(&monitor->refcnt) == 0);
}
示例#21
0
static ssize_t sock_cq_sreadfrom(struct fid_cq *cq, void *buf, size_t count,
			fi_addr_t *src_addr, const void *cond, int timeout)
{
	int ret = 0;
	size_t threshold;
	struct sock_cq *sock_cq;
	uint64_t start_ms;
	ssize_t cq_entry_len, avail;

	sock_cq = container_of(cq, struct sock_cq, cq_fid);
	if (ofi_rbused(&sock_cq->cqerr_rb))
		return -FI_EAVAIL;

	cq_entry_len = sock_cq->cq_entry_size;
	if (sock_cq->attr.wait_cond == FI_CQ_COND_THRESHOLD)
		threshold = MIN((uintptr_t) cond, count);
	else
		threshold = count;

	start_ms = (timeout >= 0) ? fi_gettime_ms() : 0;

	if (sock_cq->domain->progress_mode == FI_PROGRESS_MANUAL) {
		while (1) {
			sock_cq_progress(sock_cq);
			fastlock_acquire(&sock_cq->lock);
			avail = ofi_rbfdused(&sock_cq->cq_rbfd);
			if (avail) {
				ret = sock_cq_rbuf_read(sock_cq, buf,
					MIN(threshold, (size_t)(avail / cq_entry_len)),
					src_addr, cq_entry_len);
			}
			fastlock_release(&sock_cq->lock);
			if (ret)
				return ret;

			if (timeout >= 0) {
				timeout -= (int) (fi_gettime_ms() - start_ms);
				if (timeout <= 0)
					return -FI_EAGAIN;
			}

			if (ofi_atomic_get32(&sock_cq->signaled)) {
				ofi_atomic_set32(&sock_cq->signaled, 0);
				return -FI_ECANCELED;
			}
		};
	} else {
		do {
			fastlock_acquire(&sock_cq->lock);
			ret = 0;
			avail = ofi_rbfdused(&sock_cq->cq_rbfd);
			if (avail) {
				ret = sock_cq_rbuf_read(sock_cq, buf,
					MIN(threshold, (size_t)(avail / cq_entry_len)),
					src_addr, cq_entry_len);
			} else {
				ofi_rbfdreset(&sock_cq->cq_rbfd);
			}
			fastlock_release(&sock_cq->lock);
			if (ret && ret != -FI_EAGAIN)
				return ret;

			if (timeout >= 0) {
				timeout -= (int) (fi_gettime_ms() - start_ms);
				if (timeout <= 0)
					return -FI_EAGAIN;
			}

			if (ofi_atomic_get32(&sock_cq->signaled)) {
				ofi_atomic_set32(&sock_cq->signaled, 0);
				return -FI_ECANCELED;
			}
			ret = ofi_rbfdwait(&sock_cq->cq_rbfd, timeout);
		} while (ret > 0);
	}

	return (ret == 0 || ret == -FI_ETIMEDOUT) ? -FI_EAGAIN : ret;
}