消息队列-接收消息_tx_queue_receive
1,如果消息队列有消息,从队列头部取出消息
(1)并且tx_queue_suspension_list有挂起线程,说明发送线程由于消息队列已满而挂起,挂起时把发送的消息
存放到了发送线程的tx_additional_suspend_info域,需要把这个消息移动到消息队列尾部,并且恢复发送线程
2,如果消息队列为空,挂起接收线程到tx_queue_suspension_list队列,并把接收缓冲区指针暂存到接收线程的tx_additional_suspend_info域。等到发送消息发送消息时,会把发送消息直接存储到tx_additional_suspend_info中缓冲区指针并恢复接收线程。
UINT _tx_queue_receive(TX_QUEUE *queue_ptr, VOID *destination_ptr, ULONG wait_option)
{
TX_INTERRUPT_SAVE_AREA
REG_1 UINT status; /* Return status */
REG_2 TX_THREAD *thread_ptr; /* Working thread pointer */
REG_3 ULONG_PTR source; /* Source pointer */
REG_4 ULONG_PTR destination; /* Destination pointer */
/* Disable interrupts to receive message from queue. */
#def 禁止中断,防止被打断
TX_DISABLE
/* Determine if there is anything in the queue. */
if (queue_ptr -> tx_queue_enqueued)
{
#def 消息队列中有消息
/* Setup source and destination pointers. */
#def tx_queue_read指向第一个可读消息,消息队列头部
source = (ULONG_PTR) queue_ptr -> tx_queue_read;
#def 接收进程的接收缓冲区指针
destination = (ULONG_PTR) destination_ptr;
#def 把消息队列最前面消息复制到接收缓冲区
/* Yes, there is something in the queue. Place the oldest message in the
queue into the thread's area. */
switch (queue_ptr -> tx_queue_message_size)
{
default:
/* Copy a sixteen longword message from the queue. */
*destination++ = *source++;
*destination++ = *source++;
*destination++ = *source++;
*destination++ = *source++;
*destination++ = *source++;
*destination++ = *source++;
*destination++ = *source++;
*destination++ = *source++;
/* Fall through to copy the remaining eight longwords. */
case TX_8_ULONG:
/* Copy an eight longword message from the queue. */
*destination++ = *source++;
*destination++ = *source++;
*destination++ = *source++;
*destination++ = *source++;
/* Fall through to copy the remaining four longwords. */
case TX_4_ULONG:
/* Copy a four longword message from the queue. */
*destination++ = *source++;
*destination++ = *source++;
/* Fall through to copy the remaining two longwords. */
case TX_2_ULONG:
/* Copy a two longword message from the queue. */
*destination++ = *source++;
/* Fall through to copy the remaining longword. */
case TX_1_ULONG:
/* Copy single longword message from the queue. */
*destination = *source;
}
/* Adjust the read pointer. */
#def 消息队列最前面消息已经被读走,那么tx_queue_read 移动到下一个消息地址
queue_ptr -> tx_queue_read =
queue_ptr -> tx_queue_read + queue_ptr -> tx_queue_message_size;
/* Determine if we are at the end. */
#def 如果移动后,tx_queue_read 已经到底消息队列尾部地址,那么设置tx_queue_read 为tx_queue_start,循环一圈
if (queue_ptr -> tx_queue_read >= queue_ptr -> tx_queue_end)
/* Yes, wrap around to the beginning. */
queue_ptr -> tx_queue_read = queue_ptr -> tx_queue_start;
/* Successful service. */
status = TX_SUCCESS;
/* Now determine if there is a thread waiting to place a message in the queue. */
if (!queue_ptr -> tx_queue_suspension_list)
{
#def 挂起队列中没有发送线程挂起,可以返回了
/* No thread waiting on full queue. */
/* Increase the amount of available storage. */
#def 可用空间加1
queue_ptr -> tx_queue_available_storage++;
/* Decrease the enqueued count. */
#def 队列中消息减一
queue_ptr -> tx_queue_enqueued--;
}
else
{
#def tx_queue_suspension_list不为空,发送线程在_tx_queue_send发送消息时发现消息队列满了,
#def 自我挂起到了tx_queue_suspension_list,并把发送消息指针存储到了tx_additional_suspend_info域,
#def 那么先需要把在tx_additional_suspend_info中存储发送消息移动回消息队列尾部 (前面读取了消息,消息队列有了一个空间)
/* Disable preemption. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
/* Interrupts are enabled briefly here to keep the interrupt
lockout time deterministic. */
/* Disable interrupts again. */
TX_DISABLE
/* Decrement the preemption disable variable. */
_tx_thread_preempt_disable--;
/* Thread suspended waiting to place a message in the queue. Copy its message
into the queue and remove it from the suspension list. */
thread_ptr = queue_ptr -> tx_queue_suspension_list;
/* Setup source and destination pointers. */
#def tx_additional_suspend_info存储了挂起线程的发送消息指针
source = (ULONG_PTR) thread_ptr -> tx_additional_suspend_info;
#def 消息队列可以指针,也就是消息队列尾部
destination = (ULONG_PTR) queue_ptr -> tx_queue_write;
#def 复制消息
/* Copy the message into the queue. */
switch (queue_ptr -> tx_queue_message_size)
{
default:
/* Copy a sixteen longword message into the queue. */
*destination++ = *source++;
*destination++ = *source++;
*destination++ = *source++;
*destination++ = *source++;
*destination++ = *source++;
*destination++ = *source++;
*destination++ = *source++;
*destination++ = *source++;
/* Fall through to copy the remaining eight longwords. */
case TX_8_ULONG:
/* Copy an eight longword message into the queue. */
*destination++ = *source++;
*destination++ = *source++;
*destination++ = *source++;
*destination++ = *source++;
/* Fall through to copy the remaining four longwords. */
case TX_4_ULONG:
/* Copy a four longword message into the queue. */
*destination++ = *source++;
*destination++ = *source++;
/* Fall through to copy the remaining two longwords. */
case TX_2_ULONG:
/* Copy a two longword message into the queue. */
*destination++ = *source++;
/* Fall through to copy the remaining longword. */
case TX_1_ULONG:
/* Copy single longword message into the queue. */
*destination = *source;
}
/* Adjust the write pointer. */
#def tx_queue_write 位置已经写入消息,移动指向下一个可写位置
queue_ptr -> tx_queue_write =
queue_ptr -> tx_queue_write + queue_ptr -> tx_queue_message_size;
/* Determine if we are at the end. */
#def 如果已经移动到了尾部,那么指向tx_queue_start,绕了一圈
if (queue_ptr -> tx_queue_write >= queue_ptr -> tx_queue_end)
/* Yes, wrap around to the beginning. */
queue_ptr -> tx_queue_write = queue_ptr -> tx_queue_start;
#def 从tx_queue_suspension_list 中移除线程,这里还是fifo,并没有按照线程优先级高低顺序
/* Message is now in the queue. See if this is the only suspended thread
on the list. */
if (thread_ptr == thread_ptr -> tx_suspended_next)
{
/* Yes, the only suspended thread. */
/* Update the head pointer. */
queue_ptr -> tx_queue_suspension_list = TX_NULL;
}
else
{
/* At least one more thread is on the same expiration list. */
/* Update the list head pointer. */
queue_ptr -> tx_queue_suspension_list = thread_ptr -> tx_suspended_next;
/* Update the links of the adjacent threads. */
(thread_ptr -> tx_suspended_next) -> tx_suspended_previous =
thread_ptr -> tx_suspended_previous;
(thread_ptr -> tx_suspended_previous) -> tx_suspended_next =
thread_ptr -> tx_suspended_next;
}
/* Decrement the suspension count. */
queue_ptr -> tx_queue_suspended_count--;
/* Prepare for resumption of the first thread. */
/* Clear cleanup routine to avoid timeout. */
thread_ptr -> tx_suspend_cleanup = TX_NULL;
/* Temporarily disable preemption. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
/* Deactivate the timeout timer if necessary. */
if (thread_ptr -> tx_thread_timer.tx_list_head)
{
/* Deactivate the thread's timeout timer. */
_tx_timer_deactivate(&(thread_ptr -> tx_thread_timer));
}
else
{
/* Clear the remaining time to ensure timer doesn't get activated. */
thread_ptr -> tx_thread_timer.tx_remaining_ticks = 0;
}
/* Put return status into the thread control block. */
#def 设置tx_suspend_status 为成功,这个值是发送线程恢复后,_tx_queue_send函数返回值
thread_ptr -> tx_suspend_status = TX_SUCCESS;
/* Resume thread. */
if (_tx_thread_resume(thread_ptr))
/* Preemption is required, transfer control back to
system. */
_tx_thread_system_return();
/* Return success. */
return (TX_SUCCESS);
}
}
else
{
#def 消息队列中没有消息,wait_option为0,函数直接返回
#def wait_option不为0,线程自我挂起到tx_queue_suspension_list,并且把接收缓冲区指针存储在tx_additional_suspend_info 中
#def 发送线程_tx_queue_send发送消息时,把消息直接copy到tx_additional_suspend_info 存储的接收缓冲区指针地址
/* Determine if the request specifies suspension. */
if (wait_option)
{
#def 线程自我挂起
/* Prepare for suspension of this thread. */
/* Pickup thread pointer. */
thread_ptr = _tx_thread_current_ptr;
/* Setup cleanup routine pointer. */
thread_ptr -> tx_suspend_cleanup = _tx_queue_cleanup;
/* Setup cleanup information, i.e. this queue control
block and the source pointer. */
thread_ptr -> tx_suspend_control_block = (VOID_PTR) queue_ptr;
#def接收缓冲区指针存储在tx_additional_suspend_info 中
thread_ptr -> tx_additional_suspend_info = (VOID_PTR) destination_ptr;
/* Setup suspension list. */
if (queue_ptr -> tx_queue_suspension_list)
{
/* This list is not NULL, add current thread to the end. */
thread_ptr -> tx_suspended_next =
queue_ptr -> tx_queue_suspension_list;
thread_ptr -> tx_suspended_previous =
(queue_ptr -> tx_queue_suspension_list) -> tx_suspended_previous;
((queue_ptr -> tx_queue_suspension_list) -> tx_suspended_previous) -> tx_suspended_next =
thread_ptr;
(queue_ptr -> tx_queue_suspension_list) -> tx_suspended_previous = thread_ptr;
}
else
{
/* No other threads are suspended. Setup the head pointer and
just setup this threads pointers to itself. */
queue_ptr -> tx_queue_suspension_list = thread_ptr;
thread_ptr -> tx_suspended_next = thread_ptr;
thread_ptr -> tx_suspended_previous = thread_ptr;
}
/* Increment the suspended thread count. */
queue_ptr -> tx_queue_suspended_count++;
/* Set the state to suspended. */
thread_ptr -> tx_state = TX_QUEUE_SUSP;
/* Set the suspending flag. */
thread_ptr -> tx_suspending = TX_TRUE;
/* Temporarily disable preemption. */
_tx_thread_preempt_disable++;
/* Save the timeout value. */
thread_ptr -> tx_thread_timer.tx_remaining_ticks = wait_option;
/* Restore interrupts. */
TX_RESTORE
/* See if we need to start a timer. */
#def wait_option 不为TX_WAIT_FOREVER 开启定时器,定时器超时,会调用tx_suspend_cleanup 清除相关数据
if (wait_option != TX_WAIT_FOREVER)
{
/* A timeout is required. */
/* Activate the thread timer for the timeout. */
_tx_timer_activate(&(thread_ptr -> tx_thread_timer));
}
/* Call actual thread suspension routine. */
#def 挂起
_tx_thread_suspend(thread_ptr);
/* Return the completion status. */
#def 线程恢复后,返回值为tx_suspend_status, 这个值在_tx_queue_send中设置,或者前面定时器超时,返回失败
return (thread_ptr -> tx_suspend_status);
}
else
/* Immediate return, return error completion. */
status = TX_QUEUE_EMPTY;
}
/* Restore interrupts. */
TX_RESTORE
/* Return completion status. */
return (status);
}