O_CLOEXEC的使用

By default, the new file descriptor is set to remain open across
an execve(2) (i.e., the FD_CLOEXEC file descriptor flag described
in fcntl(2) is initially disabled); the O_CLOEXEC flag, described
below, can be used to change this default.
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.

          Note that the use of this flag is essential in some
          multithreaded programs, because 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 and attempts to set its close-on-exec flag
          using fcntl(2) at the same time as another thread does a
          fork(2) plus execve(2).  Depending on the order of
          execution, the race may lead to the file descriptor
          returned by open() being unintentionally leaked to the
          program executed by the child process created by fork(2).
          (This kind of race is in principle possible for any system
          call that creates a file descriptor whose close-on-exec
          flag should be set, and various other Linux system calls
          provide an equivalent of the O_CLOEXEC flag to deal with
          this problem.)

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>

using namespace std;

#define BUFFER   "test"


int main(int argc, char **argv)
{
    int     tty_fd = -1 ;
    int     rv = -1 ;
    struct termios options;
    printf("pid: %d\n", getpid());

    tty_fd = open("/dev/ttyXRUSB0",O_RDWR|O_NOCTTY|O_NDELAY | O_CLOEXEC) ; //打开串口设备
#if 1
    pid_t fpid; //fpid表示fork函数返回的值
    int count = 0;
    fpid = fork();
    if (fpid < 0){
        printf("error in fork!");
    }else if (fpid == 0) {
        printf("i am the child process, my process id is %d\n", getpid());
        char *argv[] = {"ls", "-l", NULL};
        execv("/bin/ls", argv);
    }
    else {
        printf("i am the parent process, my process id is %d\n", getpid());
        count++;
    }
    printf("统计结果是: %d\n", count);
#endif
    if(tty_fd < 0)
    {
        printf("open tty failed:%s\n", strerror(errno)) ;

        goto cleanup ;
    }

    printf("open devices sucessful!\n") ;

    memset(&options, 0, sizeof(options)) ;

    rv = tcgetattr(tty_fd, &options); //获取原有的串口属性的配置

    if(rv != 0)
    {

        printf("tcgetattr() failed:%s\n",strerror(errno)) ;

        goto cleanup ;

    }

    options.c_cflag|=(CLOCAL|CREAD ); // CREAD 开启串行数据接收,CLOCAL并打开本地连接模式

    options.c_cflag &=~CSIZE;// 先使用CSIZE做位屏蔽

    options.c_cflag |= CS8; //设置8位数据位

    options.c_cflag &= ~PARENB; //无校验位


    /* 设置115200波特率  */

    cfsetispeed(&options, B115200);

    cfsetospeed(&options, B115200);


    options.c_cflag &= ~CSTOPB;/* 设置一位停止位; */


    options.c_cc[VTIME] = 0;/* 非规范模式读取时的超时时间;*/

    options.c_cc[VMIN]  = 0; /* 非规范模式读取时的最小字符数*/

    tcflush(tty_fd ,TCIFLUSH);/* tcflush清空终端未完成的输入/输出请求及数据;TCIFLUSH表示清空正收到的数据,且不读取出来 */


    if((tcsetattr(tty_fd, TCSANOW,&options))!=0)
    {
        printf("tcsetattr failed:%s\n", strerror(errno));
        goto cleanup ;
    }

    while(1)
    {
        rv = write(tty_fd, BUFFER,strlen(BUFFER)) ;
        if(rv < 0)
        {
            printf("Write() error:%s\n",strerror(errno)) ;
            goto cleanup ;
        }
        sleep(3) ;
    }

cleanup:
    close(tty_fd) ;
    return 0 ;

}

O_CLOEXEC 的意思是 close-on-exec,就是执行 (exec函数簇)的时候,关闭父进程继承的 file descriptor.。
如上述代码,不加O_CLOEXEC,执行以下命令:
fuser /dev/ttyXRUSB0
结果是父子两个进程(都打开着文件描述符)。
加O_CLOEXEC。就只有父进程有。子进程在执行execv函数的时候关闭了file descriptor.。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值