enum {
RS_CTRL_DISCONNECT,
- RS_CTRL_SHUTDOWN,
- RS_CTRL_SYNC
+ RS_CTRL_SHUTDOWN
};
struct rs_msg {
case RS_OP_CTRL:
rs->ctrl_avail++;
if (rs_msg_data(rs_wr_data(wc.wr_id)) == RS_CTRL_DISCONNECT)
- {
rs->state = rs_disconnected;
- printf("rsocket disconnected - send complete\n");
- }
break;
case RS_OP_IOMAP_SGL:
rs->sqe_avail++;
void *context;
int ret;
- printf("rs_get_cq_event\n");
if (!rs->cq_armed)
return 0;
- printf("waiting on cq event\n");
ret = ibv_get_cq_event(rs->cm_id->recv_cq_channel, &cq, &context);
if (!ret) {
ibv_ack_cq_events(rs->cm_id->recv_cq, 1);
rs->cq_armed = 0;
- printf("retrieved event\n");
} else if (errno != EAGAIN) {
rs->state = rs_error;
}
if (ret)
break;
- printf("real poll start\n");
ret = poll(rfds, nfds, timeout);
- printf("real poll exit\n");
if (ret <= 0)
break;
return ret;
}
-static void rs_unblock_rpoll(struct rsocket *rs)
-{
- if (!rs->ctrl_avail) {
- if (rs_process_cq(rs, 0, rs_conn_can_send_ctrl))
- return;
- }
-
- ibv_req_notify_cq(rs->cm_id->recv_cq, 0);
- rs->ctrl_avail--;
- rs_post_msg(rs, rs_msg_set(RS_OP_CTRL, RS_CTRL_SYNC));
-}
-
/*
* For graceful disconnect, notify the remote side that we're
- * disconnecting and wait until all outstanding sends complete.
+ * disconnecting and wait until all outstanding sends complete, provided
+ * that the remote side has not sent a disconnect message.
*/
int rshutdown(int socket, int how)
{
if (rs->state & rs_connected)
rs_process_cq(rs, 0, rs_conn_all_sends_done);
- rs_unblock_poll(rs);
+ if (rs->state & rs_disconnected) {
+ /* Generate event by flushing receives to unblock rpoll */
+ ibv_req_notify_cq(rs->cm_id->recv_cq, 0);
+ rdma_disconnect(rs->cm_id);
+ }
+
if ((rs->fd_flags & O_NONBLOCK) && (rs->state & rs_connected))
rs_set_nonblocking(rs, rs->fd_flags);