Raw-OS源代码分析之消息系统-Queue_Size

分析的内核版本号截止到2014-04-15。基于1.05正式版。blogs会及时跟进最新版本号的内核开发进度,若源代码凝视出现”???”字样,则是未深究理解部分。

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

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

有了前一讲queue的基础后,这次来说说queue_size这个模块,前一讲的queue通信,知道queue在通信时,为了加快数据的传递速度。是不直接发送数据的详细内容。而是发送指向用户数据的指针。并且这个指针是void指针。在取出queue其中的数据时,强制转换这个void指针成发送的原始数据内容的指针类型。就能够准确获取原始数据。

那么queue_size这个东西,就是将指向原始数据的指针,和表示原始数据大小的变量,再打包封装成一个新的msg。称这个msg为queue_size的msg。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdG9ydG9pc2VjaGFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

这个打包封装好的msg就是作为queue_size存储的基本单元。每个单元就是一个queue_size的msg。这个msg包括了指向用户发送数据段的指针void *msg_ptr。和用户数据段的大小msg_size。

还注意到。另一个*next的指针存在,这个*next指针就是将这些msg组成一个单项链表而存在的,学过数据结构的童鞋都知道~

如今,结合queue和queue_size总结一下,然后再看看queue_size和queue在内核表示的不同方式

1.在queue中,消息是一个能够指向不论什么数据类型的void指针

2.在queue_size中,消息是一个能够指向不论什么数据类型的void指针和一个表征数据大小msg_size变量封装体

在queue中,存放queue消息是通过指针数组来实现的~

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdG9ydG9pc2VjaGFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

那么就就能够非常负责任地告诉你,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分为两条链表,一条我自称为消息链表。一条称为空暇消息链表,尼玛啊,这又是什么???

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdG9ydG9pc2VjaGFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

事实上也非常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;
}
时间: 2024-10-14 00:34:50

Raw-OS源代码分析之消息系统-Queue_Size的相关文章

Raw-OS源代码分析之消息系统-Queue_Buffer

分析的内核版本号截止到2014-04-15,基于1.05正式版.blogs会及时跟进最新版本号的内核开发进度,若源代码凝视出现"???"字样,则是未深究理解部分. Raw-OS官方站点:http://www.raw-os.org/ Raw-OS托管地址:https://github.com/jorya/raw-os/ 有了之前的queue和queue_size的解读之后.这个queue_buffer就很之简单了~对于queue是转发消息的指针,queue_size则是转发消息指针和消息

Memcached源代码分析 - Memcached源代码分析之消息回应(3)

文章列表: <Memcached源代码分析 - Memcached源代码分析之基于Libevent的网络模型(1)> <Memcached源代码分析 - Memcached源代码分析之命令解析(2)> <Memcached源代码分析 - Memcached源代码分析之消息回应(3)  > <Memcached源代码分析 - Memcached源代码分析之HashTable(4) > <Memcached源代码分析 - Memcached源代码分析之增删

[Android源代码分析]Android消息机制,Handler,Message,Looper,MessageQueue

最近准备把Android源码大致过一遍,不敢私藏,写出来分享给大家,顺便记录一下自己的学习感悟.里面一定有一些错误的地方,希望广大看客理解理解. 网上也有不少分析文章,这里我尽量分析的更加细致详尽.不留死角. 一.核心循环体:Looper.loop(); 我们知道,在线程run()中Looper.prepare();Looper.looper().之后这个线程就是一个HandlerThread了.我们可以通过Handler在另外一个线程中(自己也可以)向这个线程发送消息,在这个线程中处理消息.

1.4. chromium源代码分析 - chromiumframe - 消息系列

Message framework 是对消息循环的封装和扩展,Chromium在消息循环中增加处理内部任务的工作.将内部工作处理寄生在Windows的消息循环中,会有一个问题,就是没有Windows自身消息,而有Chromium内部工作,此时内部动作就无法及时处理.Chromium这里定义了一个自定义消息kMsgHaveWork,用来在Chromium内部有工作的时候,驱动Windows的消息一直会运行. 从代码级别来说,Chromium内部工作队列被塞入工作时Post一条kMsgHaveWor

android 消息系统Handler、MessageQueue、Looper源代码学习

android消息系统 总体框架如图所看到的 在安卓的消息系统中,每一个线程有一个Looper,Looper中有一个MessageQueue,Handler向这个队列中投递Message,Looper循环拿出Message再交由Handler处理.总体是一个生产者消费者模式,这四部分也就构成了android的消息系统. 先来看一个最简单的样例 //这段代码在某个Activity的onCreate中 Handler handler = new Handler(Looper.getMainLoope

Android系统进程Zygote启动过程的源代码分析

原文地址:http://blog.csdn.net/luoshengyang/article/details/6747696 Android应用程序框架层创建的应用程序进程具有两个特点,一是进程的入口函数是ActivityThread.main,二是进程天然支持Binder进程间通信机制:这两个特点都是在进程的初始化过程中实现的,本文将详细分析Android应用程序进程创建过程中是如何实现这两个特点的. Android应用程序框架层创建的应用程序进程的入口函数是ActivityThread.ma

Android应用程序进程启动过程的源代码分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址: http://blog.csdn.net/luoshengyang/article/details/6747696 Android 应用程序框架层创建的应用程序进程具有两个特点,一是进程的入口函数是ActivityThread.main,二是进程天然支持Binder进程间通信 机制:这两个特点都是在进程的初始化过程中实现的,本文将详细分析Android应用程序进程创建过程中是如何实现这两个特点的. Android应用程序框架层创建的应用程序进程

android 消息系统Handler、MessageQueue、Looper源码学习

android消息系统 整体框架如图所示 在安卓的消息系统中,每个线程有一个Looper,Looper中有一个MessageQueue,Handler向这个队列中投递Message,Looper循环拿出Message再交由Handler处理.整体是一个生产者消费者模式,这四部分也就构成了android的消息系统. 先来看一个最简单的例子 //这段代码在某个Activity的onCreate中 Handler handler = new Handler(Looper.getMainLooper()

Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6642463 在前面几篇文章中,我们详细介绍了Android系统进程间通信机制Binder的原理,并且深入分析了系统提供的Binder运行库和驱动程序的 源代码.细心的读者会发现,这几篇文章分析的Binder接口都是基于C/C++语言来实现的,但是我们在编写应用程序都是基于Java语言的,那么,我 们如何使用Java语言来使用系统的Binder机