为什么作了信号处理之后select函数就不能正常工作了?

ashamwolf 2005-09-12 05:02:13
程序的结构是这样的:
在一个循环里用select函数从socket接收字符,然后进行处理,但是如果在处理的过程中处理了ALARM和TERM信号之后,就再也读不到数据了,有时候select会返回-1,有时候什么动静也没有。
这是为什么呢?
...全文
598 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
cky41 2005-12-12
  • 打赏
  • 举报
回复
系统调用会被信号打断的


还讨论这么久
cashtang 2005-09-21
  • 打赏
  • 举报
回复
我原来也以为所有的系统调用被中断都可以重新调用.原来select是不行的:-( .
cashtang 2005-09-21
  • 打赏
  • 举报
回复
我又看了看select的程序,原来select处理中是不能有信号的.
select.c的代码:
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
for (i = 0 ; i < n; i++) {
unsigned long bit = BIT(i);
unsigned long mask;
struct file *file;

off = i / __NFDBITS;
if (!(bit & BITS(fds, off)))
continue;
file = fget(i);
mask = POLLNVAL;
if (file) {
mask = DEFAULT_POLLMASK;
if (file->f_op && file->f_op->poll)
mask = file->f_op->poll(file, wait);
fput(file);
}
if ((mask & POLLIN_SET) && ISSET(bit, __IN(fds,off))) {
SET(bit, __RES_IN(fds,off));
retval++;
wait = NULL;
}
if ((mask & POLLOUT_SET) && ISSET(bit, __OUT(fds,off))) {
SET(bit, __RES_OUT(fds,off));
retval++;
wait = NULL;
}
if ((mask & POLLEX_SET) && ISSET(bit, __EX(fds,off))) {
SET(bit, __RES_EX(fds,off));
retval++;
wait = NULL;
}
}
wait = NULL;
if (retval || !__timeout || signal_pending(current))
break;
if(table.error) {
retval = table.error;
break;
}
__timeout = schedule_timeout(__timeout);
}
这一行:if (retval || !__timeout || signal_pending(current))
break;
说明select在处理的时候如果有信号,则直接跳出循环.如果是因为系统中断而跳出循环的retval的值应该为4,即EINVAL,这个就是errno的值.你可以判断如果是这个原因,在重新调用.
ashamwolf 2005-09-20
  • 打赏
  • 举报
回复
我用下面函数来设置信号处理函数还是不行,函数里有不对的地方吗?信号处理函数里什么都不做select也会返回-1,在select返回-1的时候用strerror得到的错误描述是"Interrupted system call"。

typedef void Sigfunc(int);

Sigfunc *msignal(int signo, Sigfunc *func)
{
struct sigaction act, oact;

act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
#ifdef SA_RESTART
act.sa_flags |= SA_RESTART;
#endif
if (sigaction(signo, &act, &oact) < 0)
return(SIG_ERR);
return(oact.sa_handler);
}


tengulre 2005-09-20
  • 打赏
  • 举报
回复
up
cashtang 2005-09-16
  • 打赏
  • 举报
回复
不是!是在你设置alarm处理的信号函数时用 sigaction 方法的struct sigaction有一个flag参数可以设置信号函数的一些标志。系统内核在调用 do_signal函数处理完信号后,检查是否在执行信号的时间中断了一个系统调用(select就是一种系统调用),如果是,再根据do_signal的返回值(应该是根据设置信号时的flag来决定)来决定是否要重新调用被中断的系统调用。
wxywh 2005-09-16
  • 打赏
  • 举报
回复
表头文件 #include<string.h>

定义函数 char * strerror(int errnum);

用它将错误信息输出来看看。
wxywh 2005-09-16
  • 打赏
  • 举报
回复
楼主,能否详细点。
ashamwolf 2005-09-16
  • 打赏
  • 举报
回复
cashtang(孤独),你的意思是执行我的处理函数之后再把信号的处理函数设置为默认的?
cashtang 2005-09-15
  • 打赏
  • 举报
回复
因为信号处理是调用int0x80陷入内核的,当信号处理完成,系统会根据情况来恢复中断的系统调用,一般情况是直接返回-1,你可以用sigaction来设置信号的参数使信号处理完成后重新调用系统调用,你可以看一下man手册,或者看一下系统signal.c的源码。
wind123 2005-09-15
  • 打赏
  • 举报
回复
关注!!!
楼主,关键源码不全
ashamwolf 2005-09-14
  • 打赏
  • 举报
回复
写log的函数是自己的,就是打开一个文件然后往里面写东西,再关闭。
gaoxianfeng 2005-09-14
  • 打赏
  • 举报
回复
不知道你的log是怎么实现的?
用的系统log?
把它去掉试试看 因为中断服务程序里再有中断 程序会有些 混乱的行为
ashamwolf 2005-09-13
  • 打赏
  • 举报
回复
alarm的处理函数只有一条写log的语句。
调用select的代码:
struct timeval timeout;
int n,res,val,len;
char buf;
fd_set input;

timeout.tv_sec = sec;
timeout.tv_usec = 0;

//ioctl(fd, FIONBIO, 1);
FD_ZERO(&input);
FD_SET(fd, &input);

n = select(fd+1, &input, NULL, NULL, &timeout);

switch (n){
case -1:
writelog("!Select Error");
return(-1);
......
这些和SIGALRM的处理都是在守护进程之内执行的。打开socket之后就进入主循环读取数据,收到一条完整的消息(STX开头,ETX结尾)之后就进行处理,处理的过程主要是字符串的处理和数据库的操作然后向socket写回复消息,其中没有调用到select,处理完之后进入下一次循环调用select读数据。
主循环的代码:
for(;;){
ret=waitCtrlChar(fd);
switch(ret){
case -1:
return(-1);
case 0: //link Break or haven't data to transmit
......
break;
case STX: //start record
......
break;
}
}
其中waitCtrlChar调用了select。

我后来又测试了一下,发现在以下地方调用alarm(1)会使select返回-1:
1. 主循环之前;
2. waitCtrlChar返回0的时候。
如果在读完了整条消息之后再调用alarm(1)就不会有问题。
yyy790601 2005-09-13
  • 打赏
  • 举报
回复
贴关键源码。
yjf7888 2005-09-13
  • 打赏
  • 举报
回复
关注
daemeon 2005-09-12
  • 打赏
  • 举报
回复
重新初始化fdset没有?
gaoxianfeng 2005-09-12
  • 打赏
  • 举报
回复
??
你的term alarm 处理函数是什么?
你的select一次后 做了什么操作

23,125

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧