/************************************************************************* * * FUNCTION * * get_endpoint * * DESCRIPTION * * Retrieves the endpoint identifier associated with a specific node * ID and port ID. * * INPUTS * * node_id The unique ID of the node on which the target * endpoint resides. * port_id The port ID of the target endpoint. * *mcapi_status A pointer to memory that will be filled in * with the status of the call. * timeout The amount of time to block for the operation * to complete. * * OUTPUTS * * The endpoint identifier associated with the node ID / port ID * combination. * *************************************************************************/ void get_remote_endpoint(mcapi_node_t node_id, mcapi_port_t port_id, mcapi_status_t *mcapi_status, mcapi_uint32_t timeout) { mcapi_endpoint_t dest_endpoint; unsigned char buffer[MCAPI_GET_ENDP_LEN]; mcapi_request_t request; /* Set the type. */ MCAPI_PUT16(buffer, MCAPI_PROT_TYPE, MCAPI_GETENDP_REQUEST); /* Set the port. */ MCAPI_PUT16(buffer, MCAPI_GETENDP_PORT, port_id); /* Insert the endpoint to which the receiver should respond * in the packet. */ MCAPI_PUT32(buffer, MCAPI_GETENDP_ENDP, MCAPI_CTRL_RX_Endp); /* Encode the destination endpoint. */ dest_endpoint = mcapi_encode_endpoint(node_id, MCAPI_RX_CONTROL_PORT); /* Send the message. */ msg_send(MCAPI_CTRL_TX_Endp, dest_endpoint, buffer, MCAPI_GET_ENDP_LEN, MCAPI_DEFAULT_PRIO, &request, mcapi_status, timeout); }
/************************************************************************* * * FUNCTION * * mcapi_check_foreign_resume * * DESCRIPTION * * Checks if any pending requests from foreign nodes should be resumed. * * INPUTS * * type The type of request to check. * endpoint The endpoint for which the request is * suspended on some action. * status The status to set in the request structure. * * OUTPUTS * * None. * *************************************************************************/ void mcapi_check_foreign_resume(int type, mcapi_endpoint_t endpoint, mcapi_status_t status) { mcapi_request_t *request, *next_ptr; MCAPI_GLOBAL_DATA *node_data; /* Get a pointer to the global node list. */ node_data = mcapi_get_node_data(); /* Get a pointer to the first entry in the request queue. */ request = node_data->mcapi_foreign_req_queue.flink; /* Check each request to see if the operation has been completed. */ while (request) { /* Get a pointer to the next entry. */ next_ptr = request->mcapi_next; switch (type) { /* An endpoint associated with a pending request has been * created. */ case MCAPI_REQ_CREATED: /* If the request structure is waiting for an endpoint to be * created. */ if ( (request->mcapi_type == MCAPI_REQ_CREATED) && (mcapi_encode_endpoint(request->mcapi_target_node_id, request->mcapi_target_port_id) == endpoint) ) { /* Remove this item from the list. */ mcapi_remove(&node_data->mcapi_foreign_req_queue, request); /* Set the status to success. */ request->mcapi_status = MCAPI_SUCCESS; /* Send the response. */ mcapi_tx_response(node_data, request); /* Set this request structure back to available. */ mcapi_release_request_struct(request); } break; default: break; } /* Get the next request entry in the list. */ request = next_ptr; } }
/************************************************************************* * * FUNCTION * * mcapi_check_resume * * DESCRIPTION * * Checks if any pending requests in the system should be resumed. * * INPUTS * * type The type of request to check. * endpoint The endpoint for which the request is * suspended on some action. * *endp_ptr If data was received, a pointer to the * endpoint for which data was received. * byte_count If the type is MCAPI_REQ_TX_FIN or * MCAPI_REQ_RX_FIN, the number of bytes * pending on the endpoint. * status The status to set in the request structure. * * OUTPUTS * * None. * *************************************************************************/ void mcapi_check_resume(int type, mcapi_endpoint_t endpoint, MCAPI_ENDPOINT *endp_ptr, size_t byte_count, mcapi_status_t status) { mcapi_request_t *request, *next_ptr; MCAPI_GLOBAL_DATA *node_data; MCAPI_BUFFER *rx_buf; mcapi_boolean_t data_copied = 0; /* Get a pointer to the global node list. */ node_data = mcapi_get_node_data(); /* Get a pointer to the first entry in the request queue. */ request = node_data->mcapi_local_req_queue.flink; /* Check each request to see if the operation has been completed. */ while (request) { /* Get a pointer to the next entry. */ next_ptr = request->mcapi_next; switch (type) { /* An endpoint associated with a request structure has been * deleted. */ case MCAPI_REQ_DELETED: //mcapi_printf("~~~~~Suspend received MCAPI_REQ_DELETED\n"); /* If the operation is waiting for something to happen * on the send side, and the endpoint matches the send * endpoint. */ if ( ((request->mcapi_type == MCAPI_REQ_TX_FIN) || (request->mcapi_type == MCAPI_REQ_TX_OPEN) || (request->mcapi_type == MCAPI_REQ_CONNECTED)) && (request->mcapi_target_endp == endpoint) ) { mcapi_resume(node_data, request, status); } /* If the operation is waiting for something to happen * on the receive side, and the endpoint matches the receive * endpoint. */ else if ( ((request->mcapi_type == MCAPI_REQ_RX_FIN) || (request->mcapi_type == MCAPI_REQ_RX_OPEN) || (request->mcapi_type == MCAPI_REQ_CONNECTED)) && (request->mcapi_target_endp == endpoint) ) { mcapi_resume(node_data, request, status); } break; /* The connection has been closed. */ case MCAPI_REQ_CLOSED: //mcapi_printf("~~~~~Suspend received MCAPI_REQ_CLOSED\n"); /* No matter what the reason the thread is suspended, if the * connection has been closed, resume the thread. */ if (request->mcapi_target_endp == endpoint) { /* Resume the task. */ mcapi_resume(node_data, request, status); } break; /* The send side of an endpoint has been opened. */ case MCAPI_REQ_TX_OPEN: //mcapi_printf("~~~~~Suspend received MCAPI_REQ_TX_OPEN\n"); /* If the request structure is waiting for the send side * of the connection to open. */ if (request->mcapi_target_endp == endpoint) { /* Resume the task. */ mcapi_resume(node_data, request, status); } break; /* Data associated with a request structure has been transmitted * successfully, or the transmit has been canceled. */ case MCAPI_REQ_TX_FIN: //mcapi_printf("~~~~~Suspend received MCAPI_REQ_TX_FIN\n"); /* If the request structure is waiting for outgoing data to be * successfully transmitted. */ if ( (request->mcapi_type == MCAPI_REQ_TX_FIN) && (request->mcapi_target_endp == endpoint) ) { /* Resume the task. */ mcapi_resume(node_data, request, status); } break; /* The receive side of an endpoint has been opened. */ case MCAPI_REQ_RX_OPEN: //mcapi_printf("~~~~~Suspend received MCAPI_REQ_RX_OPEN\n"); /* If the request structure is waiting for the receive side * of the connection to open. */ if (request->mcapi_target_endp == endpoint) { /* Resume the task. */ mcapi_resume(node_data, request, status); } break; /* Data associated with a request structure has been received * successfully, or the receive has been canceled. */ case MCAPI_REQ_RX_FIN: //mcapi_printf("~~~~~Suspend received MCAPI_REQ_RX_FIN\n"); /* If the request structure is waiting for data to be * received on the endpoint. */ if ( (request->mcapi_type == MCAPI_REQ_RX_FIN) && (request->mcapi_target_endp == endpoint) ) { switch (request->mcapi_chan_type) { case MCAPI_MSG_TYPE: /* Ensure the data will fit in the buffer. */ if (byte_count <= request->mcapi_buf_size) { /* Copy the data into the user buffer. */ request->mcapi_byte_count = msg_recv_copy_data(endp_ptr, request->mcapi_buffer); /* Data has been successfully copied. */ data_copied = MCAPI_TRUE; } /* The data is too big for the user buffer. Leave * the data on the receive queue for a subsequent * receive call. */ else { status = MCAPI_ERR_MSG_TRUNCATED; } break; case MCAPI_CHAN_PKT_TYPE: /* Get a pointer to the head buffer. */ rx_buf = endp_ptr->mcapi_rx_queue.head; /* Set the user buffer to the incoming buffer. */ *(request->mcapi_pkt) = &rx_buf->buf_ptr[MCAPI_HEADER_LEN]; /* Set the size of the incoming buffer. */ request->mcapi_byte_count = rx_buf->buf_size - MCAPI_HEADER_LEN; /* Data has been successfully copied. */ data_copied = MCAPI_TRUE; break; default: break; } /* Resume the task. */ mcapi_resume(node_data, request, status); } break; /* An endpoint associated with a pending request has been * created. */ case MCAPI_REQ_CREATED: //mcapi_printf("~~~~~Suspend received MCAPI_REQ_CREATED\n"); /* If the request structure is waiting for an endpoint to be * created. */ if ( (request->mcapi_type == MCAPI_REQ_CREATED) && (mcapi_encode_endpoint(request->mcapi_target_node_id, request->mcapi_target_port_id) == endpoint) ) { /* If this is a local call, fill in the endpoint pointer. */ if (request->mcapi_endp_ptr) { *(request->mcapi_endp_ptr) = endpoint; } mcapi_resume(node_data, request, status); } break; /* A connection between two endpoints has been made. */ case MCAPI_REQ_CONNECTED: //mcapi_printf("~~~~~Suspend received MCAPI_REQ_CONNECTED\n"); g_connect_finish = 1; /* If the request structure is waiting for a connection * between two endpoints to be made. */ if ( (request->mcapi_type == MCAPI_REQ_CONNECTED) && (request->mcapi_target_endp == endpoint) ) { /* Resume the task. */ mcapi_resume(node_data, request, status); } break; default: break; } /* Get the next request entry in the list. */ request = next_ptr; } /* Multiple request structures could have been suspended on the same * receive operation; therefore, the data must not be removed from * the queue until all request structures have been serviced. */ if (data_copied) { /* Remove the buffer from the receive queue. */ rx_buf = mcapi_dequeue(&endp_ptr->mcapi_rx_queue); if (endp_ptr->mcapi_chan_type == MCAPI_CHAN_PKT_TYPE) { /* Add the receive buffer structure to the list of * buffers waiting to be freed by the application. */ mcapi_enqueue(&MCAPI_Buf_Wait_List, rx_buf); } else { /*Enhanced by tony on 2013/12/13*/ #if 0 /* Return the message buffer to the pool of available buffers. */ ((MCAPI_INTERFACE*)(rx_buf->mcapi_dev_ptr))-> mcapi_recover_buffer(rx_buf); #endif shm_free_buffer(rx_buf); } } }
/************************************************************************* * * FUNCTION * * create_endpoint * * DESCRIPTION * * Routine to create an endpoint on the local node. If the port * ID field is set to MCAPI_PORT_ANY, an endpoint will be created using * the next available port in the system. * * INPUTS * * port_id The port ID of the endpoint, or MCAPI_PORT_ANY * to create an endpoint with the next available * port ID. * *mcapi_status A pointer to memory that will be filled in * with the status of the call. * * OUTPUTS * * The newly created endpoint. * *************************************************************************/ mcapi_endpoint_t create_endpoint(MCAPI_NODE *node_ptr, mcapi_port_t port_id, mcapi_status_t *mcapi_status) { mcapi_endpoint_t endpoint = 0; MCAPI_ENDPOINT *endp_ptr = MCAPI_NULL; int i, endp_idx; #if (MCAPI_MAX_ENDPOINTS != 0) /* If there is an available endpoint entry. */ if (node_ptr->mcapi_endpoint_count < MCAPI_MAX_ENDPOINTS) { /* Initialize mcapi_status to success. */ *mcapi_status = MCAPI_SUCCESS; /* If a specific port was specified for the new endpoint, check * that an endpoint does not already exist that uses that port. */ if (port_id != (unsigned int)MCAPI_PORT_ANY) { /* If a matching endpoint already exists. */ if (mcapi_find_endpoint(port_id, node_ptr) != -1) { *mcapi_status = MCAPI_ERR_ENDP_EXISTS; } } /* If a port was not passed in, find a unique port. */ else { /* Find a unique port to assign to the endpoint. */ do { port_id = MCAPI_Next_Port ++; /* Ensure the application has not used this port for * another endpoint. */ i = mcapi_find_endpoint(port_id, node_ptr); } while ( (i != -1) && (port_id != (unsigned int)MCAPI_PORT_ANY) ); /* If an unused port could not be found. */ if (port_id == (unsigned int)MCAPI_PORT_ANY) { *mcapi_status = MCAPI_ERR_PORT_INVALID; } } /* If the status is still success. */ if (*mcapi_status == MCAPI_SUCCESS) { /* Create a hash index. */ endp_idx = (port_id % MCAPI_MAX_ENDPOINTS); /* If this slot is available. */ if (node_ptr->mcapi_endpoint_list[endp_idx].mcapi_state == MCAPI_ENDP_CLOSED) { endp_ptr = &node_ptr->mcapi_endpoint_list[endp_idx]; } /* Otherwise, find the next available slot. */ else { /* Set the counter variable to zero. */ i = 0; /* Find an empty slot. */ do { /* Move to the next slot. */ endp_idx ++; /* If the index has rolled over. */ if ( (endp_idx < 0) || (endp_idx >= MCAPI_MAX_ENDPOINTS) ) { endp_idx = 0; } /* If the endpoint entry is unused. */ if (node_ptr->mcapi_endpoint_list[endp_idx]. mcapi_state == MCAPI_ENDP_CLOSED) { /* Use this entry. */ endp_ptr = &node_ptr->mcapi_endpoint_list[endp_idx]; break; } i ++; } while (i < MCAPI_MAX_ENDPOINTS); } /* If an available entry was found. */ if (endp_ptr) { /* Increment the number of used endpoints on the * node. */ node_ptr->mcapi_endpoint_count ++; /* Clear the endpoint structure. */ memset(endp_ptr, 0, sizeof(MCAPI_ENDPOINT)); /* Set the state of the entry to open. */ endp_ptr->mcapi_state = MCAPI_ENDP_OPEN; /* Set the port ID of the entry. */ endp_ptr->mcapi_port_id = port_id; /* Set the node ID of the entry. */ endp_ptr->mcapi_node_id = node_ptr->mcapi_node_id; /* Encode the endpoint. */ endpoint = mcapi_encode_endpoint(endp_ptr->mcapi_node_id, port_id); /* Store the handle for future use. */ endp_ptr->mcapi_endp_handle = endpoint; /* Set the priority to the default. */ endp_ptr->mcapi_priority = MCAPI_DEFAULT_PRIO; /* Check if any foreign nodes are waiting for this * endpoint to be created. */ mcapi_check_foreign_resume(MCAPI_REQ_CREATED, endpoint, MCAPI_SUCCESS); /* Check if any local threads are waiting for this endpoint * to be created. */ mcapi_check_resume(MCAPI_REQ_CREATED, endpoint, MCAPI_NULL, 0, MCAPI_SUCCESS); } } } /* There are no available endpoint entries in the system. */ else { *mcapi_status = MCAPI_ERR_GENERAL; /* XXX document me */ } #else *mcapi_status = MCAPI_EEP_NOTALLOWED; #endif return (endpoint); }