【发布时间】:2011-09-27 09:15:25
【问题描述】:
我使用这个 fanotify 示例来监控整个文件系统 (/) 上的打开/访问权限:http://git.infradead.org/users/eparis/fanotify-example.git。
然后我有一个带有多个线程的测试程序,每个线程迭代示例文件并打开/关闭其中的文件,有时我的程序在 open() 处挂起。
操作系统:Ubuntu 2.6.38-11 x86_64。
不支持多线程打开是不是fanotify的bug?
我的测试程序代码:
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <ctype.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
//open file function
void open_file( char* file )
{
int fd = -1;
fd = open( file, O_WRONLY, 0x666 );
if( fd >= 0 )
{
printf("open:%s\n", file );
close( fd );
}
}
//iterate directory function
void printdir(char *dir, int depth)
{
DIR *dp;
struct stat statbuf;
char pathbuf[2048] = {0};
struct dirent entry;
struct dirent *entryPtr = NULL;
//printf("opendir %s\n", dir );
usleep( 300 );
if((dp = opendir(dir)) == NULL) {
if( errno != ENOTDIR )
{
fprintf(stderr,"cannot open directory: %s\n", dir);
perror("open fial");
}
return;
}
readdir_r( dp, &entry, &entryPtr );
while( entryPtr != NULL)
{
snprintf(pathbuf,2000, "%s/%s\0", dir, entry.d_name );
printf("iteraotr:%s\n", pathbuf );
lstat( pathbuf, &statbuf );
if(S_ISDIR( statbuf.st_mode ))
{
/* Found a directory, but ignore . and .. */
if(strcmp(".",entry.d_name) == 0 ||
strcmp("..",entry.d_name) == 0)
{
}
else
{
//printf("%d,%s\n",depth, entry->d_name);
printdir( pathbuf, depth+1);
}
}
else
{
//printf("%*s%s\n",depth,"",entry->d_name);
open_file( pathbuf );
}
readdir_r( dp, &entry, &entryPtr );
}
closedir(dp);
}
//thread function
void* iterator_dir( void* data )
{
char* path = (char*)data;
printf("In iterator_dir(): %s\n", path );
printdir( path, 0 );
return NULL;
}
pthread_t threadID[10] = {0};
//main function
int main( int argc, char** argv )
{
if( argc < 3 )
{
printf("Usage: %s <thread_num> <file>\n", argv[0] );
exit(0);
}
if( isdigit( (char)*argv[1] ) == 0 )
{
printf(" Thread num is 0 - 9\n");
exit(0);
}
int thread_num = atoi( argv[1] );
char* res;
pthread_attr_t attr;
pthread_attr_init(&attr);
int i = 0;
for( i = 0; i < thread_num; ++i )
{
pthread_create( &threadID[i], &attr, &iterator_dir, argv[2]);
}
for( i = 0; i < thread_num; ++i )
{
pthread_join( threadID[i] , &res );
}
}
2011-09-28 编辑:
我注释了打开文件的操作,只保留了迭代目录部分。应用程序仍然挂起。 这是 strace 的输出:
enter code here
pid 10692] open("/home/byang//.config/menus", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC <unfinished ...>
[pid 10691] write(1, "1213966080 opendir /home/byang//"..., 56) = 56
…………
[pid 10689] madvise(0x7f3c48dbc000, 8368128, MADV_DONTNEED) = 0
[pid 10689] _exit(0) = ?
Process 10689 detached
[pid 10688] <... futex resumed> ) = 0
[pid 10688] futex(0x7f3c47db99d0, FUTEX_WAIT, 10692, NULL <unfinished ...>
它挂在这里,当我关闭 fanotify 时,它继续...
[pid 10692] <... open resumed> ) = 11
[pid 10692] getdents(11, /* 4 entries */, 32768) = 128
[pid 10692] lstat("/home/byang//.config/menus/applications.menu", {st_mode=S_IFREG|0644, st_size=233, ...}) = 0
10688 是父线程; 10689,10691,10692 是迭代目录的子线程。 好像10692正在等待fanotify的回复?
【问题讨论】:
-
好吧,'open()' 是用 3 个参数调用的,但你没有给出 O_CREAT,所以这是错误的 - 我至少要解决这个问题,删除 3. 参数。 (而且 0x666 无论如何都不是你想要的,而是 0666)。还要检查所有调用是否有错误,以确保您没有遗漏任何失败的内容(例如 readdir_r,lstat 调用)。了解程序挂起时在做什么也很有趣,因此请通过
strace -f运行它 -
我注释了打开的文件,只保留打开的目录,问题依旧。我检查了 readdir_r 和 lstat 的结果,出错时退出。 strace 的输出在 body 中更新。
标签: linux multithreading freeze