Threadx 消息队列-接收消息_tx_queue_receive

消息队列-接收消息_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);
}
发布了41 篇原创文章 · 获赞 2 · 访问量 3243

猜你喜欢

转载自blog.csdn.net/qq_45683435/article/details/104215740