浅析open函数O_CLOEXEC模式和fcntl函数FD_CLOEXEC选项

关于open函数O_CLOEXEC模式,fcntl函数FD_CLOEXEC 选项 ,总结为如下几点:

1.调用open函数O_CLOEXEC 模式 打开的文件描述符在执行exec调用新程序中关闭,且为原子操作。

2.调用 open函数不使用O_CLOEXEC模式打开的文件描述符,然后调用fcntl 函数设置FD_CLOEXEC选项,效果和使用O_CLOEXEC选项open函数相同,但分别调用open、fcnt两个l函数,不是原子操作,多线程环境中存在竞态条件,故用open函数O_CLOEXEC选项代替之

3.
调用open函数O_CLOEXEC模式打开的文件描述符,或是使用fcntl设置FD_CLOEXEC选项,这二者得到(处理)的描述符在通过fork调用产生的子进程中均不被关闭。

4.调用dup族类函数得到的新文件描述符将清除O_CLOEXEC模式。


测试程序如下:

点击(此处)折叠或打开

  1. #include <unistd.h>
  2. #include <sys/types.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <errno.h>

  8. #define err_sys(fmt, arg...) \
  9. do { \
  10.     printf(fmt, ##arg);\
  11.     printf("\nerrno:%d %s\n", errno, strerror(errno));\
  12.     exit(EXIT_FAILURE);\
  13. } while (0)


  14. int main()
  15. {
  16.     int fd, fd2, val;
  17.     pid_t pid;
  18. #ifdef _O_CLOEXEC
  19.     if ((fd = open("my.txt", O_RDWR | O_CREAT | O_CLOEXEC, 0600)) < 0) 
  20. #else
  21.     if ((fd = open("my.txt", O_RDWR | O_CREAT, 0600)) < 0) 
  22. #endif
  23.         err_sys("open error");

  24. #ifdef _DUP
  25.     if ((fd2 = dup(fd)) < 0)
  26.         err_sys("dup error");
  27.     if (write(fd2, "123", 3) < 0)
  28.         err_sys("write error");
  29. #endif

  30. #ifdef _FCNTL_CLOEXEC
  31.     if ((val = fcntl(fd, F_GETFD)) < 0)
  32.         err_sys("fcntl(F_GETFD) error");

  33.     val |= FD_CLOEXEC;
  34.     if (fcntl(fd, F_SETFD, val) < 0)
  35.         err_sys("fcntl( F_SETFD) error");
  36. #endif

  37. #ifndef _FORK 
  38.     if (execl("/bin/sleep", "sleep", "10000", (void*)0) < 0)
  39.         err_sys("execl error");
  40. #else
  41.  switch ((pid = fork())) {
  42.         case -1:
  43.             err_sys("fork error");
  44.         case 0:
  45.             sleep(10000);
  46.             break;
  47.         default:
  48.             sleep(10000);
  49.             break;
  50.     }
  51. #endif

  52.     return 0;
  53. }
通过宏 _O_CLOEXEC编译进 O_CLOEXEC选项
#gcc -D_O_CLOEXEC -o cloexec cloexec.c
执行程序
#./cloexec 

查看进程和进程资源,注意执行execl后进程名字变为sleep了
#ps aux|grep sleep 
root      7900  0.0  0.0   4200   280 pts/0    S+   11:45   0:00 sleep 10000
root      7915  0.0  0.1   4384   836 pts/1    S+   11:49   0:00 grep --color=auto sleep

#lsof -p 7900     
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
sleep   7900 root  cwd    DIR    8,1     4096 163741 /home/zozy/AUP
sleep   7900 root  rtd    DIR    8,1     4096      2 /
sleep   7900 root  txt    REG    8,1    26156 131621 /bin/sleep
sleep   7900 root  mem    REG    8,1  2919792     12 /usr/lib/locale/locale-archive
sleep   7900 root  mem    REG    8,1  1730024  15701 /lib/i386-linux-gnu/libc-2.15.so
sleep   7900 root  mem    REG    8,1   134344  15713 /lib/i386-linux-gnu/ld-2.15.so
sleep   7900 root    0u   CHR  136,0      0t0      3 /dev/pts/0
sleep   7900 root    1u   CHR  136,0      0t0      3 /dev/pts/0
sleep   7900 root    2u   CHR  136,0      0t0      3 /dev/pts/0

可以看出进程资源中没有文件my.txt


不带 _O_CLOEXEC 编译
# gcc  -o nocloexec cloexec.c
执行程序
# ./nocloexec 

查看进程和进程资源
#ps aux|grep sleep
root      7925  0.0  0.0   4200   280 pts/0    S+   11:51   0:00 sleep 10000
root      7928  0.0  0.1   4384   836 pts/1    S+   11:52   0:00 grep --color=auto sleep

#lsof -p 7925
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
sleep   7925 root  cwd    DIR    8,1     4096 163741 /home/zozy/AUP
sleep   7925 root  rtd    DIR    8,1     4096      2 /
sleep   7925 root  txt    REG    8,1    26156 131621 /bin/sleep
sleep   7925 root  mem    REG    8,1  2919792     12 /usr/lib/locale/locale-archive
sleep   7925 root  mem    REG    8,1  1730024  15701 /lib/i386-linux-gnu/libc-2.15.so
sleep   7925 root  mem    REG    8,1   134344  15713 /lib/i386-linux-gnu/ld-2.15.so
sleep   7925 root    0u   CHR  136,0      0t0      3 /dev/pts/0
sleep   7925 root    1u   CHR  136,0      0t0      3 /dev/pts/0
sleep   7925 root    2u   CHR  136,0      0t0      3 /dev/pts/0
sleep   7925 root    3u   REG    8,1        0 163759 /home/zozy/AUP/my.txt

可以看出进程资源中有文件my.txt


测试fcntl函数可以通过设置编译宏-D _FCNTL_CLOEXEC测试,编译测试过程同上,同理通过开启-D_O _CLOEXEC -D_FORK编译选项测试使用 O _CLOEXEC模式的描述符在子进程中的状态,通过宏 -D _DUP编译选项测试dup函数对O_CLOEXEC的影响,编译测试过程略。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值