ibv_get_cq_event, ibv_ack_cq_events

Gets and acknowledges the completion queue (CQ) events.

Syntax

#include <rdma/verbs.h>
int ibv_get_cq_event(struct ibv_comp_channel *channel, struct ibv_cq **cq, void **cq_context); 
void ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents);

Description

The ibv_get_cq_event() function waits for the next completion event in the completion event channel. The cq argument is used to return the CQ that caused the event and the cq_context parameter is used to return the context of the CQ.

The ibv_ack_cq_events() function acknowledges the nevents events on the CQ cq parameter.

Notes:
  • All completion events that the ibv_get_cq_event() function returns must be acknowledged by using the ibv_ack_cq_events() function.
  • To avoid competiiton, when you destroy a CQ, the CQ waits for the completion of the events. This action guarantees a one-to-one correspondence between acknowledgements and successful get operation.
  • When you call the ibv_ack_cq_events() function, it is expensive in the datapath because it must take a mutex. To reduce the cost, a count of the number of events requesting acknowledgement and acknowledging several completion events in one call to the ibv_ack_cq_events() function are performed.

Input Parameters

Item Descriptor
channel The ibv_comp_channel struct for the ibv_create_comp_channel() function.

Output Parameters

Item Descriptor
cq A pointer to the completion queue (CQ) that is associated with the event.
cq_context The user-supplied context that is set in the ibv_create_cq() function.

Return Value

The ibv_get_cq_event() and ibv_ack_cq_events() functions return 0 on success, and -1 if the request fails.

Examples

  1. The following code example demonstrates one possible way to work with completion events. It performs the following steps:
    1. Preparation:
      1. Creates a CQ.
      2. Requests notification after creation of a new (first) completion event.
    2. Completion handling routine:
      1. Waits for the completion event and acknowledges it.
      2. Requests notification for the next completion event.
      3. Empties the CQ.
      Note: An extra event can be triggered without having a corresponding completion entry in the CQ. This occurs if a completion entry is added to the CQ between requesting for notification and emptying the CQ. Then, the CQ is emptied.
    		cq = ibv_create_cq(ctx, 1, ev_ctx, channel, 0);
    		if (!cq) {
    				fprintf(stderr, "Failed to create CQ\n");
    				return 1;
    		}
    
    		/* Request notification before any completion can be created */
    		if (ibv_req_notify_cq(cq, 0)) {
    				fprintf(stderr, "Could not request CQ notification\n");
    				return 1;
    		}
    
    		.
    		.
    		.
    		/* Wait for the completion event */
    		if (ibv_get_cq_event(channel, &ev_cq, &ev_ctx)) {
    				fprintf(stderr, "Failed to get cq_event\n");
    				return 1;
    		}  
    
    		/* Ack the event */ 
    		ibv_ack_cq_events(ev_cq, 1);
    
    		/* Request notification upon the next completion event */ 
    		if (ibv_req_notify_cq(cq, 0)) {
    				fprintf(stderr, "Could not request CQ notification\n");
    				return 1;
    		}  
    
    		/* Empty the CQ: poll all of the completions from the CQ (if any exist) */
    		do {
    				ne = ibv_poll_cq(cq, 1, &wc);
    				if (ne < 0) {
    						fprintf(stderr, "Failed to poll completions from the CQ\n");
    						return 1;
    				}
    				if (wc.status != IBV_WC_SUCCESS) {
    						fprintf(stderr, "Completion with status 0x%x was found\n", wc.status);
    						return 1;
    				}
    		} while (ne);
  2. The following code example demonstrates a possible way to work with completion events in nonblocking mode. The code performs the following steps:
    1. Sets the completion event channel in nonblocked mode.
    2. Polls the channel until it has a completion event.
    3. Gets the completion event and acknowledges it.
    /* change the blocking mode of the completion channel */
    flags = fcntl(channel->fd, F_GETFL);
    rc = fcntl(channel->fd, F_SETFL, flags | O_NONBLOCK);
    if (rc < 0) {
    		fprintf(stderr, "Failed to change file descriptor of completion event channel\n"); 
    		return 1; 
    } 
    /*
    * poll the channel until it has an event and sleep ms_timeout
    * milliseconds between any iteration
    */
    my_pollfd.fd = channel->fd;
    my_pollfd.events = POLLIN;
    my_pollfd.revents = 0; 
    
    do { 
    
    rc = poll(&my_polfd;, 1, ms_timeout);
    		} while (rc == 0);
    		if (rc &lt; 0){  fprintf(stderr, "poll failed\n");
    		return 1;
    		}
     ev_cq = cq;
     /* Wait for the completion event */
     if (ibv_get_cq_event(channel, &ev_cq, &ev_ctx)) {
     		fprintf(stderr, "Failed to get cq_event\n");
     		return 1;
     }
      /* Ack the event */
     ibv_ack_cq_events(ev_cq, 1);