首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >libfuse:退出fuse_session_loop

libfuse:退出fuse_session_loop
EN

Stack Overflow用户
提问于 2012-01-18 08:06:35
回答 4查看 3K关注 0票数 6

上下文: Ubuntu 11.10和libfuse 2.8.4-1.4ubuntu1Linux 3.0.0-14-generic #23-Ubuntu SMP Mon Nov 21 20:28:43 UTC 2011 x86_64 GNU/Linux

我正在尝试使用libfuse。我想让fuse_session_loop退出(从信号处理程序或不同的线程),但是当我调用fuse_session_exit时,在会话收到新请求之前什么都不会发生。

fuse_session_exit设置由fuse_session_exited读取的标志。在fuse_session_loop中调试它在fuse_chan_recv上似乎是阻塞的,所以直到循环的顶部它才会再次检查fuse_session_exited ...

代码语言:javascript
复制
int fuse_session_loop(struct fuse_session *se)
{
    int res = 0;
    struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
    size_t bufsize = fuse_chan_bufsize(ch);
    char *buf = (char *) malloc(bufsize);
    if (!buf) {
        fprintf(stderr, "fuse: failed to allocate read buffer\n");
        return -1;
    }

    while (!fuse_session_exited(se)) {
        struct fuse_chan *tmpch = ch;
        res = fuse_chan_recv(&tmpch, buf, bufsize); <--- BLOCKING
        if (res == -EINTR)
            continue;
        if (res <= 0)
            break;
        fuse_session_process(se, buf, res, tmpch);
    }

    free(buf);
    fuse_session_reset(se);
    return res < 0 ? -1 : 0;
}

fuse_chan_recv调用在"/dev/fuse“设备的”读“syscall上阻塞的fuse_kern_chan_receive,所以即使设置了fuse_session_exited标志,也不会发生任何事情。

代码语言:javascript
复制
static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf,
                  size_t size)
{
    struct fuse_chan *ch = *chp;
    int err;
    ssize_t res;
    struct fuse_session *se = fuse_chan_session(ch);
    assert(se != NULL);

restart:
    res = read(fuse_chan_fd(ch), buf, size); <--- BLOCKING
    err = errno;

    if (fuse_session_exited(se))
        return 0;
    if (res == -1) {
        /* ENOENT means the operation was interrupted, it's safe
           to restart */
        if (err == ENOENT)
            goto restart;

        if (err == ENODEV) {
            fuse_session_exit(se);
            return 0;
        }
        /* Errors occuring during normal operation: EINTR (read
           interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
           umounted) */
        if (err != EINTR && err != EAGAIN)
            perror("fuse: reading device");
        return -err;
    }
    if ((size_t) res < sizeof(struct fuse_in_header)) {
        fprintf(stderr, "short read on fuse device\n");
        return -EIO;
    }
    return res;
}

这个问题似乎影响了libfuse提供的hello_ll.c示例以及我的程序。这让我想,也许有一些机制是不起作用的,而应该是这样。也许fuse_session_exit还应该做一些中断read调用的事情,但由于某种原因,这在我的系统上不起作用。

有什么想法吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-01-19 06:41:06

通常,如果在系统调用(如read(2))阻塞时执行信号处理程序,则系统调用会立即返回EINTR (在信号处理程序完成执行之后)。这显然是fuse_session_loopfuse_session_exit的设计目标。

但是,如果信号处理程序安装时设置了SA_RESTART标志(参见sigaction(2)) ),则在信号处理程序执行后,系统调用将不会返回EINTR。系统调用将改为恢复阻塞。

由于某些原因,在我的系统(Ubuntu11.10 x86_64)上, signal (2)的默认行为是安装带有SA_RESTART标志的信号处理程序。

也就是下面节目的重点...

代码语言:javascript
复制
#include <stdlib.h>
#include <signal.h>

void f(int signum) {}

int main()
{
    signal(SIGINT,f);
    return EXIT_SUCCESS;
}

...is如下所示:

代码语言:javascript
复制
rt_sigaction(SIGINT, {0x400524, [INT], SA_RESTORER|SA_RESTART, 0x7f4997e1f420}, {SIG_DFL, [], 0}, 8) = 0

由于这个原因,信号(在fuse和我自己的程序提供的示例中)没有中断fuse_kern_chan_receive中的阻塞读取,正如它们的作者所期望的那样。

修复方法是使用sigaction(2) (并保留SA_RESTART位为零)来安装处理程序(而不是signal(2))。

仍然存在的一个悬而未决的问题是,为什么对signal(2)的调用在缺省情况下会将SA_RESTART标志设置为打开?我预计中断(而不是重启)是预期的默认行为。

票数 1
EN

Stack Overflow用户

发布于 2012-01-18 08:30:01

这可能值得一份错误报告;它也可能被关闭为“按预期工作”。

也就是说,如果您还发送了一个信号来中断在fuse_kern_chan_receive()函数中执行的read()调用,那么它似乎已经准备好通过堆栈向上传播错误,这将触发更高级别调用中的continue,后者将注意到exited标志,并希望尽可能干净地终止循环。

尝试添加一个pthread_kill(3)来终止特定的线程。fuse_signals.c为调用fuse_session_exit()SIGHUPSIGINTSIGTERM安装处理程序。

票数 2
EN

Stack Overflow用户

发布于 2018-04-08 22:50:47

我不能通过将fuse 2.9.2的SA_RESTART标志置零来解决这个问题。

取而代之的是,当我想退出时,我使用了假读。

  1. 在调用fuse_session_exit
  2. Call fuse_session_exit
  3. Read之前打开文件

中的一个字节

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8903448

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档