Raw-OS源代碼分析之消息系統-Queue_Size

        分析的內核版本號截止到2014-04-15。基於1.05正式版。blogs會及時跟進最新版本號的內核開發進度,若源代碼凝視出現」???」字樣,則是未深究理解部分。前端

        Raw-OS官方站點:http://www.raw-os.org/git

        Raw-OS託管地址:https://github.com/jorya/raw-os/github

 

        有了前一講queue的基礎後,此次來講說queue_size這個模塊,前一講的queue通訊,知道queue在通訊時,爲了加快數據的傳遞速度。是不直接發送數據的詳細內容。而是發送指向用戶數據的指針。而且這個指針是void指針。在取出queue其中的數據時,強制轉換這個void指針成發送的原始數據內容的指針類型。就可以準確獲取原始數據。數組

 

        那麼queue_size這個東西,就是將指向原始數據的指針,和表示原始數據大小的變量,再打包封裝成一個新的msg。稱這個msg爲queue_size的msg。數據結構

 

 

 

        這個打包封裝好的msg就是做爲queue_size存儲的基本單元。每一個單元就是一個queue_size的msg。這個msg包括了指向用戶發送數據段的指針void *msg_ptr。和用戶數據段的大小msg_size。函數

        還注意到。另外一個*next的指針存在,這個*next指針就是將這些msg組成一個單項鍊表而存在的,學過數據結構的童鞋都知道~post

 

        現在,結合queue和queue_size總結一下,而後再看看queue_size和queue在內核表示的不一樣方式ui

        1.在queue中,消息是一個可以指向不論什麼數據類型的void指針spa

        2.在queue_size中,消息是一個可以指向不論什麼數據類型的void指針和一個表徵數據大小msg_size變量封裝體指針

 

        在queue中,存放queue消息是經過指針數組來實現的~

 

 

 

        那麼就就可以很是負責任地告訴你,queue_size中。存放queue_size消息是經過單向鏈表來實現的~

 

 

 

        事實上,我的認爲實現queue_size的消息存放時,相同可以用結構的指針數組去實現,但是這樣用戶就需要自定義msg結構體,總感受怪怪的,假設內核封裝過的queue_size的msg。用戶僅僅要傳入一個接收數據的void指針,一個接收數據大小的變量就能夠~

        感受仍是API搞的鬼~

 

        好~現在知道什麼事queue_size的msg。和queue_size的msg在內核的存放形式。那麼還要告訴你的一點就是。Raw-OS還有queue_size的空消息和詳細消息的差異,也就是說,會將存放queue_size的msg分爲兩條鏈表,一條我自稱爲消息鏈表。一條稱爲空暇消息鏈表,尼瑪啊,這又是什麼???

 

 

 

        事實上也很是easy,queue_size初始化時,將queue_size用來存放queue_size的msg的內存空間初始化成空暇消息鏈表,而後當queue_size的msg發送到達時,從空暇消息鏈表中劃一個出來存放消息。那麼存放消息的queue_size鏈表就是消息鏈表~

 

        明確這些要點以後,騷年們~大家可以去看Raw-OS的代碼是怎樣實現的了~

 

        如下附上queue_size有凝視的若干條主要函數,事實上就是建立。發送,接收的而已~

 

        1.Queue_size的建立

RAW_U16 raw_queue_size_create(RAW_QUEUE_SIZE  *p_q, RAW_U8 *p_name, RAW_MSG_SIZE *msg_start, MSG_SIZE_TYPE number)
{
	RAW_MSG_SIZE      *p_msg1;
    RAW_MSG_SIZE      *p_msg2;

    /* 檢查建立消息隊列的邊界條件 */
	#if (RAW_QUEUE_SIZE_FUNCTION_CHECK > 0)
	if (p_q == 0) {
		return RAW_NULL_OBJECT;
	}
	/*
	 * 傳入的消息塊的起始地址。這裏是一個二級指針,一般傳入的是數組指針的首地址
	 * 好比在應用層定義,void* msg[size]。那麼msg[size]就是數組。msg=msg[0]是數組首地址。&msg就是數組指針首地址
	 * 傳入時就是傳入&msg的值。通常會將這個值強制轉成(RAW_VOID **)&msg的形式傳入,可有可無,傳入的是數組指針首地址
	 *
	 * 假設未定義存儲消息的消息數組。錯誤返回
	 */
	if (msg_start == 0) {
		return RAW_NULL_POINTER;
	}
	/* 存儲消息的消息數組大小,需要建立queue時指定,好比定義的是void* msg[10]。那麼這裏傳入的就是10,爲0錯誤返回 */
	if (number == 0) {
		return RAW_ZERO_NUMBER;
	}

	#endif
	/* 初始化queue的堵塞鏈表 */
	list_init(&p_q->common_block_obj.block_list);
	/* queue名稱 */
	p_q->common_block_obj.name = p_name;
	/* queue堵塞方式 */
	p_q->common_block_obj.block_way = RAW_BLOCKED_WAY_PRIO;
	/* current_numbers表明當前在消息數組中的消息數量 */
	p_q->queue_current_msg = 0;
	/* queue歷史最大消息數量 */
	p_q->peak_numbers = 0;
	/* 存儲消息的消息數組的大小 */
	p_q->queue_msg_size = number;
	/* queue中消息起始地址,差異於普通queue,這裏msg_start指向queue_size剩餘空暇元素鏈表 */
	p_q->free_msg = msg_start;

	/*
	 * 空暇消息鏈表初始化
	 *
	 * 在queue_size中,消息數組存放的再也不是void指針,而是RAW_MSG_SIZE類型的元素
	 * 在queue_size組織RAW_MSG_SIZE類型消息時。分爲兩個鏈表,第一個是消息鏈表,第二個是空暇消息鏈表
	 * 這裏初始化的是空暇消息鏈表
	 */
	p_msg1 = msg_start;
	p_msg2 = msg_start;
	p_msg2++;

	while (--number) {
		p_msg1->next = p_msg2;
		p_msg1->msg_ptr = 0;
		p_msg1->msg_size = 0;

		p_msg1++;
		p_msg2++;
	}

	/* 對空暇消息鏈表的最後一個元素。即鏈表尾部,指向不論什麼元素,即消息鏈表和空暇消息鏈表都是單向鏈表 */
	p_msg1->next = 0;
	p_msg1->msg_ptr  = 0;
	p_msg1->msg_size = 0;
	/* 初始queue控制塊對象爲Raw-OS消息隊列對象類型 */
	p_q->common_block_obj.object_type = RAW_QUEUE_SIZE_OBJ_TYPE;

	TRACE_QUEUE_SIZE_CREATE(raw_task_active, p_q);

	return RAW_SUCCESS;

}

        2.發送Queue_size消息

        對於queue_size仍然有發送的queue_size的末端仍是發送到queue_size的前端的發送選擇,這個依據用戶決定消息的緊急程度而定

RAW_U16 raw_queue_size_create(RAW_QUEUE_SIZE  *p_q, RAW_U8 *p_name, RAW_MSG_SIZE *msg_start, MSG_SIZE_TYPE number)
{
	RAW_MSG_SIZE      *p_msg1;
    RAW_MSG_SIZE      *p_msg2;

    /* 檢查建立消息隊列的邊界條件 */
	#if (RAW_QUEUE_SIZE_FUNCTION_CHECK > 0)
	if (p_q == 0) {
		return RAW_NULL_OBJECT;
	}
	/*
	 * 傳入的消息塊的起始地址,這裏是一個二級指針,一般傳入的是數組指針的首地址
	 * 好比在應用層定義,void* msg[size],那麼msg[size]就是數組,msg=msg[0]是數組首地址。&msg就是數組指針首地址
	 * 傳入時就是傳入&msg的值,通常會將這個值強制轉成(RAW_VOID **)&msg的形式傳入,可有可無,傳入的是數組指針首地址
	 *
	 * 假設未定義存儲消息的消息數組。錯誤返回
	 */
	if (msg_start == 0) {
		return RAW_NULL_POINTER;
	}
	/* 存儲消息的消息數組大小,需要建立queue時指定,好比定義的是void* msg[10],那麼這裏傳入的就是10,爲0錯誤返回 */
	if (number == 0) {
		return RAW_ZERO_NUMBER;
	}

	#endif
	/* 初始化queue的堵塞鏈表 */
	list_init(&p_q->common_block_obj.block_list);
	/* queue名稱 */
	p_q->common_block_obj.name = p_name;
	/* queue堵塞方式 */
	p_q->common_block_obj.block_way = RAW_BLOCKED_WAY_PRIO;
	/* current_numbers表明當前在消息數組中的消息數量 */
	p_q->queue_current_msg = 0;
	/* queue歷史最大消息數量 */
	p_q->peak_numbers = 0;
	/* 存儲消息的消息數組的大小 */
	p_q->queue_msg_size = number;
	/* queue中消息起始地址,差異於普通queue,這裏msg_start指向queue_size剩餘空暇元素鏈表 */
	p_q->free_msg = msg_start;

	/*
	 * 空暇消息鏈表初始化
	 *
	 * 在queue_size中。消息數組存放的再也不是void指針,而是RAW_MSG_SIZE類型的元素
	 * 在queue_size組織RAW_MSG_SIZE類型消息時,分爲兩個鏈表,第一個是消息鏈表,第二個是空暇消息鏈表
	 * 這裏初始化的是空暇消息鏈表
	 */
	p_msg1 = msg_start;
	p_msg2 = msg_start;
	p_msg2++;

	while (--number) {
		p_msg1->next = p_msg2;
		p_msg1->msg_ptr = 0;
		p_msg1->msg_size = 0;

		p_msg1++;
		p_msg2++;
	}

	/* 對空暇消息鏈表的最後一個元素。即鏈表尾部,指向不論什麼元素,即消息鏈表和空暇消息鏈表都是單向鏈表 */
	p_msg1->next = 0;
	p_msg1->msg_ptr  = 0;
	p_msg1->msg_size = 0;
	/* 初始queue控制塊對象爲Raw-OS消息隊列對象類型 */
	p_q->common_block_obj.object_type = RAW_QUEUE_SIZE_OBJ_TYPE;

	TRACE_QUEUE_SIZE_CREATE(raw_task_active, p_q);

	return RAW_SUCCESS;

}

        3.接收Queue_size消息

RAW_U16 raw_queue_size_receive(RAW_QUEUE_SIZE *p_q, RAW_TICK_TYPE wait_option, RAW_VOID  **msg_ptr, MSG_SIZE_TYPE *receive_size)
{
	RAW_U16 result;

	RAW_MSG_SIZE  *msg_tmp;

	RAW_SR_ALLOC();
	/* 檢查中斷嵌套,和用戶設置的接收堵塞標誌,僅當用戶設置接收不到消息時不發生堵塞才幹在中斷中接收消息 */
	#if (RAW_QUEUE_SIZE_FUNCTION_CHECK > 0)
	if (raw_int_nesting && (wait_option != RAW_NO_WAIT)) {
		return RAW_NOT_CALLED_BY_ISR;
	}
	/* 檢查傳入消息隊列控制塊的地址。爲空時。說明沒有實體,錯誤返回 */
	if (p_q == 0) {
		return RAW_NULL_OBJECT;
	}
	/* 這裏傳入的是用來存放接收數據後,數據存放的變量。一個二級指針 */
	if (msg_ptr == 0) {
		return RAW_NULL_POINTER;
	}
	/* 這裏傳入的是用來存放接收數據後存放消息大小的變量。一個int或uint就能夠 */
	if (receive_size == 0) {
		return RAW_NULL_POINTER;
	}
	#endif
	/* 當開啓task 0後,消息由task 0轉發??? */
	#if (CONFIG_RAW_ZERO_INTERRUPT > 0)
	if (raw_int_nesting) {
		return RAW_NOT_CALLED_BY_ISR;
	}
	#endif

	RAW_CRITICAL_ENTER();

	/* 假設傳入的queue控制的類型對象不是Raw-OS的隊列對象。錯誤返回 */
	if (p_q->common_block_obj.object_type != RAW_QUEUE_SIZE_OBJ_TYPE) {
		RAW_CRITICAL_EXIT();
		return RAW_ERROR_OBJECT_TYPE;
	}

	/*
	 * 獲取queue_size中消息的實現過程
	 *
	 * 推斷queue_size是否有消息,假設沒有。想要獲取queue_size的任務堵塞
	 * 存在消息時:
	 *     1.暫時消息msg_tmp指向讀指針。因爲讀指針指向消息鏈表的第一個消息,那麼msg_tmp就指向第一個消息
	 *     2.傳入的存放queue_size消息的內容指針指向第一個消息中的內容指針
	 *     3.傳入的存放queue_size消息的大小變量變爲第一個消息的大小
	 *     4.消息鏈表的read指針後移到下一個消息
	 *	   5.回收消息鏈表被讀取的消息。置空後歸還到空暇消息鏈表
	 *
	 */
	if (p_q->queue_current_msg) {
		/* 指向read指針 */
		msg_tmp =   p_q->read;
		/* 讀取queue_size消息內容 */
		*msg_ptr = msg_tmp->msg_ptr;
		/* 讀取queue_size消息大小 */
		*receive_size = msg_tmp->msg_size;
		/* read指針後移 */
	    p_q->read = msg_tmp->next;
	    /* 消息鏈表不爲空時(消息鏈表的最後一個消息下一個消息連接爲0)。存在消息鏈表的消息數量-- */
	    if (p_q->read) {
	         p_q->queue_current_msg--;
	    }
	    /* 消息鏈表爲空時,write指針置0。消息數量清0 */
		else {
			p_q->write     = 0;
			p_q->queue_current_msg = 0;
	    }

	    /* 回收消息鏈表被讀取的消息內存空間,增長到空間消息鏈表 */
		msg_tmp->next = p_q->free_msg;
		p_q->free_msg =  msg_tmp;

		RAW_CRITICAL_EXIT();

		TRACE_QUEUE_SIZE_GET_MSG(raw_task_active, p_q, wait_option, *msg_ptr, *receive_size);

		return RAW_SUCCESS;
	}

	/* 用戶設置不堵塞標誌時,返回空指針queue_size消息,大小爲0 */
	if (wait_option == RAW_NO_WAIT) {

		*msg_ptr    = 0;
		*receive_size   = 0;

		RAW_CRITICAL_EXIT();

		return RAW_NO_PEND_WAIT;
	}

	SYSTEM_LOCK_PROCESS_QUEUE_SIZE();
	/* 當queue_size沒有消息時。對要獲取queue_size消息進行堵塞。堵塞到queue_size的堵塞鏈表上 */
	raw_pend_object((RAW_COMMON_BLOCK_OBJECT  *)p_q, raw_task_active, wait_option);

	RAW_CRITICAL_EXIT();

	TRACE_QUEUE_SIZE_GET_BLOCK(raw_task_active, p_q, wait_option);
	/* 系統任務調度 */
	raw_sched();
	/* 獲取堵塞任務被調度時的堵塞返回狀態 */
	result = block_state_post_process(raw_task_active, 0);

	/* 假設堵塞任務是queue_size存在消息被調度的,不是因爲堵塞超時等等的狀況調度,那麼將獲取queue_size消息 */
	if (result == RAW_SUCCESS) {
		/* 以前分析過post msg時。消息是直接發送到任務控制塊中的,當堵塞任務被調度時,從任務控制塊中取出消息給msg,返回調度後堵塞狀態 */
		*receive_size = raw_task_active->msg_size;
		*msg_ptr =  raw_task_active->msg;
	}

	else {
		*msg_ptr    = 0;
		*receive_size   = 0;
	}

	return result;
}
相關文章
相關標籤/搜索