// Handle randomly selected pending write void handle_buffer_read(struct cmd *cmd) { struct cmd_event *event; // Check that cmd struct is valid buffer read is available if ((cmd == NULL) || (cmd->buffer_read != NULL)) return; // Randomly select a pending write (or none) event = cmd->list; while (event != NULL) { if ((event->type == CMD_WRITE) && (event->state == MEM_TOUCHED) && ((event->client_state != CLIENT_VALID) || !allow_reorder(cmd->parms))) { break; } event = event->_next; } // Test for client disconnect if ((event == NULL) || (_get_client(cmd, event) == NULL)) return; // Send buffer read request to AFU. Setting cmd->buffer_read // will block any more buffer read requests until buffer read // data is returned and handled in handle_buffer_data(). if (psl_buffer_read(cmd->afu_event, event->tag, event->addr, CACHELINE_BYTES) == PSL_SUCCESS) { cmd->buffer_read = event; debug_cmd_buffer_read(cmd->dbg_fp, cmd->dbg_id, event->tag); event->state = MEM_BUFFER; } }
void rpcudp::_package_process(const udpaddr& addr, int len, shared_memory memory, size_t memory_size) { /* 要最先发送ack */ const_memory_block blk(memory); blk.size = memory_size; packages_analysis sis(blk); rpcudp_detail::__slice_head_attacher attacher(sis); complete_result job; job.user_key = get_slice; job.key = 0; auto* arg = new _complete_argument(addr, memory); job.argument = arg; auto wlock = ISU_AUTO_LOCK(_spinlock); arg->client = &_get_client(addr); wlock.unlock(); if (attacher.udp_ex != nullptr) { arg->client->_send_ack( addr, attacher.udp_ex->group_id, attacher.udp_ex->slice_id); } _process_port.post(job); }
// Decide what to do with a client memory acknowledgement void handle_mem_return(struct cmd *cmd, struct cmd_event *event, int fd) { struct client *client; // Test for client disconnect if ((event == NULL) || ((client = _get_client(cmd, event)) == NULL)) return; // Randomly cause paged response if (((event->type != CMD_WRITE) || (event->state != MEM_REQUEST)) && (client->flushing == FLUSH_NONE) && !_page_cached(cmd, event->addr) && allow_paged(cmd->parms)) { if (event->type == CMD_READ) _handle_mem_read(cmd, event, fd); event->resp = PSL_RESPONSE_PAGED; event->state = MEM_DONE; client->flushing = FLUSH_PAGED; debug_cmd_update(cmd->dbg_fp, cmd->dbg_id, event->tag, event->context, event->resp); return; } _update_age(cmd, event->addr); if (event->type == CMD_READ) _handle_mem_read(cmd, event, fd); else if (event->type == CMD_TOUCH) event->state = MEM_DONE; else if (event->state == MEM_TOUCH) // Touch before write event->state = MEM_TOUCHED; else // Write after touch event->state = MEM_DONE; debug_cmd_return(cmd->dbg_fp, cmd->dbg_id, event->tag, event->context); }
/*** * Manage UDP packets */ void NetGameServer::_handle_udp() { DVector<uint8_t> raw; NetGameServerConnection *cd; // Flush packets queue while(udp_queue.size() > 0) { // Only this thread removes from the queue // it is safe to lock here udp_mutex->lock(); QueuedPacket *qp = udp_queue.get(0); udp_queue.remove(0); udp_mutex->unlock(); NetGameServerConnection *cd = _get_client(qp->id); if(cd != NULL) { udp_server->set_send_address(cd->udp_host, cd->udp_port); udp_server->put_packet_buffer(cd->build_pkt(qp)); } memdelete(qp); } // Handle incoming packets if(udp_server->get_available_packet_count() > 0) { udp_server->get_packet_buffer(raw); if(raw.size() < 1) { WARN_PRINT("Invalid UDP Packet!"); return; } cd = _get_client(raw.get(0)); if(cd == NULL) { WARN_PRINT("Invalid UDP Auth!"); return; } cd->handle_udp(raw, udp_server->get_packet_address(), udp_server->get_packet_port()); } }
int rpcudp::sendto(const void* buf, size_t bufsize, int flag, const udpaddr& addr) { _spinlock.lock(); auto& client = _get_client(addr); _spinlock.unlock(); const_shared_memory memory( deep_copy(const_memory_block(buf, bufsize))); return client.sendto(memory, addr); }
void handle_mem_write(struct cmd *cmd) { struct cmd_event **head; struct cmd_event *event; struct client *client; uint64_t *addr; uint8_t *buffer; uint64_t offset; // Make sure cmd structure is valid if (cmd == NULL) return; // Send any ready write data to client immediately head = &cmd->list; while (*head != NULL) { if (((*head)->type == CMD_WRITE) && ((*head)->state == MEM_RECEIVED)) break; head = &((*head)->_next); } event = *head; // Test for client disconnect if ((event == NULL) || ((client = _get_client(cmd, event)) == NULL)) return; // Check that memory request can be driven to client if (client->mem_access != NULL) return; // Send data to client and clear event to allow // the next buffer read to occur. The request will now await // confirmation from the client that the memory write was // successful before generating a response. The client // response will cause a call to either handle_aerror() or // handle_mem_return(). buffer = (uint8_t *) malloc(event->size + 10); offset = event->addr & ~CACHELINE_MASK; buffer[0] = (uint8_t) PSLSE_MEMORY_WRITE; buffer[1] = (uint8_t) event->size; addr = (uint64_t *) & (buffer[2]); *addr = htonll(event->addr); memcpy(&(buffer[10]), &(event->data[offset]), event->size); event->abort = &(client->abort); if (put_bytes(client->fd, event->size + 10, buffer, cmd->dbg_fp, cmd->dbg_id, client->context) < 0) { client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE); } debug_cmd_client(cmd->dbg_fp, cmd->dbg_id, event->tag, event->context); event->state = MEM_REQUEST; client->mem_access = (void *)event; }
Error NetGameServer::put_tcp_packet(int id, const DVector<uint8_t> &pkt, int cmd) { Error out; conn_mutex->lock(); NetGameServerConnection *cd = _get_client(id); if(cd == NULL) { conn_mutex->unlock(); return ERR_DOES_NOT_EXIST; } out = cd->enqueue_tcp(pkt, cmd); conn_mutex->unlock(); return out; }
Error NetGameServer::kick_client(CID id) { conn_mutex->lock(); NetGameServerConnection *conn = _get_client(id); if(conn == NULL) { conn_mutex->unlock(); return ERR_DOES_NOT_EXIST; } this->connections.erase(conn->id); conn_mutex->unlock(); _delete_client(conn); return OK; }
Error NetGameServer::put_udp_packet(int id, const DVector<uint8_t> &pkt, int cmd, bool timed) { conn_mutex->lock(); NetGameServerConnection *cd = _get_client(id); if(cd == NULL) { conn_mutex->unlock(); return ERR_DOES_NOT_EXIST; } if(cd->state != READY) { conn_mutex->unlock(); return ERR_CONNECTION_ERROR; } conn_mutex->unlock(); return _enqueue_udp(id, pkt, cmd, timed); }
// Handle randomly selected memory touch void handle_touch(struct cmd *cmd) { struct cmd_event *event; struct client *client; uint8_t buffer[10]; uint64_t *addr; // Make sure cmd structure is valid if (cmd == NULL) return; // Randomly select a pending touch (or none) event = cmd->list; while (event != NULL) { if (((event->type == CMD_TOUCH) || (event->type == CMD_WRITE)) && (event->state == MEM_IDLE) && ((event->client_state != CLIENT_VALID) || !allow_reorder(cmd->parms))) { break; } event = event->_next; } // Test for client disconnect if ((event == NULL) || ((client = _get_client(cmd, event)) == NULL)) return; // Check that memory request can be driven to client if (client->mem_access != NULL) return; // Send memory touch request to client buffer[0] = (uint8_t) PSLSE_MEMORY_TOUCH; buffer[1] = (uint8_t) event->size; addr = (uint64_t *) & (buffer[2]); *addr = htonll(event->addr & CACHELINE_MASK); event->abort = &(client->abort); if (put_bytes(client->fd, 10, buffer, cmd->dbg_fp, cmd->dbg_id, event->context) < 0) { client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE); } event->state = MEM_TOUCH; client->mem_access = (void *)event; debug_cmd_client(cmd->dbg_fp, cmd->dbg_id, event->tag, event->context); }
// Add new command to list static void _add_cmd(struct cmd *cmd, uint32_t context, uint32_t tag, uint32_t command, uint32_t abort, enum cmd_type type, uint64_t addr, uint32_t size, enum mem_state state, uint32_t resp, uint8_t unlock) { struct cmd_event **head; struct cmd_event *event; if (cmd == NULL) return; event = (struct cmd_event *)calloc(1, sizeof(struct cmd_event)); event->context = context; event->command = command; event->tag = tag; event->abt = abort; event->type = type; event->addr = addr; event->size = size; event->state = state; event->resp = resp; event->unlock = unlock; event->data = (uint8_t *) malloc(CACHELINE_BYTES); memset(event->data, 0xFF, CACHELINE_BYTES); event->parity = (uint8_t *) malloc(DWORDS_PER_CACHELINE / 8); memset(event->parity, 0xFF, DWORDS_PER_CACHELINE / 8); // Test for client disconnect if (_get_client(cmd, event) == NULL) { event->resp = PSL_RESPONSE_FAILED; event->state = MEM_DONE; } head = &(cmd->list); while ((*head != NULL) && !allow_reorder(cmd->parms)) head = &((*head)->_next); event->_next = *head; *head = event; debug_cmd_add(cmd->dbg_fp, cmd->dbg_id, tag, context, command); }
// Send pending interrupt to client as soon as possible void handle_interrupt(struct cmd *cmd) { struct cmd_event **head; struct cmd_event *event; struct client *client; uint16_t irq; uint8_t buffer[3]; // Make sure cmd structure is valid if (cmd == NULL) return; // Send any interrupts to client immediately head = &cmd->list; while (*head != NULL) { if (((*head)->type == CMD_INTERRUPT) && ((*head)->state == MEM_IDLE)) break; head = &((*head)->_next); } event = *head; // Test for client disconnect if ((event == NULL) || ((client = _get_client(cmd, event)) == NULL)) return; // Send interrupt to client buffer[0] = PSLSE_INTERRUPT; irq = htons(cmd->irq); memcpy(&(buffer[1]), &irq, 2); event->abort = &(client->abort); if (put_bytes(client->fd, 3, buffer, cmd->dbg_fp, cmd->dbg_id, event->context) < 0) { client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE); } debug_cmd_client(cmd->dbg_fp, cmd->dbg_id, event->tag, event->context); event->state = MEM_DONE; }
Error NetGameServer::auth_client(CID id) { conn_mutex->lock(); NetGameServerConnection *conn = _get_client(id); if(conn == NULL) { conn_mutex->unlock(); return ERR_DOES_NOT_EXIST; } if(conn->authed) { conn_mutex->unlock(); return ERR_ALREADY_EXISTS; } conn->authed = true; // Assign id to client unsigned char raw[4]; raw[0] = CMD_MAX; raw[1] = PCMD_AUTH; raw[2] = conn->id; raw[3] = conn->secret; conn->tcp->put_packet(raw, 4); conn_mutex->unlock(); return OK; }
// Send a randomly selected pending response back to AFU void handle_response(struct cmd *cmd) { struct cmd_event **head; struct cmd_event *event; struct client *client; int rc; // Select a random pending response (or none) client = NULL; head = &cmd->list; while (*head != NULL) { // Fast track error responses if (((*head)->resp == PSL_RESPONSE_PAGED) || ((*head)->resp == PSL_RESPONSE_NRES) || ((*head)->resp == PSL_RESPONSE_NLOCK) || ((*head)->resp == PSL_RESPONSE_FAILED) || ((*head)->resp == PSL_RESPONSE_FLUSHED)) { event = *head; goto drive_resp; } if (((*head)->state == MEM_DONE) && !allow_reorder(cmd->parms)) { break; } head = &((*head)->_next); } // Randomly decide not to drive response yet event = *head; if ((event == NULL) || ((event->client_state == CLIENT_VALID) && !allow_resp(cmd->parms))) { return; } // Test for client disconnect if ((event == NULL) || ((client = _get_client(cmd, event)) == NULL)) return; // Send response, remove command from list and free memory if ((event->resp == PSL_RESPONSE_PAGED) || (event->resp == PSL_RESPONSE_AERROR) || (event->resp == PSL_RESPONSE_DERROR)) { client->flushing = FLUSH_FLUSHING; _update_pending_resps(cmd, PSL_RESPONSE_FLUSHED); } drive_resp: // Check for pending buffer activity if (event == cmd->buffer_read) { fatal_msg("Driving response when buffer read still active"); _print_event(event); assert(event != cmd->buffer_read); } rc = psl_response(cmd->afu_event, event->tag, event->resp, 1, 0, 0); if (rc == PSL_SUCCESS) { debug_msg("%s:RESPONSE tag=0x%02x code=0x%x", cmd->afu_name, event->tag, event->resp); debug_cmd_response(cmd->dbg_fp, cmd->dbg_id, event->tag); if ((client != NULL) && (event->command == PSL_COMMAND_RESTART)) client->flushing = FLUSH_NONE; *head = event->_next; free(event->data); free(event->parity); free(event); cmd->credits++; } }
// Handle randomly selected pending read by either generating early buffer // write with bogus data, send request to client for real data or do final // buffer write with valid data after it has been received from client. void handle_buffer_write(struct cmd *cmd) { struct cmd_event *event; struct client *client; uint8_t buffer[10]; uint64_t *addr; int quadrant, byte; // Make sure cmd structure is valid if (cmd == NULL) return; // Randomly select a pending read (or none) event = cmd->list; while (event != NULL) { if ((event->type == CMD_READ) && (event->state != MEM_DONE) && ((event->client_state != CLIENT_VALID) || !allow_reorder(cmd->parms))) { break; } event = event->_next; } // Test for client disconnect if ((event == NULL) || ((client = _get_client(cmd, event)) == NULL)) return; // After the client returns data with a call to the function // _handle_mem_read() issue buffer write with valid data and // prepare for response. if (event->state == MEM_RECEIVED) { if (psl_buffer_write(cmd->afu_event, event->tag, event->addr, CACHELINE_BYTES, event->data, event->parity) == PSL_SUCCESS) { debug_msg("%s:BUFFER WRITE tag=0x%02x", cmd->afu_name, event->tag); for (quadrant = 0; quadrant < 4; quadrant++) { DPRINTF("DEBUG: Q%d 0x", quadrant); for (byte = 0; byte < CACHELINE_BYTES / 4; byte++) { DPRINTF("%02x", event->data[byte]); } DPRINTF("\n"); } event->resp = PSL_RESPONSE_DONE; event->state = MEM_DONE; debug_cmd_buffer_write(cmd->dbg_fp, cmd->dbg_id, event->tag); debug_cmd_update(cmd->dbg_fp, cmd->dbg_id, event->tag, event->context, event->resp); } } if (event->state != MEM_IDLE) return; if (!event->buffer_activity && allow_buffer(cmd->parms)) { // Buffer write with bogus data, but only once debug_cmd_buffer_write(cmd->dbg_fp, cmd->dbg_id, event->tag); psl_buffer_write(cmd->afu_event, event->tag, event->addr, CACHELINE_BYTES, event->data, event->parity); event->buffer_activity = 1; } else if (client->mem_access == NULL) { // Send read request to client, set client->mem_access // to point to this event blocking any other memory // accesses to client until data is returned by call // to the _handle_mem_read() function. buffer[0] = (uint8_t) PSLSE_MEMORY_READ; buffer[1] = (uint8_t) event->size; addr = (uint64_t *) & (buffer[2]); *addr = htonll(event->addr); event->abort = &(client->abort); if (put_bytes(client->fd, 10, buffer, cmd->dbg_fp, cmd->dbg_id, event->context) < 0) { client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE); } event->state = MEM_REQUEST; debug_cmd_client(cmd->dbg_fp, cmd->dbg_id, event->tag, event->context); client->mem_access = (void *)event; } }