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公共程序之总体描述的更多相关文章

  1. sloop公共程序之初始过程及启动

    1:sloop_init() 初始化主要是初始化静态sloop_*** 结构体和填充struct sloop_data 结构体中的成员. //初始化静态存储区给sloop_***结构体 static ...

  2. Verilog HDL的程序结构及其描述

    这篇博文是写给要入门Verilog HDL及其初学者的,也算是我对Verilog  HDL学习的一个总结,主要是Verilog HDL的程序结构及其描述,如果有错,欢迎评论指出. 一.Verilog ...

  3. Microsoft.VisualBasic.dll的妙用and 改善C#公共程序类库质量的10种方法

    Microsoft.VisualBasic.dll的妙用(开发中肯定会用到哦) 前言 做过VB开发的都知道,有一些VB里面的好的函数在.NET里面都没有,而Microsoft.VisualBasic. ...

  4. UCOS2系统内核讲述_总体描述

    Ⅰ.写在前面 学习本文之前可以参考我前面基于STM32硬件平台移植UCOS2的几篇文章,我将其汇总在一起: UCOS2_STM32F1移植详细过程(汇总文章) 要想学习,或使用系统配套的资源(如:信号 ...

  5. 改善C#公共程序类库质量的10种方法

    最近重构一套代码,运用以下几种方法,供参考. 1  公共方法尽可能的使用缓存 public static List<string> GetRegisteredCompany() { Str ...

  6. 改善C#公共程序类库质量的10种方法和工具

    最近重构一套代码,运用以下几种方法,供参考. 1  公共方法尽可能的使用缓存 public static List<string> GetRegisteredCompany() { Str ...

  7. 程序员如何描述清楚线上bug

    案例 一个管理后台的bug,把操作记录中的操作员姓名,写成了该操作员的id.原因是修改了一个返回操作人姓名的函数,返回了操作人的id.但是还有其他地方也用这个函数,导致其他地方把姓名字段填写成了操作员 ...

  8. 改善C#公共程序类库质量的10种方法(转)

    出处:http://www.cnblogs.com/JamesLi2015/p/3140897.html 最近重构一套代码,运用以下几种方法,供参考. 1  公共方法尽可能的使用缓存 public s ...

  9. sloop公共函数之添加信号,定时器及socket

    1:添加信号 1.1 原型:sloop_handle sloop_register_signal(int sig, sloop_signal_handler handler, void * param ...

随机推荐

  1. POJ 3579 Median 二分加判断

    Median Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12453   Accepted: 4357 Descripti ...

  2. [C++基础] 成员变量的初始化顺序

    转载链接:https://blog.csdn.net/qq_37059483/article/details/78608375 1.成员变量在使用初始化列表初始化时,只与定义成员变量的顺序有关,与构造 ...

  3. 微信小程序-----自定义验证码实现

    这一段时间做小程序项目,使用的是mpvue的框架,需要自己实现验证码输入,模拟input的光标,上一个框输入后后一个框自动获取焦点,删除时从后往前依次删除.下图是整体效果: <template& ...

  4. Scrum立会报告+燃尽图(十月十日总第一次):选题

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2190 Scrum立会master:付佳 一.小组介绍 组长:付佳 组员: ...

  5. Python:三元运算

    result=值1 if 条件 else 值2 如果条件为真,result=值1 如果条件为假,result=值2 例子: a,b,c=1,3,5 d=a if a>b else c print ...

  6. 2018软工实践—Alpha冲刺(2)

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 协助前端界面的开发 搭建测试用服务器的环境 完成 ...

  7. 寒假MOOC学习计划

    我选择的是西北工业大学的课程,理由如下: 首先,选择这门课的网友还蛮多的,特意看了一下评价,也不错: 其次,这个课程的排版与我从图书馆借来的一本书内容排版比较符合,可以结合起来一起看,说不定会有更多收 ...

  8. 福大软工1816:Beta(3/7)

    Beta 冲刺 (3/7) 队名:第三视角 组长博客链接 本次作业链接 团队部分 团队燃尽图 工作情况汇报 张扬(组长) 过去两天完成了哪些任务 文字/口头描述 参与开发关键词提醒部分 展示GitHu ...

  9. [codecademy]fonts in css

    Great job! You learned how to style an important aspect of the user experience: fonts! Let's review ...

  10. VS2013安装及单元测试

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZ0AAAIlCAIAAACBzLJwAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAgAE ...