關於檔案描述符的close-on-exec標誌位

li27z發表於2016-10-02

引言

我們在使用一些系統呼叫對檔案描述符進行操作時,常常會碰到是否為檔案描述符賦予CLOEXEC屬性的情況,例如:

// open函式中的flags引數可指定O_CLOEXEC標誌
int open(const char *pathname, int flags);

// fcntl函式可通過FD_GETFD、FD_SETFD操作設定FD_CLOEXEC標誌
int fcntl(int fd, int cmd, ... /* arg */);

在上篇部落格,我們新學到的系統呼叫eventfd同樣也有:
// 引數flags可取EFD_NONBLOCK、EFD_CLOEXEC、EFD_SEMAPHORE
int eventfd(unsigned int initval, int flags);

那麼,close-on-exec標誌位究竟有什麼用呢?

設定close-on-exec標誌位的意義

close-on-exec字面意思即執行時關閉。程式中每個開啟的描述符都有一個執行時關閉標誌,若設定此標誌,則在執行exec時關閉該描述符,否則該描述符仍開啟。

設定該標誌位的重要意義在於它可以方便我們關閉無用的檔案描述符

我們考慮這樣的情況:父程式fork出一個子程式,子程式是父程式的副本,獲得父程式的資料空間、堆和棧的副本,當然也包括父程式開啟的檔案描述符。

fork之後一般我們會呼叫exec執行另一個程式,此時會用全新的程式替換子程式的正文、資料、堆和棧等,此時儲存檔案描述符的變數當然也不存在了,我們就無法關閉無用的檔案描述符了。所以通常我們會在fork子程式後,在子程式中直接執行close關掉無用的檔案描述符,然後再執行exec。

但是在複雜系統中,有時我們fork出子程式時已經不知道開啟了多少檔案描述符了(包括socket控制程式碼等),如果進行逐一清理難度很大。我們期望的是能在fork出子程式前、開啟某個檔案描述符時就指定好——這個檔案描述符在我fork出子程式後、執行exec時就關閉。其實是有這樣的方法的:即所謂的 close-on-exec。

測試程式碼

#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
    int fd;
    pid_t pid;
// 判斷是否定義_O_CLOEXEC巨集
#ifdef _O_CLOEXEC
    if ((fd = open("my.txt", O_RDWR | O_CREAT | O_CLOEXEC, 0600)) < 0) 
#else
    if ((fd = open("my.txt", O_RDWR | O_CREAT, 0600)) < 0) 
#endif
        perror("open");
// 通過開啟-D_O_CLOEXEC -D_FORK編譯選項測試使用O_CLOEXEC模式的描述符在子程式中的狀態
#ifndef _FORK 
    // 執行execl後程式名更改為sleep
    if (execl("/bin/sleep", "sleep", "10000", (void*)0) < 0)
        perror("execl");
#else
 switch ((pid = fork())) {
        case -1:
            perror("fork");
        case 0:
            if (execl("/bin/sleep", "sleep", "10000", (void*)0) < 0)
                perror("execl");
        default:
            sleep(10000);
            break;
    }
#endif

    return 0;
}

測試結果

1.(1)編譯進O_CLOEXEC選項

這裡寫圖片描述

這裡寫圖片描述

程式資源中沒有了my.txt

(2)不編譯進O_CLOEXEC選項

這裡寫圖片描述

這裡寫圖片描述

程式資源中仍有my.txt

2.編譯進O_CLOEXEC選項、_FORK選項

這裡寫圖片描述

這裡寫圖片描述

子程式資源中沒有了my.txt,父程式中仍存在。


參考資料:
http://blog.csdn.net/chrisniu1984/article/details/7050663
http://blog.csdn.net/ubuntu_hao/article/details/51393632

相關文章