ucs_status_t ucp_ep_create(ucp_worker_h worker, ucp_address_t *address, ucp_ep_h *ep_p) { uint64_t dest_uuid = ucp_address_uuid(address); char peer_name[UCP_PEER_NAME_MAX]; ucs_status_t status; ucp_ep_h ep; UCS_ASYNC_BLOCK(&worker->async); ep = ucp_worker_ep_find(worker, dest_uuid); if (ep != NULL) { ucs_debug("returning existing ep %p which is already connected to %"PRIx64, ep, ep->dest_uuid); goto out; } ucp_address_peer_name(address, peer_name); status = ucp_ep_new(worker, dest_uuid, peer_name, " from api call", &ep); if (status != UCS_OK) { goto err; } status = ucp_wireup_start(ep, address); if (status != UCS_OK) { goto err_free; } out: UCS_ASYNC_UNBLOCK(&worker->async); *ep_p = ep; return UCS_OK; err_free: ucs_free(ep); err: UCS_ASYNC_UNBLOCK(&worker->async); return status; }
ucs_status_t ucp_ep_wireup_start(ucp_ep_h ep, ucp_address_t *address) { ucp_worker_h worker = ep->worker; struct sockaddr *am_short_addr; ucp_rsc_index_t wireup_rsc_index; struct sockaddr *wireup_addr; uct_iface_attr_t *iface_attr; uct_iface_h iface; ucp_rsc_index_t dst_rsc_index, wireup_dst_rsc_index; ucp_rsc_index_t wireup_dst_pd_index; ucs_status_t status; UCS_ASYNC_BLOCK(&worker->async); ep->dest_uuid = ucp_address_uuid(address); sglib_hashed_ucp_ep_t_add(worker->ep_hash, ep); ucs_debug("connecting 0x%"PRIx64"->0x%"PRIx64, worker->uuid, ep->dest_uuid); /* * Select best transport for active messages */ status = ucp_pick_best_wireup(worker, address, ucp_am_short_score_func, &ep->uct.rsc_index, &dst_rsc_index, &ep->uct.dst_pd_index, &am_short_addr, &ep->uct.reachable_pds, "short_am"); if (status != UCS_OK) { ucs_error("No transport for short active message"); goto err; } iface = worker->ifaces[ep->uct.rsc_index]; iface_attr = &worker->iface_attrs[ep->uct.rsc_index]; /* * If the selected transport can be connected directly, do it. */ if (iface_attr->cap.flags & UCT_IFACE_FLAG_CONNECT_TO_IFACE) { status = uct_ep_create_connected(iface, am_short_addr, &ep->uct.next_ep); if (status != UCS_OK) { ucs_debug("failed to create ep"); goto err; } ep->state |= UCP_EP_STATE_LOCAL_CONNECTED; ucp_ep_remote_connected(ep); goto out; } /* * If we cannot connect the selected transport directly, select another * transport for doing the wireup. */ status = ucp_pick_best_wireup(worker, address, ucp_wireup_score_func, &wireup_rsc_index, &wireup_dst_rsc_index, &wireup_dst_pd_index, &wireup_addr, &ep->uct.reachable_pds, "wireup"); if (status != UCS_OK) { goto err; } status = uct_ep_create_connected(worker->ifaces[wireup_rsc_index], wireup_addr, &ep->wireup_ep); if (status != UCS_OK) { goto err; } if (!(iface_attr->cap.flags & UCT_IFACE_FLAG_CONNECT_TO_EP)) { status = UCS_ERR_UNREACHABLE; goto err_destroy_wireup_ep; } /* * Until the transport is connected, send operations should return NO_RESOURCE. * Plant a dummy endpoint object which will do it. */ status = UCS_CLASS_NEW(ucp_dummy_ep_t, &ep->uct.ep, ep); if (status != UCS_OK) { goto err_destroy_wireup_ep; } /* * Create endpoint for the transport we need to wire-up. */ status = uct_ep_create(iface, &ep->uct.next_ep); if (status != UCS_OK) { goto err_destroy_uct_ep; } /* * Send initial connection request for wiring-up the transport. */ status = ucp_ep_wireup_send(ep, ep->wireup_ep, UCP_AM_ID_CONN_REQ, dst_rsc_index); if (status != UCS_OK) { goto err_destroy_next_ep; } out: UCS_ASYNC_UNBLOCK(&worker->async); return UCS_OK; err_destroy_next_ep: uct_ep_destroy(ep->uct.next_ep); err_destroy_uct_ep: uct_ep_destroy(ep->uct.ep); err_destroy_wireup_ep: uct_ep_destroy(ep->wireup_ep); err: sglib_hashed_ucp_ep_t_delete(worker->ep_hash, ep); UCS_ASYNC_UNBLOCK(&worker->async); return status; }