分析的內核版本號截止到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; }