/* * \brief This function pop command from queue with specific priority. * * Returned command is allocated on the heap and have to be free from calling * function. When *count is not NULL, then this function will write number of * commands with same ID that could be compressed on this address. When *len * is not NULL, then this function will write length of compressed commands * at this address. When *len value is not 0, then this value represents maximal * size of commands that could be removed from this priority queue. * * \param[in] *out_queue The pointer at list of priority queues * \param[in] prio The value of priority * \param[out] *count The pointer at count of commands with same id that * could be compressed. * \param[out] *share The size of address that could be shared * \param[out] *len The length of compressed commands. * * \return This function returns pointer at command. This command is allocated * at the heap. */ struct Generic_Cmd *v_out_queue_pop(struct VOutQueue *out_queue, uint8 prio, uint16 *count, int8 *share, uint16 *len) { struct VPrioOutQueue *prio_queue = out_queue->queues[prio]; struct VOutQueueCommand *queue_cmd; struct Generic_Cmd *cmd=NULL; int i, can_pop_cmd = 1; /* Lock mutex */ pthread_mutex_lock(&out_queue->lock); /*printf("\tcount: %u, share: %u, len: %u\n", *count, *share, *len);*/ queue_cmd = prio_queue->cmds.first; if(queue_cmd != NULL ) { cmd = (struct Generic_Cmd *)queue_cmd->vbucket->data; assert(cmd != NULL); /* Return value of count and length of compressed commands */ if(queue_cmd->counter != NULL) { if(count != NULL) { *count = *queue_cmd->counter; } if(share != NULL) { *share = *queue_cmd->share; } if(len != NULL) { /* When *len value is not 0, then this value represents maximal * size of buffer that could be filled with this priority queue. This * function should return value, that is smaller or equal than this * maximum. */ if(*len != 0) { if(*len < *queue_cmd->len) { if (count != NULL) { *count = v_cmd_count(cmd, *len, *queue_cmd->share); /* FIXME: compute length and count correctly, when command is added to the queue */ *count = ((*count) > (*queue_cmd->counter)) ? *queue_cmd->counter : *count; /* Is enough space in buffer to unpack this command? */ if(*count == 0) { can_pop_cmd = 0; } *len = v_cmds_len(cmd, *count, *queue_cmd->share, 0); } else { can_pop_cmd = 0; } } else { *len = *queue_cmd->len; } } else { *len = *queue_cmd->len; } } } else { if(count != NULL) { *count = 0; } if(share != NULL) { *share = 0; } if(len != NULL) { if(v_cmd_size(cmd) > *len) { can_pop_cmd = 0; } *len = 0; } } /* Is it possible to pop command from the queue */ if(can_pop_cmd == 1) { /* Remove command from hashed linked list */ v_hash_array_remove_item(&out_queue->cmds[cmd->id]->cmds, (void*)cmd); /* Remove command from priority queue */ v_list_rem_item(&prio_queue->cmds, queue_cmd); /* Update total count and size of commands */ out_queue->count--; out_queue->size -= out_queue->cmds[cmd->id]->item_size; /* Update count and size of commands in subqueue with priority prio */ out_queue->queues[prio]->count--; out_queue->queues[prio]->size -= out_queue->cmds[cmd->id]->item_size; /* If needed, then update counter of commands with the same id in the queue */ if(queue_cmd->counter != NULL) { *queue_cmd->counter -= 1; /* Free values, when it's last command in the queue */ if(*queue_cmd->counter == 0) { free(queue_cmd->counter); queue_cmd->counter = NULL; free(queue_cmd->share); queue_cmd->share = NULL; free(queue_cmd->len); queue_cmd->len = NULL; } } /* When this priority queue is empty now, then update summary of * real priorities and it is possibly necessary to change maximal * or minimal priority queue*/ if(out_queue->queues[prio]->count == 0) { if(prio>=VRS_DEFAULT_PRIORITY) { out_queue->r_prio_sum_high -= out_queue->queues[prio]->r_prio; } else { out_queue->r_prio_sum_low -= out_queue->queues[prio]->r_prio; } if(out_queue->max_prio == prio && out_queue->min_prio != prio) { for(i=prio; i>=out_queue->min_prio; i--) { if(out_queue->queues[i]->count != 0) { out_queue->max_prio = i; break; } } } else if(out_queue->min_prio == prio && out_queue->max_prio != prio) { for(i=prio; i<=out_queue->max_prio; i++) { if(out_queue->queues[i]->count != 0) { out_queue->min_prio = i; break; } } } else if(out_queue->min_prio == prio && out_queue->max_prio == prio) { out_queue->min_prio = out_queue->max_prio = VRS_DEFAULT_PRIORITY; } } /* Free queue command */ free(queue_cmd); } else { cmd = NULL; } } pthread_mutex_unlock(&out_queue->lock); return cmd; }
/** * \brief This function add VQueueCommand to the priority queue */ static void _v_out_queue_command_add(struct VPrioOutQueue *prio_queue, uint8 flag, uint8 share_addr, struct VOutQueueCommand *queue_cmd, struct Generic_Cmd *cmd) { struct VOutQueueCommand *border_queue_cmd = NULL; /* Will be command added to then head or tail of queue? */ if(flag & OUT_QUEUE_ADD_TAIL) { border_queue_cmd = prio_queue->cmds.last; } else if(flag & OUT_QUEUE_ADD_HEAD) { border_queue_cmd = prio_queue->cmds.first; } /* Add command to the end of new priority queue. If needed * update counter of same commands in the queue */ if(border_queue_cmd != NULL) { /* Is ID of this command same as ID of the last command * in this priority queue? */ if( (share_addr == 1) && (border_queue_cmd->id == queue_cmd->id)) { struct Generic_Cmd *border_cmd = (struct Generic_Cmd *)border_queue_cmd->vbucket->data; /* Is the last command in this priority queue and the * first command with this ID? */ if(border_queue_cmd->counter == NULL) { /* Set initial number of commands with same ID */ border_queue_cmd->counter = (uint16*)malloc(sizeof(uint16)); *border_queue_cmd->counter = 1; /* Compute size of address that could be shared */ border_queue_cmd->share = (int8*)malloc(sizeof(int8)); *border_queue_cmd->share = v_cmd_cmp_addr(border_cmd, cmd, 0xFF); /* Allocate memory for length of compressed commands */ border_queue_cmd->len = (uint16*)malloc(sizeof(uint16)); *border_queue_cmd->len = v_cmds_len(border_cmd, *border_queue_cmd->counter, *border_queue_cmd->share, 0); } else if(*border_queue_cmd->share > 0) { /* Try to update size of address that could be shared */ *border_queue_cmd->share = v_cmd_cmp_addr(border_cmd, cmd, *border_queue_cmd->share); } /* Set up pointer */ queue_cmd->counter = border_queue_cmd->counter; queue_cmd->share = border_queue_cmd->share; queue_cmd->len = border_queue_cmd->len; /* Update values */ (*queue_cmd->counter)++; *queue_cmd->len = v_cmds_len(cmd, *queue_cmd->counter, *queue_cmd->share, *queue_cmd->len); } else { queue_cmd->counter = NULL; queue_cmd->share = NULL; queue_cmd->len = NULL; } } /* Will be command added to then head or tail of queue? */ if(flag & OUT_QUEUE_ADD_TAIL) { v_list_add_tail(&prio_queue->cmds, queue_cmd); } else if(flag & OUT_QUEUE_ADD_HEAD) { v_list_add_head(&prio_queue->cmds, queue_cmd); } }
/** * \brief This function packs and compress command to the packet from one * priority queue. * * \param[in] *C The verse context * \param[in] *sent_packet The pointer at structure with send packet * \param[in] buffer_pos The curent size of buffer of sent packet * \param[in] prio The priority of sub queue * \param[in] prio_win The window size of current prio queue * \param[out] tot_cmd_size The total size of commands that were poped from prio queue */ static int pack_prio_queue(struct vContext *C, struct VSent_Packet *sent_packet, int buffer_pos, uint8 prio, uint16 prio_win, uint16 *tot_cmd_size) { struct VSession *vsession = CTX_current_session(C); struct VDgramConn *vconn = CTX_current_dgram_conn(C); struct IO_CTX *io_ctx = CTX_io_ctx(C); struct Generic_Cmd *cmd; int ret, last_cmd_count = 0; uint16 cmd_count, cmd_len, cmd_size, sum_len=0; int8 cmd_share; uint8 last_cmd_id = CMD_RESERVED_ID; while( (v_out_queue_get_count_prio(vsession->out_queue, prio) > 0) && (sum_len < prio_win) && (buffer_pos < vconn->io_ctx.mtu)) { cmd_count = 0; cmd_share = 0; /* Compute how many commands could be compressed to the packet * and compute right length of compressed commands. */ cmd_len = ((prio_win - sum_len)<(vconn->io_ctx.mtu - buffer_pos)) ? (prio_win - sum_len) : (vconn->io_ctx.mtu - buffer_pos); /* Remove command from queue */ cmd = v_out_queue_pop(vsession->out_queue, prio, &cmd_count, &cmd_share, &cmd_len); /* When it is not possible to pop more commands from queue, then break * while loop */ if(cmd == NULL) { break; } /* Is this command fake command? */ if(cmd->id < MIN_CMD_ID) { if(cmd->id == FAKE_CMD_CONNECT_TERMINATE) { struct VS_CTX *vs_ctx = CTX_server_ctx(C); if(vs_ctx != NULL) { vconn->host_state = UDP_SERVER_STATE_CLOSEREQ; } else { vconn->host_state = UDP_CLIENT_STATE_CLOSING; } } else if(cmd->id == FAKE_CMD_FPS) { struct Fps_Cmd *fps_cmd = (struct Fps_Cmd*)cmd; /* Change value of FPS. It will be sent in negotiate command * until it is confirmed be the peer (server) */ vsession->fps_host = fps_cmd->fps; } v_cmd_destroy(&cmd); } else { /* What was size of command in queue */ cmd_size = v_cmd_size(cmd); if(!(buffer_pos < (vconn->io_ctx.mtu - cmd_size))) { /* When there is not enough space for other command, * then push command back to the beginning of queue. */ v_out_queue_push_head(vsession->out_queue, prio, cmd); break; } else { /* Update total size of commands that were poped from queue */ *tot_cmd_size += cmd_size; /* When compression is not allowed, then add this command as is */ if( vconn->host_cmd_cmpr == CMPR_NONE) { cmd_count = 0; cmd_len = cmd_size; /* Debug print */ v_print_log(VRS_PRINT_DEBUG_MSG, "Cmd: %d, count: %d, length: %d\n", cmd->id, cmd_count, cmd_len); /* Add command to the buffer */ buffer_pos += v_cmd_pack(&io_ctx->buf[buffer_pos], cmd, cmd_len, 0); } else { /* When command compression is allowed and was ID of command changed? */ if( (cmd->id != last_cmd_id) || (last_cmd_count <= 0) ) { /* When this command is alone, then use default command size */ if(cmd_count == 0) { cmd_len = cmd_size; } else { /* FIXME: do not recompute command length here, but do it right, * when command is added to the queue */ cmd_len = v_cmds_len(cmd, cmd_count, cmd_share, cmd_len); } /* Debug print */ v_print_log(VRS_PRINT_DEBUG_MSG, "Cmd: %d, count: %d, length: %d\n", cmd->id, cmd_count, cmd_len); /* Add command to the buffer */ buffer_pos += v_cmd_pack(&io_ctx->buf[buffer_pos], cmd, cmd_len, cmd_share); /* Set up current count of commands in the line */ last_cmd_count = cmd_count; /* Update summary of commands length */ sum_len += cmd_len; } else { buffer_pos += v_cmd_pack(&io_ctx->buf[buffer_pos], cmd, 0, cmd_share); } } /* Print command */ v_cmd_print(VRS_PRINT_DEBUG_MSG, cmd); /* TODO: remove command alias here (layer value set/unset) */ /* Add command to the packet history */ ret = v_packet_history_add_cmd(&vconn->packet_history, sent_packet, cmd, prio); assert(ret==1); /* Update last command id */ last_cmd_id = cmd->id; /* Decrement counter of commands in queue */ last_cmd_count--; } } } return buffer_pos; }