问题
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