2017-02-01 15 views
1

Я пытаюсь создать распределяемый двоичный код, чтобы установить старый NAS, у которого есть только libc 2.3. Так pipe2() не доступен на этой машине, но код, который я пытаюсь построить имеет следующую строку:pipe2 (...) vs pipe() + fcntl (...), почему разные?

if (pipe2(info_pipe, O_CLOEXEC | O_NONBLOCK) < 0) 
    goto info_pipe_err; 

Я понимаю, что причина pipe2() существует, чтобы избежать условий гонки, принимая O_CLOEXEC | O_NONBLOCK во время открытия против выполнения этого в два этапа. Но нет никаких потоков в случае, если я смотрю, так что я думал, что я мог бы просто заменить в:

if (pipe(info_pipe) < 0) 
    goto info_pipe_err; 

int direction; // 0=READ, 1=WRITE 
for (direction = 0; direction < 2; ++direction) { 
    int oldflags; 
    oldflags = fcntl(info_pipe[direction], F_GETFL); 
    if (oldflags < 0) 
     goto info_pipe_err; 
    if (
     fcntl(info_pipe[direction], F_SETFL, oldflags | O_NONBLOCK | O_CLOEXEC) < 0 
    ){ 
     goto info_pipe_err; 
    } 
} 

Но это, казалось бы, не взаимозаменяемы, потому что код не работает. Почему это не эквивалентно?

ответ

2

(Отвечая на мой собственный вопрос, потому что я понял это, просто размещение здесь для потомков.)

Если вы строите двоичный файл на более новый компилятор для старой системы, что во время выполнения, вероятно, не знайте значение для O_CLOEXEC ..., поскольку этот флаг был введен с помощью pipe2(). Если он ничего знает, он знает FD_CLOEXEC. И вы не устанавливаете это с помощью F_SETFL, вы используете F_SETFD ... который является отдельным вызовом fcntl().

Следующая замена должна работать:

if (pipe(info_pipe) < 0) 
    goto info_pipe_err; 

int direction; // 0=READ, 1=WRITE 
for (direction = 0; direction < 2; ++direction) { 
    int oldflags; 
    oldflags = fcntl(info_pipe[direction], F_GETFL); 
    if (oldflags < 0) 
     goto info_pipe_err; 
    if (
     fcntl(info_pipe[direction], F_SETFL, oldflags | O_NONBLOCK) < 0 
    ){ 
     goto info_pipe_err; 
    } 
    oldflags = fcntl(info_pipe[direction], F_GETFD); 
    if (oldflags < 0) 
     goto info_pipe_err; 
    if (
     fcntl(info_pipe[direction], F_SETFD, oldflags | FD_CLOEXEC) < 0 
    ){ 
     goto info_pipe_err; 
    } 
} 

Как уже отмечалось, это не имеет аспект безопасности потоков, предлагаемых pipe2(), позволяя все это должно быть сделано сразу.