Threadx 消息隊列-發送消息_tx_queue_send

消息隊列-發送消息_tx_queue_send

1,發送消息會插入到隊列尾部。
2,如果消息隊列有掛起的接收線程,發送消息時,可以直接把消息放到接收線程的緩衝中,這可以降低消息傳遞延時。
TX_THREAD線程控制塊中tx_additional_suspend_info域用於存儲接收線程緩衝區地址。
3,如果消息隊列已滿,發送線程調用_tx_queue_send(wait_option不爲0)發送消息時,線程會被掛起到隊列tx_queue_suspension_list。其它線程接收消息時,會恢復掛起的線程。

在這裏插入圖片描述

source_ptr參數指向發送消息的指針

UINT    _tx_queue_send(TX_QUEUE *queue_ptr, VOID *source_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 place message in the queue.  */
    #def 禁止中斷,防止下面操作被打斷
    TX_DISABLE

    /* Determine if there is room in the queue.  */
   
    if (queue_ptr -> tx_queue_available_storage)
    {
		#def 隊列中有可用空間
        /* Now determine if there is a thread waiting for a message.  */
        if (!queue_ptr -> tx_queue_suspension_list)
        {
			#def 掛起list中沒有掛起線程,直接把消息插入隊列尾部
            /* No thread suspended while waiting for a message from
               this queue.  */

            /* Simply place the message in the queue.  */

            /* Reduce the amount of available storage.  */
            #def 可用容量減1
            queue_ptr -> tx_queue_available_storage--;

            /* Increase the enqueued count.  */
            #def 隊列中當前消息個數加1
            queue_ptr -> tx_queue_enqueued++;

            /* Setup source and destination pointers.  */
            #def source_ptr爲發送消息的指針   tx_queue_write爲隊列中可寫空間首地址,把消息放到這個地址開始處
            source = (ULONG_PTR) source_ptr;
            destination = (ULONG_PTR) queue_ptr -> tx_queue_write;

            /* Copy the message into the queue.  */
            #def 根據消息大小tx_queue_message_size佔用的word個數進行copy,這裏採用了特殊處理,沒有break
            switch (queue_ptr -> tx_queue_message_size)
            {
				#def tx_queue_message_size爲16是,需要copy 16此
                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.  */
				#def tx_queue_message_size爲8時,copy 8次,
                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_write 指針如果到了隊列末尾,那麼重頭開始
            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;

            /* Set status to success.  */
            status =  TX_SUCCESS;
        }
        else
        {
			#def 消息隊列中有可用空間,並且掛起隊列中線程等待,說明消息隊列中沒有任何消息,有消息的話不可能掛起線程等待
			#def 這種情況下,沒有把消息放到消息隊列tx_queue_write 處,而是直接放到了等待線程的緩衝區
			#def 等待線程在調度_tx_queue_receive時,發現隊列中沒有消息,就自我掛起到了tx_queue_suspension_list中,
			#def 並且把_tx_queue_receive 接收緩衝區指針存儲到了TX_THREAD控制塊的tx_additional_suspend_info域
			
            /* Thread suspended waiting for a message.  Remove it and copy this message
               into its storage area.  */
            #def 取tx_queue_suspension_list隊列中最前面線程,FIFO規則,並沒有按照優先級高低順序
            thread_ptr =  queue_ptr -> tx_queue_suspension_list;

            /* See if this is the only suspended thread on the list.  */
            #def 從tx_queue_suspension_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 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

            /* Setup source and destination pointers.  */
            source = (ULONG_PTR) source_ptr;
            #def tx_additional_suspend_info中存儲了之前接收線程的接收緩衝區指針
            destination = (ULONG_PTR) thread_ptr -> tx_additional_suspend_info;
			
			#def 把發送消息source_ptr copy 到tx_additional_suspend_info 接收緩衝區
            /* Copy the message into the thread's destination.  */
            switch (queue_ptr -> tx_queue_message_size)
            {

                default:

                    /* Copy a sixteen longword message into the thread's destination.  */
                    *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 thread's destination.  */
                    *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 thread's destination.  */
                    *destination++ =  *source++;
                    *destination++ =  *source++;
                /* Fall through to copy the remaining two longwords.  */

                case TX_2_ULONG:

                    /* Copy a two longword message into the thread's destination.  */
                    *destination++ =  *source++;
                /* Fall through to copy the remaining longword.  */

                case TX_1_ULONG:

                    /* Copy single longword message into the thread's destination.  */
                    *destination =  *source;
            }

            /* 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_queue_receive函數要使用的變量, 這個掛起線程掛起,現在恢復後,作爲_tx_queue_receive函數返回值
            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 successful status.  */
            return (TX_SUCCESS);
        }
    }
    else
    {
		#def 消息隊列已經沒有可用空間 ,消息隊列是滿的,需要掛起這個發送線程,等有空間在發送消息
		#def 由於消息隊列是滿,肯定沒有接收線程掛起。 所以掛起到tx_queue_suspension_list的一定是發送線程
		#def 掛起時,把要發送的消息指針source_ptr,存放到了tx_additional_suspend_info 中,所以tx_additional_suspend_info 這個變量可以存儲接收線程的接收緩衝區指針,也可以存儲發送消息指針

		
        /* Determine if the request specifies suspension.  */
        if (wait_option)
        {
			#def wait_option不爲0才掛起發送線程,爲0,函數就直接返回失敗
            /* 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 發送消息指針source_ptr暫存到TX_THREAD控制塊的tx_additional_suspend_info 域
            thread_ptr -> tx_additional_suspend_info = (VOID_PTR) source_ptr;

            /* Setup suspension list.  */
            #def 把發送線程插入到tx_queue_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.  */
            #def 開始掛起過程,所以這裏必須設置tx_suspending 標誌,_tx_thread_suspend中會檢查
            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 不爲TX_WAIT_FOREVER開啓定時器,定時器超時會把這個線程從掛起隊列移除
            if (wait_option != TX_WAIT_FOREVER)
            {

                /* A timeout is required.  */

                /* Activate the thread timer for 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_receive函數中設置
            return (thread_ptr -> tx_suspend_status);
        }
        else

            /* Immediate return, return error completion.  */
            status =  TX_QUEUE_FULL;
    }

    /* Restore interrupts.  */
    TX_RESTORE

    /* Return completion status.  */
    return (status);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章