statvfs 可以阻止某些网络设备吗?这种情况怎么处理?
Can statvfs block on certain network devices? How to handle that case?
我正在使用 keybase(用于您的 SSH 和其他密钥的云基础数据存储),今天以某种方式在我启动 X-Windows.
时它没有重新启动
因此,命令 df
(因此在我的代码中是 statvfs()
)会在告诉我传输中断后阻塞。
$ 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
_
提示会停在那里,永远不会 return。
我不太关心 df
目前会卡住,但我想知道我应该如何更新我的 C++ 代码以处理 statvfs()
在我的应用程序中阻塞的情况因为那在那里是不可接受的。我只是看不出有什么方法可以在不使用信号的情况下中断该调用(我想到了 SIGALRM)。
有没有更好的方法来处理这种情况?
(注意:我的代码是用 C++ 编写的,尽管 C 解决方案应该可以正常工作并且很可能是需要的,因此使用两种语言进行标记。)
此代码将 statvfs()
包装在一个函数中,该函数设置一个中断调用的警报。如果警报触发并中断对 statvfs()
的调用,它将 return -1
和 errno 设置为 EINTR
(我没有尝试过,所以它可能不完美.. .):
#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 );
}
这也可以使用一些错误检查,尤其是在 sigaction()
调用时,但它已经足够长以生成滚动条,所以我将其省略。
如果您发现您的进程仍然卡在 statvfs()
调用中,并且如果您 运行 正在 Linux 上,运行 您的进程在 strace
并跟踪实际的系统调用。您应该看到对 statvfs()
的调用,然后是中断 statvfs()
调用的警报信号。如果您看到 另一个 调用 statvfs()
,这意味着您的 libc
已重新启动系统调用。
我正在使用 keybase(用于您的 SSH 和其他密钥的云基础数据存储),今天以某种方式在我启动 X-Windows.
时它没有重新启动因此,命令 df
(因此在我的代码中是 statvfs()
)会在告诉我传输中断后阻塞。
$ 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
_
提示会停在那里,永远不会 return。
我不太关心 df
目前会卡住,但我想知道我应该如何更新我的 C++ 代码以处理 statvfs()
在我的应用程序中阻塞的情况因为那在那里是不可接受的。我只是看不出有什么方法可以在不使用信号的情况下中断该调用(我想到了 SIGALRM)。
有没有更好的方法来处理这种情况?
(注意:我的代码是用 C++ 编写的,尽管 C 解决方案应该可以正常工作并且很可能是需要的,因此使用两种语言进行标记。)
此代码将 statvfs()
包装在一个函数中,该函数设置一个中断调用的警报。如果警报触发并中断对 statvfs()
的调用,它将 return -1
和 errno 设置为 EINTR
(我没有尝试过,所以它可能不完美.. .):
#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 );
}
这也可以使用一些错误检查,尤其是在 sigaction()
调用时,但它已经足够长以生成滚动条,所以我将其省略。
如果您发现您的进程仍然卡在 statvfs()
调用中,并且如果您 运行 正在 Linux 上,运行 您的进程在 strace
并跟踪实际的系统调用。您应该看到对 statvfs()
的调用,然后是中断 statvfs()
调用的警报信号。如果您看到 另一个 调用 statvfs()
,这意味着您的 libc
已重新启动系统调用。