当前位置: 首页 > 面试题库 >

SIGIO到达文件描述符时,我没有设置它,并且当没有可能的IO时

唐照
2023-03-14
问题内容

我正在尝试在文件描述符上进行I / O时接收信号。该程序在不执行I / O时需要做其他事情,因此不能使用select(2)。

当我在下面运行示例代码时,即使在stdin上没有数据,它也会从处理程序内部以最快的速度打印消息。甚至更奇怪的是,siginfo_t结构中报告的文件描述符因运行而异。我只将其设置为stdin(fd
0); 处理程序为什么还要报告其他任何值?有时我看到0,有时我看到1,大多数时候我看到“?”,这表示0、1或2以外的值。

这是在OpenSUSE 12.3,Linux内核3.7.10-1.16上,但是我看到在带有其备用内核的CentOS 6.4上似乎是相同的问题。

我在处理程序中使用write,因为signal(7)表示它是可重入的,因此在信号处理程序中使用是合法的。这也是为什么我不打印sinfo->
si_fd的值的原因。snprintf不是可重入的。有一阵子我怀疑使用SIGIO的stdio库,这就是为什么示例程序中的任何地方(除了库函数err(3)之外)都没有stdio调用的原因。

感谢您花时间阅读我的代码。

#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <err.h>
#include <errno.h>

int needRead = 0;
const unsigned int bufsize = 256;

void handler(int sig, siginfo_t *sinfo, void *value)
{
    char *cp;

    cp = "in handler. fd: ";
    write(2, cp, strlen(cp));
    switch(sinfo->si_fd) {
        case 0: cp = "0\n"; break;
        case 1: cp = "1\n"; break;
        case 2: cp = "2\n"; break;
        default: cp = "?\n"; break;
    }
    write(2, cp, strlen(cp));

    needRead = 1;
}

int main(int argc, char *argv[])
{
    struct sigaction act;
    unsigned int counter = 0;
    int flags;
    char *outp = ".";

    /* set up the signal handler for SIGIO */
    act.sa_sigaction = handler;
    act.sa_flags = 0;
    act.sa_flags = SA_RESTART;
    sigemptyset(&act.sa_mask);
    if (sigaction(SIGIO, &act, NULL) == -1)
        err(1, "attempt to set up handler for SIGIO failed");

    /* arrange to get the signal */
    if (fcntl(0, F_SETOWN, getpid()) == -1)
        err(1, "fnctl to set F_SETOWN failed");
    flags = fcntl(0, F_GETFL);
    if (flags >= 0 && fcntl(0, F_SETFL, flags | O_ASYNC ) == -1)
        err(1, "fnctl F_SETFL to set O_ASYNC failed");

    while (1) {
        char in_buf[bufsize];
        int nc;

        counter++;

        write(STDERR_FILENO, outp, strlen(outp));

        if (needRead) {
            needRead = 0;
            if ((nc = read(STDIN_FILENO, in_buf, bufsize)) == -1) {
                err(1, "read from stdin failed");
            } else {
                outp = "Read '";
                write(STDERR_FILENO, outp, strlen(outp));
                write(STDERR_FILENO, in_buf, nc);
                outp = "'\n";
                write(STDERR_FILENO, outp, strlen(outp));
            }
        }
    }
    return 0;
}

问题答案:

啊,有趣。

简短的答案是,因为stdin是 可写的 ,所以SIGIO反复到达stdin ,并且单独地,您的SIGIO传递设置不正确。

为什么si_fd显然不可靠?

首先,您需要先指定SA_SIGINFO sa_flags才能安全使用sa_sigaction处理程序。

其次,#define _GNU_SOURCE在Linux
为您填充si_fd(和si_band)之前,您需要将F_SETSIG显式地添加到SIGIO
。有点傻,恕我直言,但事实如此。si_fd如您所发现的,没有这个,传入的值就没有意义。

为什么要反复交付SIGIO?

我猜您程序的stdin是从您调用的shell继承的,我猜它是一个终端设备并且是可写的。就像fd 0会持续 select(2)
可写一样,它也会连续为您生成SIGIO。

无论如何,si_band保持答案。启用F_SETSIG,,#include <poll.h>并检查si_bandPOLLIN,POLLOUT等,以确定哪些I / O事件使信号跳闸。

真的,stdin是可写的吗?

是的 尝试以下比较:

$ [ -w /dev/stdin ] && echo Yes, stdin is writeable
Yes, stdin is writeable

# Endless SIGIOs
$ ./my-sigio-prog
^C

# No SIGIO
$ ./my-sigio-prog < /dev/null

# Two SIGIOs, after a delay.  One for line-buffered "foo\n" and one for EOF
$ { sleep 3; echo foo; sleep 3; } | ./my-sigio-prog


 类似资料:
  • 我想开发一个模块化的应用程序,使用MySql数据库,Java11和Spring启动。在我添加模块描述符之前,这个应用程序运行得非常好;所以我只能猜测我在module-info.java中丢失了一些东西,但我不知道它是什么。我感谢任何帮助。这是我的密码 波姆。xml 应用yml module-info.java 使用者JAVA UsersRepository.java 用户资源。JAVA 演示应用程

  • 我已经运行了数据库,并且可以使用swing GUI连接到它。但当我尝试运行我的应用程序时,我得到一个启动错误。以下是详细内容: 1:错误- 信息:初始化Spring根WebApplicationContext[ERROR][pool-2-thread-1 05:20:08](JDBCExceptionReporter.java:LogException:101)无法从基础数据库获取连接![错误][

  • 我的主要活动是 运行时的错误为 w/system.err:org.json.jsonException:org.json.jsonobject.get(jsonobject.java:392)上的描述没有值w/system.err:at org.json.jsonobject.getStri 列表项 ng(JSONObject.java:553) w/system.err:org.json.jso

  • 我想从Kafka的主题消费事件后,他们到达的时间。我希望使用事件的时间在消息的有效负载中。在Kafka那里有可能实现那样的事情吗?它的缺点是什么? 实际示例:一条消息M在12:10产生,在12:11到达我的Kafka主题,我希望消费者在12:41(到达后30分钟)轮询它

  • 问题内容: 这与“没有单独的联接表的hibernate@OneToMany”类似,因为我需要一个没有联接表的@OneToMany关系。但是,我也不想定义逆关系。删除相反的内容似乎会导致自动生成联接表…是否有解决方法? 问题答案: 在JPA 2.0+中,您可以使用@JoinColumn作为避免生成联接表的方法。 尝试一下。 更新 上面提供的信息摘自EJB 3.0o’illy书(查找@JoinColu

  • 我正在尝试从系统中读取。输入是这样的:第一个数字是测试用例的数量,然后是整数,然后是一些行。 问题是,尽管循环中存在条件,但当我完成最后一个测试时,while循环不会退出。