libgcc

导航

 

man open里有这么一个flag:


       O_CLOEXEC (Since Linux 2.6.23)
              Enable the close-on-exec flag for the new file descriptor.  Specifying this flag permits a program to  avoid  additional  fcntl(2)  F_SETFD
              operations  to  set the FD_CLOEXEC flag.  Additionally, use of this flag is essential in some multithreaded programs since using a separate fcntl(2) F_SETFD operation to set the FD_CLOEXEC flag does not suffice to avoid race conditions where one thread opens a file descriptor at the same time as another thread does a fork(2) plus execve(2).

  意思就是新的内核里的这个选项是把fcntl的这个设置放在open里原子操作,以免在多线程程序里有可能会出现fcntl在设置的同时其它线程在fork+execve,虽然在线程里fork比较罕见.这个选项的意思就是子进程默认是继承父进程打开的所有fd,如果句柄加入了这个设置,在execve替换进程时就会关闭设置这个选项的所有fd.写个例子:

 1 #include <sys/types.h>
 2 #include <sys/stat.h>
 3 #include <sys/wait.h>
 4 #include <unistd.h>
 5 #include <fcntl.h>
 6 #include <stdio.h>
 7 #include <string.h>
 8 #include <stdlib.h>
 9 #include <pthread.h>
10 
11 int flag=0;
12 void* threadFunc(void* arg)
13 {
14 #ifdef _CLOEXEC_
15     int fd = open("mm.log", O_CREAT|O_WRONLY|O_TRUNC|O_CLOEXEC, 0644);
16 #else
17     int fd = open("mm.log", O_CREAT|O_WRONLY|O_TRUNC, 0644);
18 #endif
19     printf("fd for mm.log is : %d\n", fd);
20     if(fd<0) { perror("open mm.log failed"); exit(-1);}
21 
22     char s[32]="";
23     sprintf(s, "%u", getpid());
24     write(fd, s, strlen(s));
25     flag=1;
26     sleep(1000);
27 }
28 
29 int main(int argc, char* argv[])
30 {
31     pthread_t thd;
32     pthread_create(&thd, NULL, threadFunc, NULL);
33 
34     while(!flag);
35 
36     pid_t pid;
37     pid=fork();
38     if(pid<0) { perror("fork failed"); exit(-1);}
39     else if(pid==0)
40     {
41         //child
42         if(execl("/bin/sleep", "sleep", "100")== -1) { perror("exit failed"); exit(-1);}
43 
44         _exit(0);
45     }
46     printf("child pid: %u\n", pid);
47     exit(0);
48 }

使用两个选项编译两个程序:

[libgcc@Heineken ~/cpp]$ gcc -U_CLOEXEC_ -o nocloexec o_cloexec.c -lpthread 
[libgcc@Heineken ~/cpp]$ gcc -D_CLOEXEC_ -o cloexec o_cloexec.c -lpthread  
[libgcc@Heineken ~/cpp]$ ./nocloexec 
fd for mm.log is : 3
child pid: 2201
[libgcc@Heineken ~/cpp]$ ps -ef|grep 220[1]
libgcc    2201     1  0 03:23 pts/0    00:00:00 sleep 100
[libgcc@Heineken ~/cpp]$ lsof -p 2201
COMMAND  PID   USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
sleep   2201 libgcc  cwd    DIR  253,0     4096 319493 /home/libgcc/cpp
sleep   2201 libgcc  rtd    DIR  253,0     4096      2 /
sleep   2201 libgcc  txt    REG  253,0    25688 262402 /bin/sleep
sleep   2201 libgcc  mem    REG  253,0   151500 677607 /lib/ld-2.12.90.so
sleep   2201 libgcc  mem    REG  253,0  1889628 677608 /lib/libc-2.12.90.so
sleep   2201 libgcc  mem    REG  253,0 99158720 399306 /usr/lib/locale/locale-archive
sleep   2201 libgcc    0u   CHR  136,0      0t0      3 /dev/pts/0
sleep   2201 libgcc    1u   CHR  136,0      0t0      3 /dev/pts/0
sleep   2201 libgcc    2u   CHR  136,0      0t0      3 /dev/pts/0
sleep   2201 libgcc    3w   REG  253,0        4 336396 /home/libgcc/cpp/mm.log
[libgcc@Heineken ~/cpp]$ ./cloexec 
fd for mm.log is : 3
child pid: 2216
[libgcc@Heineken ~/cpp]$ ps -ef|grep 221[6]
libgcc    2216     1  0 03:24 pts/0    00:00:00 sleep 100
[libgcc@Heineken ~/cpp]$ lsof -p 2216
COMMAND  PID   USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
sleep   2216 libgcc  cwd    DIR  253,0     4096 319493 /home/libgcc/cpp
sleep   2216 libgcc  rtd    DIR  253,0     4096      2 /
sleep   2216 libgcc  txt    REG  253,0    25688 262402 /bin/sleep
sleep   2216 libgcc  mem    REG  253,0   151500 677607 /lib/ld-2.12.90.so
sleep   2216 libgcc  mem    REG  253,0  1889628 677608 /lib/libc-2.12.90.so
sleep   2216 libgcc  mem    REG  253,0 99158720 399306 /usr/lib/locale/locale-archive
sleep   2216 libgcc    0u   CHR  136,0      0t0      3 /dev/pts/0
sleep   2216 libgcc    1u   CHR  136,0      0t0      3 /dev/pts/0
sleep   2216 libgcc    2u   CHR  136,0      0t0      3 /dev/pts/0

  看到没,如果不加这个选项,sleep程序都能打开一个文本文件.

posted on 2013-01-23 03:27  libgcc  阅读(1386)  评论(0)    收藏  举报