cacti rrdtool snmp 版本错误问题

2010年3月12日 Michael Field 没有评论

最近新安装了cacti 0.8.7e

发现了个很莫名的问题:无法画图并且主机检测snmp error

在Console -> Utilities -> Technical Support中发现:

snmp  Version:显示为空

RRDTool Version:ERROR: Installed RRDTool version does not match configured version.
Please visit the Configuration Settings and select the correct RRDTool Utility Version.

排查所有可能引起的问题。php 模块,rrdtool也从1.4换到1.3再到1.2.30搞郁闷啦。

最后到官网发现原来是0.8.7e的bug 打了官方补丁后ok啦。虽然Technical Support中还是显示错误,但可以画图和snmp检测主机啦。
以下脚本,大家如果发现有同样问题,可以复制保存为sh文件在cacti web目录中执行即可。

wget http://www.cacti.net/downloads/patches/0.8.7e/cli_add_graph.patch
wget http://www.cacti.net/downloads/patches/0.8.7e/snmp_invalid_response.patch
wget http://www.cacti.net/downloads/patches/0.8.7e/template_duplication.patch
wget http://www.cacti.net/downloads/patches/0.8.7e/fix_icmp_on_windows_iis_servers.patch
wget http://www.cacti.net/downloads/patches/0.8.7e/cross_site_fix.patch
patch -p1 -N < cli_add_graph.patch
patch -p1 -N < snmp_invalid_response.patch
patch -p1 -N < template_duplication.patch
patch -p1 -N < fix_icmp_on_windows_iis_servers.patch
patch -p1 -N < cross_site_fix.patch
分类: Cacti, RRDTool, 系统监控 标签:

分布式监控zabbix 99%汉化完成

2010年3月10日 Michael Field 没有评论

最近改造公司监控环境,解决南北互通的带来数据延时而不能及时报警,所以选择分布式监控系统zabbix,使用下来感觉效能不错,功能齐全。

特别是开放团队以sa为基础,操作上带来极大的快捷。为了提高监控操作和方便推广,近日我自己改了汉化配置文件,先发出给大家下载试用;

有些不够精确的地方,请大家修正。

点击下载:cn_zh.inc.php.tar

解压后,复制到wwwroot/zabbix/include/locales/下覆盖原来的文件;

然后点击zabbix 首页右上角porfile,language 中选择Chinese(CN)即可。

等我文档整理完毕,在添加zabbix各项强大功能的安装和配置,以及分布式优化等文档。

Office 2010 果然不错

2010年3月7日 代码罐头 没有评论

在WIN7下面启动速度飞快.比2007要快
不论是EXCEL,WORD还是PPT
在T4200,2G RAM的DELL 1320笔记本,系统是WIN7下面的表现
首次打开速度都不到1秒
第二次之后的重复开启的时候甚至连splash screen都没显示全就进入了
界面以及速度都提升很多.

分类: 生活随笔 标签:

关于重构和重写

2010年3月2日 代码罐头 没有评论

今天读到一篇很有意思的文章
你永远不应该做的事

对于重写,这个词可能是我听到过最多开发以及经理在遇见项目瓶颈时提到的.
当作为旁观者经历过几个项目的起落之后
我越来越深刻的感觉到程序员以及经理提到重写是基于以下几个理由
1.对完全理解原有代码的恐惧
2.作为拖延项目完成时间的借口
3.希望表现自己的能力,觉得自己重新写比修复别人的工作更有挑战性与创造性
4.不了解重构
而上级能够采纳重写意见一般是基于
1.原有项目时间拖延太长,修改难度越来越高,修复时间似乎是非线性增长的.
2.所有程序员都建议重新再来,没人愿意进行修复原有代码的工作

问题在于
当你不能够理解以及改善破败代码的时候
你凭什么能够认为能够写出一个功能一致并且更清晰的软件呢?
首先你认为原来的代码已经是破败不堪,散发着腐败的臭味
你不能够靠读他去理解他,因为写的太烂了
但是你如果不读他.你又如何能理解他干了什么呢?
凭借着从头开始进行复制策划文档
你又可能忽略多少隐藏在破败代码沟壑中的细节点呢?
这些细节点必然会复现,直到你重新遇见问题.找到它,修补它
当你没有能力修整一个破败代码的话
你修补这些细节之后的代码也会是破败的.
当你无法理解别人破败代码
最终你也无法理解你自己写出来的破败代码

重构不是什么高深的技艺.但它需要磨练
但是我遇到很多人.都不会去修炼这项技能
迫于项目压力或者惰性
以及古老工匠守则的规劝:”当一个事物运行正常的时候,不要碰它”
和测试一样,至今程序员都没有把测试行为和代码结合在一起来做.
手工作坊式的做法至今仍在.
当然作坊式的手法有其优点
不过既然你已经是靠手艺吃饭
那么重构的手艺以及测试的手艺才是我们需要加强的
而不是继续锻炼靠运气编程的手艺

分类: 生活随笔 标签:

Visual Studio 2010 体验

2010年3月1日 代码罐头 1 条评论

1.安装过程中要重启一下
2.字体显示模糊-WPF的老毛病了.解决方法是用雅黑…无语.consolas字体下中文显示那个模糊哟.
3.只支持ClearType字体,以前的项目如果设置了点阵字体,打开会出错.居然也不提示下
4.在WIN7下速度很快(也许是我用WIN7的那台速度比较快),在XP下速度不如VS2008
5.界面似乎现代点了,带点WIN7味道,但是感觉IDE还是2008那种风格比较清爽.速度快很重要.
6.在C盘下面留了巨大的尾巴.我只定制了Visual C++并且去掉了x64版本等等垃圾,还是给我在C盘基本塞了4G的数据…而且这部分数据还不能切换到安装目录.
7.重构的方法没什么变化.

基本给我的总体感觉…不如VS2008爽
当然.支持C++0x应该是2010的优势
还有并行处理这东西.
据说debug也变得很NB了.

不过最核心的.我想WPF显示问题如果不解决
这些都是浮云了…
IDE最基本就是coding,你让我看字都看不清楚.那不是瞎扯淡么…
除非我不用看屏幕就能coding….

分类: 生活随笔 标签:

中国的新闻-亚克西!

2010年2月25日 代码罐头 没有评论

昨天说过张江高科地铁站点的问题
今天就看到这样一个新闻
标题是
2号线新张江站约为原来两倍大 老站改成轨交实训基地
实在是亚克西!
居然大两倍…
然后25日的新闻就变成了
轨交2号线张江高科站设计”先天不足”
那请问前面一天去的两个记者狗日的眼睛是瞎的么?!
这走道细的和一线天一样.
出口比原来少一倍的情况
居然说约为原来两倍大
大JB大!你Y的收到轨道交通公司的伟哥了吧
还是你老眼睛度数大概有1000度,是用放大镜去参观的张江站的?
就知道制造”伪和谐”
有兴趣的朋友可以打电话去东方网投诉这两个记者
60850222

分类: 生活随笔 标签:

新张江站通道小的和尿道一样

2010年2月24日 代码罐头 1 条评论

老站原来每次到站下客都要堵塞.但是也就5分钟
新站直接从下客堵变成了
下客堵塞+出闸机堵塞
上下楼梯只有2个人的宽度
从5个人的宽度变成2个人的宽度.
直接从羊肠小道变成前列腺尿道
就知道加长线路.不知道加大站头设计
就知道赚钱,把线路拉长,根本不管客户的感受
MLGB.垄断企业就是这B样!!!
还迎世博.迎JB世博
这么小连中国人都装不下还要装外国人!
为了庆祝这个鸟站
特作一首亚克西

二号线有新站上,上班族坐车人繁忙
新站的通道像尿道诶,等着每个人心发慌
什么亚克西呀
什么亚克西也
张江新站亚克西

分类: 生活随笔 标签:

Git vs Mercurial

2010年2月20日 代码罐头 没有评论

网上文章都是抄来抄去
所以这两者的对比文章中误导成分也被扩大很多倍

关于无法clone子目录
有一篇常被引用的比较文章提到Mercurial的缺点是
“分支的时候不能对子目录进行clone.一次clone就是一个工程。”
而上面的Git没有提到相关问题
让人错觉Git没有这个问题
其实Git也是无法只针对一个子目录进行clone的
两者对同样这个问题的解决方案是
Git提供sub module的方法.在一个项目下加入子模块的概念
Mercurial提供sub repo,原理基本一致
Git使用单独的submodule指令来实现
Mercurial使用.hgsub文件来实现

关于学习曲线
Git指令和概念太多.学习曲线比较陡.
Murcurial的概念比较简单,指令很少,非常容易理解.

关于Windows下两者比较
我个人看法是如果你在Windows下使用cygwin很习惯,那git没问题
否则tortoiseGit与tortoiseHg来对比
绝对是tortoiseHg比较容易上手
而且安装包小很多.
Git光是msysgit装好就有一百多M
tortoiseHg的diff非常直观.annotate files比blame要好用.非常直观的可以看到每行属于哪个版本
而tortoiseGit的菜单与tortoiseSVN的基本一致,如果你很熟悉SVN,那么这个就很简单了

关于我的看法
国内真正掌握VCS的用法的团队可以说很少.
很多时候大家都是在用commit和update两个指令而已
而branch和merge,我估计一些开发人员到目前为止都没碰过
因为branch式的开发相当于让每个开发人员又多了一个merge的工作.
所以能不碰就不碰.很少有人用这个方式去开发.除非特别大的团队项目
在这种情况下
Mercurial就比Git要适合国情的多
因为大多数情况下.许多开发人员是想要一个无限制回滚的编辑器以及一个集中代码托管服务器而已
而这两点使用Mercurial就可以很好的完成
减轻很多学习成本

分类: 生活随笔 标签:

VIM常用指令

2010年2月5日 代码罐头 7 条评论

用了好几年VIM
也从来没怎么认真的用过
VIM是一个很多指令的编辑器,多到你可以只用键盘就完成所有操作
所以…如果你不是经常用.估计你强记也会忘记的
而且VIM里面有很多重复作用的指令方式
例如你到文件末尾,可以用G,也可以用:$
下面我整理的并非是所有的VIM指令,那可以写一本书
最常用的被我记录下来,而最容易记忆的也被我保留下来了
以下格式为
指令 – 作用
所以输入的时候别把<空格>-也带进去

0 – 到行首
$ – 到行尾
^ – 到行首字母
( – 到上面一句或者上面一个代码段
) – 到下面一句或者下面一个代码段
`. – 到最后一次修改的位置,注意这个`不是单引号,是1左边的那个按键
/<文字> – 搜索指定文字,找到之后使用n来跳到下一个相同单词位置
:<数值> – 转跳到指定行数
:$ – 转跳到文件末尾,这个和G的作用相同,但是我觉得更加好记,因为和转跳行数一样,而且$一般被用来标识末尾

i – 插入模式,I也可以,还有a,A,但是个人感觉提高效率不明显
o – 在当前行下面建立新行,对应的有O,在当前行上面,但是O很少用,除非你已经到顶行而且要在上面插入一行.

v – 进入区块选择
y – 复制已经选择的区块
yy – 复制当前行
d – 剪切已经选择的区块
dd – 剪切当前行
p – 粘贴已经选择的区块

. – 重复上次指令
<数值><指令> – 重复执行指定的指令,例如10dd,剪切10行

% – 匹配花括号,方括号,括号等,用于例如跳转到对应的{}位置
gd – 到达光标所在处函数或者变量的定义处
> – 缩进代码,在v下可用
>> – 缩进当前行代码
< – 反缩进代码,在v下可用
<< – 反缩进当前行

分类: Linux 标签:

从头编写高性能服务程序12-区分读写事件

2010年2月2日 代码罐头 没有评论

前一个版本很重要的BUG
就是sendfile在发送大文件的时候会发送不完整
这个bug指出了另一需求
就是需要用到EPOLLOUT事件

前面版本我们事件处理都是在EPOLLIN中进行
当有accept_fd数据进来之后
我们判断指令的内容
再直接进行数据的处理

我们更换一种方式
当accept_fd获取到数据之后
解析数据.
当需要输出的时候,将accept_fd的事件变为EPOLLOUT

这样一种fd会有两种状态
接受指令状态以及输出数据状态
慢慢的.我们会发现这个程序越来越像Nginx或者Lighttpd了
因为一个连接会有不同的状态
事件+状态机就是Nginx以及Lighttpd高效的原因
将一个链接分成不同的生命周期然后处理

经过进化
我们的event_handle结构拥有了读写两种hook钩子

typedef struct event_handle{
    ...
    int ( * read_handle  )( struct event_handle * ev );
    int ( * write_handle )( struct event_handle * ev );
    ...
}

而我们在针对的处理过程中
初始化时会针对不同的事件挂上不同的钩子函数

int init_evhandle(...){
    ...
    ev->read_handle = r_handle;
    ev->write_handle = w_handle;
    ...
}

接着在事件发生时调用不同的钩子函数

else if( events[i].events&EPOLLIN ){
    EVENT_HANDLE current_handle = ( ( EH )( events[i].data.ptr ) )->read_handle;
    ...
}
else if( events[i].events&EPOLLOUT ){
    EVENT_HANDLE current_handle = ( ( EH )( events[i].data.ptr ) )->write_handle;
    ...
}

当分析完指令的时候
将fd变为EPOLLOUT

int parse_request(
    ...
    ev_temp.data.ptr = ev;
    ev_temp.events = EPOLLOUT|EPOLLET;
    epoll_ctl( ev->epoll_fd, EPOLL_CTL_MOD, ev->socket_fd, &ev_temp );
    ...
}

加入这些处理之后
代码越来越长了
我们还需要加很多东西
比如进程管理,等等
这之后会发现一个mini的nginx骨架或者lighttpd骨架出现了

下载: code.txt
  1. #include <sys/socket.h>
  2. #include <sys/wait.h>
  3. #include <netinet/in.h>
  4. #include <netinet/tcp.h>
  5. #include <sys/epoll.h>
  6. #include <sys/sendfile.h> 
  7. #include <sys/stat.h>
  8. #include <unistd.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <strings.h>
  13. #include <fcntl.h>
  14. #include <errno.h>
  15.  
  16. #define HANDLE_INFO   1
  17. #define HANDLE_SEND   2
  18. #define HANDLE_DEL    3
  19. #define HANDLE_CLOSE  4
  20.  
  21. #define MAX_REQLEN          1024
  22. #define MAX_PROCESS_CONN    3
  23. #define FIN_CHAR            0x00
  24. #define SUCCESS  0
  25. #define ERROR   -1
  26.  
  27. typedef struct event_handle{
  28.     int socket_fd;
  29.     int file_fd;
  30.     int file_pos;
  31.     int epoll_fd;
  32.     char request[MAX_REQLEN];
  33.     int request_len;
  34.     int ( * read_handle )( struct event_handle * ev );
  35.     int ( * write_handle )( struct event_handle * ev );
  36.     int handle_method;
  37. } EV,* EH;
  38. typedef int ( * EVENT_HANDLE )( struct event_handle * ev );
  39.  
  40. int create_listen_fd( int port ){
  41.     int listen_fd;
  42.     struct sockaddr_in my_addr;
  43.     if( ( listen_fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ){
  44.         perror( "create socket error" );
  45.         exit( 1 );
  46.     }
  47.     int flag;
  48.     int olen = sizeof(int);
  49.     if( setsockopt( listen_fd, SOL_SOCKET, SO_REUSEADDR
  50.                         , (const void *)&flag, olen ) == -1 ){
  51.         perror( "setsockopt error" );
  52.     }
  53.     flag = 5;
  54.     if( setsockopt( listen_fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &flag, olen ) == -1 ){
  55.         perror( "setsockopt error" );
  56.     }
  57.     flag = 1;
  58.     if( setsockopt( listen_fd, IPPROTO_TCP, TCP_CORK, &flag, olen ) == -1 ){
  59.         perror( "setsockopt error" );
  60.     }
  61.     int flags = fcntl( listen_fd, F_GETFL, 0 );
  62.     fcntl( listen_fd, F_SETFL, flags|O_NONBLOCK );
  63.     my_addr.sin_family = AF_INET;
  64.     my_addr.sin_port = htons( port );
  65.     my_addr.sin_addr.s_addr = INADDR_ANY;
  66.     bzero( &( my_addr.sin_zero ), 8 );
  67.     if( bind( listen_fd, ( struct sockaddr * )&my_addr,
  68.     sizeof( struct sockaddr_in ) ) == -1 ) {
  69.         perror( "bind error" );
  70.         exit( 1 );
  71.     }
  72.     if( listen( listen_fd, 1 ) == -1 ){
  73.         perror( "listen error" );
  74.         exit( 1 );
  75.     }
  76.     return listen_fd;
  77. }
  78.  
  79. int create_accept_fd( int listen_fd ){
  80.     int addr_len = sizeof( struct sockaddr_in );
  81.     struct sockaddr_in remote_addr;
  82.     int accept_fd = accept( listen_fd,
  83.         ( struct sockaddr * )&remote_addr, &addr_len );
  84.     int flags = fcntl( accept_fd, F_GETFL, 0 );
  85.     fcntl( accept_fd, F_SETFL, flags|O_NONBLOCK );
  86.     return accept_fd;
  87. }
  88.  
  89. int fork_process( int process_num ){
  90.     int i;
  91.     int pid=-1;
  92.     for( i = 0; i < process_num; i++ ){
  93.         if( pid != 0 ){
  94.             pid = fork();
  95.         }
  96.     }
  97.     return pid;
  98. }
  99.  
  100. int init_evhandle(EH ev,int socket_fd,int epoll_fd,EVENT_HANDLE r_handle,EVENT_HANDLE w_handle){
  101.     ev->epoll_fd = epoll_fd;
  102.     ev->socket_fd = socket_fd;
  103.     ev->read_handle = r_handle;
  104.     ev->write_handle = w_handle;
  105.     ev->file_pos = 0;
  106.     ev->request_len = 0;
  107.     ev->handle_method = 0;
  108.     memset( ev->request, 0, 1024 );
  109. }
  110. //accept->accept_queue->request->request_queue->output->output_queue
  111. //multi process sendfile
  112. int parse_request(EH ev){
  113.     ev->request_len--;
  114.     *( ev->request + ev->request_len - 1 ) = 0x00;
  115.     int i;
  116.     for( i=0; i<ev->request_len; i++ ){
  117.         if( ev->request[i] == ':' ){
  118.             ev->request_len = ev->request_len-i-1;
  119.             char temp[MAX_REQLEN];
  120.             memcpy( temp, ev->request, i );
  121.             ev->handle_method = atoi( temp );
  122.             memcpy( temp, ev->request+i+1, ev->request_len );
  123.             memcpy( ev->request, temp, ev->request_len );
  124.             break;
  125.         }
  126.     }
  127.     //handle_request( ev );
  128.     //register to epoll EPOLLOUT
  129.    
  130.     struct epoll_event ev_temp;
  131.     ev_temp.data.ptr = ev;
  132.     ev_temp.events = EPOLLOUT|EPOLLET;
  133.     epoll_ctl( ev->epoll_fd, EPOLL_CTL_MOD, ev->socket_fd, &ev_temp );
  134.     return SUCCESS;
  135. }
  136.  
  137. int handle_request(EH ev){
  138.     struct stat file_info;
  139.     switch( ev->handle_method ){
  140.         case HANDLE_INFO:
  141.             ev->file_fd = open( ev->request, O_RDONLY );
  142.             if( ev->file_fd == -1 ){
  143.                 send( ev->socket_fd, "open file failed\n", strlen("open file failed\n"), 0 );
  144.                 return -1;
  145.             }
  146.             fstat(ev->file_fd, &file_info);
  147.             char info[MAX_REQLEN];
  148.             sprintf(info,"file len:%d\n",file_info.st_size);
  149.             send( ev->socket_fd, info, strlen( info ), 0 );
  150.             break;
  151.         case HANDLE_SEND:
  152.             ev->file_fd = open( ev->request, O_RDONLY );
  153.             if( ev->file_fd == -1 ){
  154.                 send( ev->socket_fd, "open file failed\n", strlen("open file failed\n"), 0 );
  155.                 return -1;
  156.             }
  157.             fstat(ev->file_fd, &file_info);
  158.             sendfile( ev->socket_fd, ev->file_fd, 0, file_info.st_size );
  159.             break;
  160.         case HANDLE_DEL:
  161.             break;
  162.         case HANDLE_CLOSE:
  163.             break;
  164.     }
  165.     finish_request( ev );
  166.     return SUCCESS;
  167. }
  168.  
  169. int finish_request(EH ev){
  170.     close(ev->socket_fd);
  171.     close(ev->file_fd);
  172.     ev->handle_method = -1;
  173.     clean_request( ev );
  174.     return SUCCESS;
  175. }
  176.  
  177. int clean_request(EH ev){
  178.     memset( ev->request, 0, MAX_REQLEN );
  179.     ev->request_len = 0;
  180. }
  181.  
  182. int read_hook_v2( EH ev ){
  183.     char in_buf[MAX_REQLEN];
  184.     memset( in_buf, 0, MAX_REQLEN );
  185.     int recv_num = recv( ev->socket_fd, &in_buf, MAX_REQLEN, 0 );
  186.     if( recv_num ==0 ){
  187.         close( ev->socket_fd );
  188.         return ERROR;
  189.     }
  190.     else{
  191.         //check ifoverflow
  192.         if( ev->request_len > MAX_REQLEN-recv_num ){
  193.             close( ev->socket_fd );
  194.             clean_request( ev );
  195.         }
  196.         memcpy( ev->request + ev->request_len, in_buf, recv_num );
  197.         ev->request_len += recv_num;
  198.         if( recv_num == 2 && ( !memcmp( &in_buf[recv_num-2], "\r\n", 2 ) ) ){
  199.             parse_request(ev);
  200.         }
  201.     }
  202.     return recv_num;
  203. }
  204.  
  205. int write_hook_v1( EH ev ){
  206.     struct stat file_info;
  207.     ev->file_fd = open( ev->request, O_RDONLY );
  208.     if( ev->file_fd == ERROR ){
  209.         send( ev->socket_fd, "open file failed\n", strlen("open file failed\n"), 0 );
  210.         return ERROR;
  211.     }
  212.     fstat(ev->file_fd, &file_info);
  213.     int write_num;
  214.     while(1){
  215.         write_num = sendfile( ev->socket_fd, ev->file_fd, (off_t *)&ev->file_pos, 10240 );
  216.         ev->file_pos += write_num;
  217.         if( write_num == ERROR ){
  218.             if( errno == EAGAIN ){
  219.                 break;
  220.             }
  221.         }
  222.         else if( write_num == 0 ){
  223.             printf( "writed:%d\n", ev->file_pos );
  224.             //finish_request( ev );
  225.             break;
  226.         }
  227.     }
  228.     return SUCCESS;
  229. }
  230.  
  231. int main(){
  232.     int listen_fd = create_listen_fd( 3389 );
  233.     int pid = fork_process( 3 );
  234.     if( pid == 0 ){
  235.         int accept_handles = 0;
  236.         struct epoll_event ev, events[20];
  237.         int epfd = epoll_create( 256 );
  238.         int ev_s = 0;
  239.        
  240.         ev.data.fd = listen_fd;
  241.         ev.events = EPOLLIN|EPOLLET;
  242.         epoll_ctl( epfd, EPOLL_CTL_ADD, listen_fd, &ev );
  243.         struct event_handle ev_handles[256];
  244.         for( ;; ){
  245.             ev_s = epoll_wait( epfd, events, 20, 500 );
  246.             int i = 0;
  247.             for( i = 0; i<ev_s; i++ ){
  248.                 if( events[i].data.fd == listen_fd ){
  249.                     if( accept_handles < MAX_PROCESS_CONN ){
  250.                         accept_handles++;
  251.                         int accept_fd = create_accept_fd( listen_fd );
  252.                         init_evhandle(&ev_handles[accept_handles],accept_fd,epfd,read_hook_v2,write_hook_v1);
  253.                         ev.data.ptr = &ev_handles[accept_handles];
  254.                         ev.events = EPOLLIN|EPOLLET;
  255.                         epoll_ctl( epfd, EPOLL_CTL_ADD, accept_fd, &ev );
  256.                     }
  257.                 }
  258.                 else if( events[i].events&EPOLLIN ){
  259.                     EVENT_HANDLE current_handle = ( ( EH )( events[i].data.ptr ) )->read_handle;
  260.                     EH current_event = ( EH )( events[i].data.ptr );
  261.                     ( *current_handle )( current_event );
  262.                 }
  263.                 else if( events[i].events&EPOLLOUT ){
  264.                     EVENT_HANDLE current_handle = ( ( EH )( events[i].data.ptr ) )->write_handle;
  265.                     EH current_event = ( EH )( events[i].data.ptr );
  266.                     if( ( *current_handle )( current_event )  == 0 ){ 
  267.                         accept_handles--;
  268.                     }
  269.                 }
  270.             }
  271.         }
  272.     }
  273.     else{
  274.         //manager the process
  275.         int child_process_status;
  276.         wait( &child_process_status );
  277.     }
  278.    
  279.     return SUCCESS;
  280. }
分类: C/C++ 标签: