• 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。

     

            这个打包封装好的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消息是通过指针数组来实现的~

     

            那么就就能够非常负责任地告诉你,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;
    }


  • 相关阅读:
    Aurora 数据库支持多达五个跨区域只读副本
    Amazon RDS 的 Oracle 只读副本
    Amazon EC2 密钥对
    DynamoDB 读取请求单位和写入请求单位
    使用 EBS 优化的实例或 10 Gb 网络实例
    启动 LAMP 堆栈 Web 应用程序
    AWS 中的错误重试和指数退避 Error Retries and Exponential Backoff in AWS
    使用 Amazon S3 阻止公有访问
    路由表 Router Table
    使用MySQLAdmin工具查看QPS
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5413396.html
Copyright © 2020-2023  润新知