Can statvfs block on certain network devices? How to handle that case?

让人想犯罪 __ 提交于 2019-12-13 03:38:19

问题


I am using keybase (a cloud base data store for your SSH and other keys) and today somehow it did not restart when I started X-Windows.

As a result, the command df (and thus statvfs() in my code) would just block after telling me that the transport was down.

$ df
df: '/home/alexis/"/home/alexis/.local/share/keybase/fs"': Transport endpoint is not connected
df: /run/user/1000/gvfs: Transport endpoint is not connected
_

The prompt would sit there and never return.

I don't care much that df would get stuck at the moment, but I'm wondering how I should update my C++ code to handle the case where statvfs() blocks in my application because that's not acceptable there. I just don't see a way to break out of that call without using a signal (SIGALRM comes to mind).

Is there a better way to handle this case?

(Note: my code is in C++, although a C solution should work just fine and is likely what is required, hence the tagging with both languages.)


回答1:


This code will wrap statvfs() in a function that sets up an alarm to interrupt the call. It will return -1 with errno set to EINTR should the alarm fire and interrupt the call to statvfs() (I haven't tried this so it may not be perfect...):

#include <sigaction.h>
#include <sys/statvfs.h>
#include <unistd.h>
#include <string.h>

// alarm handler doesn't need to do anything
// other than simply exist
static void alarm_handler( int sig )
{
    return;
}

 .
 .
 .

// statvfs() with a timeout measured in seconds
// will return -1 with errno set to EINTR should
// it time out
int statvfs_try( const char *path, struct statvfs *s, unsigned int seconds )
{
    struct sigaction newact;
    struct sigaction oldact;

    // make sure they're entirely clear (yes I'm paranoid...)
    memset( &newact, 0, sizeof( newact ) );
    memset( &oldact, 0, sizeof( oldact) );

    sigemptyset( &newact.sa_mask );

    // note that does not have SA_RESTART set, so
    // statvfs should be interrupted on a signal
    // (hopefully your libc doesn't restart it...)
    newact.sa_flags = 0;
    newact.sa_handler = alarm_handler;
    sigaction( SIGALRM, &newact, &oldact );

    alarm( seconds );

    // clear errno
    errno = 0;
    int rc = statvfs( path, s );

    // save the errno value as alarm() and sigaction() might change it
    int save_errno = errno;

    // clear any alarm and reset the signal handler
    alarm( 0 );
    sigaction( SIGALRM, &oldact, NULL );

    errno = saved_errno;
    return( rc );
}

That could also use some error checking, especially on the sigaction() calls, but it's long enough to generate a scroll bar already, so I left that out.

If you find your process remains stuck in statvfs() call, and if you're running on Linux, run your process under the strace and trace the actual system calls. You should see the call to statvfs(), then an alarm signal that interrupts the statvfs() call. If you see another call to statvfs(), that means your libc has restarted the system call.



来源:https://stackoverflow.com/questions/48726796/can-statvfs-block-on-certain-network-devices-how-to-handle-that-case

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!