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. Java基础知识:Java实现Map集合二级联动2

    2. 定义获取省份的方法,创建一个Map集合,将上一步得到的映射集合赋值给它,使用Map集合的keySet()方法获取该集合中的所有键对象组成的Set 集合,即为省分集合,创建一个Object型一维数 ...

  2. IncDec序列:差分+贪心

    IncDec序列 题目描述: 给定一个长度为 n 的数列 a1,a2,…,an,每次可以选择一个区间[l,r],使下标在这个区间内的数都加一或者都减一. 求至少需要多少次操作才能使数列中的所有数都一样 ...

  3. ubuntu 设置全局代理

    ubuntu配置shadowsocks全局代理 在mac.window平台下都有shadowsocks客户端,因此这两个平台不叙述太多,现在介绍ubuntu下的配置方法. 1.安装python lin ...

  4. Alpha阶段敏捷冲刺 DAY5

    一.举行站立式例会 1.今天我们利用晚上的时间开展了站立会议,总结了一下之前工作的问题,并且制定了明天的计划. 2.站立式会议照片 二.团队报告 1.昨日已完成的工作 (1)改进了程序算法 (2)优化 ...

  5. Mware中CentOS设置静态IP

    Mware中CentOS设置静态IP   因为之前搭建的MongoDB分片没有采用副本集,最近现网压力较大,所以准备研究一下,于是在自己电脑的虚拟机中搭建环境,但是发现之前VMware设置的是DHCP ...

  6. Win2019 + Oracle18c SQLPLUS 命令行出现乱码的解决

    1. Win2019 中文版 安装了 Oracle数据库, dbca 建库时选择的 的字符集是 ZHS16GBK 然后发现使用sqlplus 时有乱码的现象如图示: 2. csdn 上面有一个博客有解 ...

  7. phpcms前端模板目录与文件结构分析图【templates】

    phpcms前端模板目录与文件结构分析图[templates] 原文地址:http://www.iphpcms.net/phpcms-ziliao/2015_14.html

  8. Mybatis 映射关系

    相比 Hibernate,Mybatis 的映射关系就显得简单了很多. 未完待续....

  9. Winform程序在XP系统上双击运行无反应解决方法

    右键程序,打开属性栏,在兼容性选项里以兼容模式运行该程序即可解决.

  10. HashMap的扩容机制以及默认大小为何是2次幂

    HashMap的Put方法 回顾HashMap的put(Key k, Value v)过程: (1)对 Key求Hash值,对n-1取模计算出Hash表数组下标 (2)如果没有碰撞,直接放入桶中,即H ...