sloop公共程序之总体描述
1:功能需求
开发一个公共库文件sloop.c,实现三个常用功能以供其它模块调用。三个功能如下:
功能一:实现一般的信号监听,调用模块只需传入要监听的信号和相应的回调函数就可以在信号到时调用回调函数处理信号(优先级高)。
功能二:实现定时器,精度至usecs,调用模块只需传入过期的sec,usec和相应的回调函数就可以在时间到后执行回调函数(可以有一定时间误差)(优先级中)。
功能三:实现套接字的监听,调用模块只需传入要监听的套接字描述符和相应的回调处理函数就可以在描述符就绪是执行回调函数,分为监听读,写两种(优先级低)。
2:设计思路
2.1 技术选择
对于信号监听,使用移植性高的sigaction函数,为了统一管理,将使用pipe(fd)+sigaction + select的模式,选择pipe是为了减少信号处理函数的复杂度,在信号处理函数中只需将收到的信号write给fd[1],然后在select中检测fd[0]的可读状态,就可以得到收到的信号的值。这样就可以将信号的处理过程过渡为文件描述符的监听,与功能三重合,统一实现。这里的pipe其实也可以使用socketpair,但socketpair返回的两个套接字都是全双工的,似乎有些"浪费",而pipe正好的单双工,刚好符合要求也不"浪费"。可参考我的博文socketpair + signal + select 的套路描述了这样做的优势。
对于定时器,大体思路就是登记定时器时传入秒、微妙,过期时间就是当前时间加上传入的秒、微妙,主循环每次将登记的时间与当前时间比较,若当前时间>登记时间,就表示定时到,再执行回调函数,这样可能会造成一定的时间误差。
对于套接字的监听,分为可读和可写两种,选择select就足够满足需求了。
2.2 数据结构
通过上面的分析,我们关心的有三种情况,所以拟定三种结构体来描述它们,即信号结构体struct sloop_struct、时间结构体struct sloop_timeout、套接字结构体struct sloop_socket。那么如何来管理它们呢?最先想到的当然是用链表来进行管理,而且使用双链表,优势在于插入和遍历都比单链表要简易。因为考虑到监听的任务量不会很大,所以使用静态数据的方式替代在堆上分配内存。我们假定最多监听的socket和最多定时器都为128个,而最多监听的信号个数为16个,这样就可以先将静态分配的结构体数组挂在free_socket、free_timeout及free_signal三个双链表中,当调用者登记时,再从free_***双链表中取出挂在readers、writers、signals、timeout等使用的双链表中,这样管理可用的链表和正使用链表。
综上所述,三个结构体定义如下:
//记录一个待监听(读 or 写)套接字
struct sloop_socket
{
struct dlist_head list;//双链表挂载点(不用时挂在free_socket,使用时挂在readers or writers)
unsigned int flags;
int sock;//套接字描述符
void * param;
sloop_socket_handler handler;//状态就绪回调函数
}; //记录一个定时器
struct sloop_timeout
{
struct dlist_head list;//双链表挂载点(不用时挂在free_timeout,使用时挂在timeout)
unsigned int flags;
struct timeval time;//超时时间
void * param;
sloop_timeout_handler handler;//超时回调函数
}; //记录一个信号
struct sloop_signal
{
struct dlist_head list;//双链表挂载点(不用时挂在free_signal,使用时挂在signals)
unsigned int flags;
int sig;//信号值
void * param;
sloop_signal_handler handler;//信号回调函数
};
将free_***等组织到一个结构体中:
struct sloop_data
{
int terminate;//退出标志
int signal_pipe[];//信号监听会使用到的管道
void * sloop_data;
struct dlist_head free_sockets;
struct dlist_head free_timeout;
struct dlist_head free_signals;
struct dlist_head readers;
struct dlist_head writers;
struct dlist_head signals;
struct dlist_head timeout;
};
2.3 双链表操作
双链表的操作通通定义在一个dlist.h文件中,包括添加、删除等一般操作:
/* dlist.h */
ifndef _DLIST_H_
#define _DLIST_H_ typedef struct dlist_head dlist_t;
struct dlist_head
{
struct dlist_head * next;
struct dlist_head * prev;
}; #define DLIST_HEAD_INIT(e) {&(e),&(e)}
#define DLIST_HEAD(name) dlist_t name = {&(name),&(name)}
#define INIT_DLIST_HEAD(e) do { (e)->next = (e)->prev = (e); } while (0) static inline void __dlist_add(dlist_t * entry, dlist_t * prev, dlist_t * next)
{
next->prev = entry;
entry->next = next;
entry->prev = prev;
prev->next = entry;
}
static inline void __dlist_del(dlist_t * prev, dlist_t * next)
{
next->prev = prev;
prev->next = next;
} /***************************************************************************/ #define dlist_entry(e, t, m) ((t *)((char *)(e)-(unsigned long)(&((t *)0)->m))) static inline int dlist_empty(struct dlist_head * head) { return head->next == head; }
static inline void dlist_add(dlist_t * entry, dlist_t * head) { __dlist_add(entry, head, head->next); }
static inline void dlist_add_tail(dlist_t * entry, dlist_t * head) { __dlist_add(entry, head->prev, head); }
static inline void dlist_del(dlist_t * entry)
{
__dlist_del(entry->prev, entry->next);
entry->next = entry->prev = (void *);
}
static inline void dlist_del_init(dlist_t * entry)
{
__dlist_del(entry->prev, entry->next);
entry->next = entry->prev = entry;
}
static inline dlist_t * dlist_get_next(dlist_t * entry, dlist_t * head)
{
entry = entry ? entry->next : head->next;
return (entry == head) ? NULL : entry;
}
static inline dlist_t * dlist_get_prev(dlist_t * entry, dlist_t * head)
{
entry = entry ? entry->prev : head->prev;
return (entry == head) ? NULL : entry;
} #endif
有一个宏定义dlist_entry是为了通过链表指针来获得指向整个结构体的指针,因为我们操作的都是结构体的list成员,它是一个指向struct dlist_head结构体的指针,而list又是sloop_***结构体的第一个成员,所以需要将指向list的指针转换为指向list所在的结构体的指针,这样才能去访问此结构体的其它成员。
结语:总体说明了模块的功能和实现的大体方法,描述了结果比较重要的结构体如何组织的和为何这样组织。下面将记录详细的实现过程 sloop公共程序之初始过程
sloop公共程序之总体描述的更多相关文章
- sloop公共程序之初始过程及启动
1:sloop_init() 初始化主要是初始化静态sloop_*** 结构体和填充struct sloop_data 结构体中的成员. //初始化静态存储区给sloop_***结构体 static ...
- Verilog HDL的程序结构及其描述
这篇博文是写给要入门Verilog HDL及其初学者的,也算是我对Verilog HDL学习的一个总结,主要是Verilog HDL的程序结构及其描述,如果有错,欢迎评论指出. 一.Verilog ...
- Microsoft.VisualBasic.dll的妙用and 改善C#公共程序类库质量的10种方法
Microsoft.VisualBasic.dll的妙用(开发中肯定会用到哦) 前言 做过VB开发的都知道,有一些VB里面的好的函数在.NET里面都没有,而Microsoft.VisualBasic. ...
- UCOS2系统内核讲述_总体描述
Ⅰ.写在前面 学习本文之前可以参考我前面基于STM32硬件平台移植UCOS2的几篇文章,我将其汇总在一起: UCOS2_STM32F1移植详细过程(汇总文章) 要想学习,或使用系统配套的资源(如:信号 ...
- 改善C#公共程序类库质量的10种方法
最近重构一套代码,运用以下几种方法,供参考. 1 公共方法尽可能的使用缓存 public static List<string> GetRegisteredCompany() { Str ...
- 改善C#公共程序类库质量的10种方法和工具
最近重构一套代码,运用以下几种方法,供参考. 1 公共方法尽可能的使用缓存 public static List<string> GetRegisteredCompany() { Str ...
- 程序员如何描述清楚线上bug
案例 一个管理后台的bug,把操作记录中的操作员姓名,写成了该操作员的id.原因是修改了一个返回操作人姓名的函数,返回了操作人的id.但是还有其他地方也用这个函数,导致其他地方把姓名字段填写成了操作员 ...
- 改善C#公共程序类库质量的10种方法(转)
出处:http://www.cnblogs.com/JamesLi2015/p/3140897.html 最近重构一套代码,运用以下几种方法,供参考. 1 公共方法尽可能的使用缓存 public s ...
- sloop公共函数之添加信号,定时器及socket
1:添加信号 1.1 原型:sloop_handle sloop_register_signal(int sig, sloop_signal_handler handler, void * param ...
随机推荐
- Matlab中 .' 的作用。
Syntax B = A.' B = transpose(A) Description B = A.' returns the nonconjugate transpose of A, that ...
- python正则表达式re之compile函数解析
re正则表达式模块还包括一些有用的操作正则表达式的函数.下面主要介绍compile函数. 定义: compile(pattern[,flags] ) 根据包含正则表达式的字符串创建模式对象. 通过py ...
- Immutable 常用API简介
本文主要整理了Immutable.js常用API的使用. Immutable 是什么? 关于Immutable的定义,官方文档是这样说的: Immutable data encourages pure ...
- Python常用模块之hashlib
Python里面的hashlib模块提供了很多加密的算法,这里介绍一下hashlib的简单使用事例,用hashlib的md5算法加密数据 import hashlib hash = hashlib.m ...
- 软件工程第九周psp
1.PSP表格 2.进度条 3.饼状图 4.折线图
- Android开发第二阶段(4)
今天:对按扭位置重新调整了一下布局了一下,改变了layout中见面的字体格式等等是其更美观. 明天:对图片的修改和替换.
- 总结在Visual Studio Code创建Node.js+Express+handlebars项目
一.安装node.js环境. Node.js安装包及源码下载地址为:https://nodejs.org/en/download/ 32 位安装包下载地址 : https://nodejs.org/d ...
- NSURLErrorDomain错误代码
kCFURLErrorUnknown = -998, kCFURLErrorCancelled = -999, kCFURLErrorBadURL = -1000, kCFURLErrorTimedO ...
- CCF——数列分段201509-1
问题描述 给定一个整数数列,数列中连续相同的最长整数序列算成一段,问数列中共有多少段? 输入格式 输入的第一行包含一个整数n,表示数列中整数的个数. 第二行包含n个整数a1, a2, …, an,表示 ...
- 【Leetcode】113Path Sum II
Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given su ...