هل يتم تعيين خاصية O_nonblock خاصية لوصف الملف أو الملف الأساسي؟

StackOverflow https://stackoverflow.com/questions/2889901

سؤال

من ما كنت أقرأه على موقع المجموعة المفتوحة على fcntl, open, read, ، و write, ، أحصل على انطباع بأن ما إذا كان O_NONBLOCK تم تعيينه على واصف الملف ، وبالتالي ما إذا كان يتم استخدام I/O غير المحظور مع الواصف ، يجب أن يكون خاصية لواصف الملف بدلاً من الملف الأساسي. إن كونك خاصية لوصف الملف يعني ، على سبيل المثال ، أنه إذا قمت بتكرار واصف ملف أو فتح واصفًا آخر على نفس الملف ، فيمكنني استخدام حظر I/O مع I/O غير المحظورة مع الآخر.

ومع ذلك ، فإن تجربة FIFO ، يبدو أنه من غير الممكن أن يكون لديك واصف I/O ممنوع واصف I/O غير المحظور إلى FIFO في وقت واحد (لذلك سواء O_NONBLOCK تعيين هو خاصية للملف الأساسي [FIFO]):

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    int fds[2];
    if (pipe(fds) == -1) {
        fprintf(stderr, "`pipe` failed.\n");
        return EXIT_FAILURE;
    }

    int fd0_dup = dup(fds[0]);
    if (fd0_dup <= STDERR_FILENO) {
        fprintf(stderr, "Failed to duplicate the read end\n");
        return EXIT_FAILURE;
    }

    if (fds[0] == fd0_dup) {
        fprintf(stderr, "`fds[0]` should not equal `fd0_dup`.\n");
        return EXIT_FAILURE;
    }

    if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) {
        fprintf(stderr, "`fds[0]` should not have `O_NONBLOCK` set.\n");
        return EXIT_FAILURE;
    }

    if (fcntl(fd0_dup, F_SETFL, fcntl(fd0_dup, F_GETFL) | O_NONBLOCK) == -1) {
        fprintf(stderr, "Failed to set `O_NONBLOCK` on `fd0_dup`\n");
        return EXIT_FAILURE;
    }

    if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) {
        fprintf(stderr, "`fds[0]` should still have `O_NONBLOCK` unset.\n");
        return EXIT_FAILURE; // RETURNS HERE
    }

    char buf[1];
    if (read(fd0_dup, buf, 1) != -1) {
        fprintf(stderr, "Expected `read` on `fd0_dup` to fail immediately\n");
        return EXIT_FAILURE;
    }
    else if (errno != EAGAIN) {
        fprintf(stderr, "Expected `errno` to be `EAGAIN`\n");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

هذا يتركني أفكر: هل من الممكن أن يكون لديك واصف I/O غير محظور وحظر واصف I/O إلى نفس الملف ، وإذا كان الأمر كذلك ، فهل يعتمد على نوع الملف (ملف منتظم ، FIFO ، حظر ملف خاص ، ملف شخصي خاص ، مقبس ، إلخ)؟

هل كانت مفيدة؟

المحلول

O_nonblock هي خاصية لوصف الملف المفتوح ، وليس من واصف الملف ، ولا للملف الأساسي.

نعم ، يمكن أن يكون لديك واصفات ملفات منفصلة مفتوحة لنفس الملف ، أحدها يحظر والآخر غير محظور.

تحتاج إلى التمييز بين FIFO (تم إنشاؤه باستخدام mkfifo()) وأنبوب (تم إنشاؤه باستخدام pipe()).

لاحظ أن حالة الحظر هي خاصية "وصف الملف المفتوح" ، ولكن في أبسط الحالات ، هناك رسم خرائط فردي بين واصفات الملفات وأوصاف الملف المفتوحة. ال open() تقوم استدعاء الوظيفة بإنشاء وصف جديد للملف المفتوح ووصف ملف جديد يشير إلى وصف الملف المفتوح.

عندما تستخدم dup(), ، لديك واصفان للملف يشاركان وصفًا مفتوحًا واحدًا ، والخصائص تنتمي إلى وصف الملف المفتوح. وصف fcntl() يقول أن f_setfl يؤثر على وصف الملف المفتوح المرتبط بوصف الملف. لاحظ أن lseek() يقوم بضبط موضع الملف لوصف الملف المفتوح المرتبط بوصاف الملف - بحيث يؤثر على واصفات الملفات الأخرى المكررة من المصنفة الأصلية.

إزالة الخطأ معالجة من الكود الخاص بك لتقليله ، لديك:

int fds[2];
pipe(fds);
int fd0_dup = dup(fds[0]);
fcntl(fd0_dup, F_SETFL, fcntl(fd0_dup, F_GETFL) | O_NONBLOCK);

الآن كل من FD0_DUP و FDS [0] الرجوع إلى نفس وصف الملف المفتوح (بسبب dup())، لذلك fcntl() أثرت العملية على كلا واصفات الملف.

if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) { ... }

وبالتالي فإن السلوك المرصود هنا مطلوب من قبل POSIX.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top