splice(2)

الاسم
splice - وصل البيانات من/إلى أنبوب

المكتبة
مكتبة سي المعيارية (libc، -lc)

موجز
#define _GNU_SOURCE         /* انظر feature_test_macros(7) */
#define _FILE_OFFSET_BITS 64
#include <fcntl.h>

ssize_t splice(int fd_in, off_t *_Nullable off_in,
               int fd_out, off_t *_Nullable off_out,
               size_t size, unsigned int flags);

الوصف
تنقل splice() البيانات بين واصفي ملف دون نسخ بين مساحة عنوان النواة ومساحة عنوان المستخدم. تنقل حتى size بايت من البيانات من واصف الملف fd_in إلى واصف الملف fd_out، حيث يجب أن يشير أحد واصفي الملف إلى أنبوب.

تنطبق الدلالات التالية على fd_in و off_in:

•   إذا كان fd_in يشير إلى أنبوب، فيجب أن يكون off_in NULL.

•   إذا كان fd_in لا يشير إلى أنبوب وكان off_in NULL، تُقرأ البايتات من fd_in بدءًا من إزاحة الملف، وتُضبط إزاحة الملف بشكل مناسب.

•   إذا كان fd_in لا يشير إلى أنبوب وكان off_in ليس NULL، فيجب أن يشير off_in إلى مخزن مؤقت يحدد الإزاحة الابتدائية التي ستُقرأ منها البايتات من fd_in؛ في هذه الحالة، لا تتغير إزاحة ملف fd_in، وتُضبط الإزاحة المشار إليها بواسطة off_in بدلاً من ذلك.

تنطبق عبارات مماثلة على fd_out و off_out.

المعامل flags هو قناع بتات (bit mask) يتكون من دمج صفر أو أكثر من القيم التالية باستخدام عملية OR المنطقية:

SPLICE_F_MOVE
    محاولة نقل الصفحات بدلاً من نسخها. هذا مجرد تلميح للنواة: قد تُنسخ الصفحات إذا لم تستطع النواة نقل الصفحات من الأنبوب، أو إذا كانت مخازن الأنبوب المؤقتة لا تشير إلى صفحات كاملة. كان التنفيذ الأولي لهذه العلامة معيبًا: لذلك بدءًا من Linux 2.6.21 أصبحت بلا تأثير (ولكنها لا تزال مسموحة في استدعاء splice())؛ في المستقبل، قد يُستعاد تنفيذ صحيح.

SPLICE_F_NONBLOCK
    لا تحجب على الإدخال/الإخراج. هذا يجعل عمليات أنبوب splice غير محجوبة، ولكن splice() قد تحجب مع ذلك لأن واصفات الملف التي يتم الوصل منها/إليها قد تحجب (ما لم تكن تحتوي على العلامة O_NONBLOCK).

SPLICE_F_MORE
    ستأتي بيانات إضافية في splice لاحق. هذا تلميح مفيد عندما يشير fd_out إلى مقبس (انظر أيضًا وصف MSG_MORE في send(2)، ووصف TCP_CORK في tcp(7)).

SPLICE_F_GIFT
    غير مستخدم لـ splice()؛ انظر vmsplice(2).

قيمة الإرجاع
عند الإكمال بنجاح، تُرجع splice() عدد البايتات التي تم وصلها إلى أو من الأنبوب.

قيمة الإرجاع 0 تعني نهاية الإدخال. إذا كان fd_in يشير إلى أنبوب، فهذا يعني عدم وجود بيانات للنقل، ولن يكون من المنطقي الحجب لأنه لا توجد كتّاب متصلون بنهاية الكتابة للأنبوب.

عند الخطأ، تُرجع splice() -1 ويُضبط errno للإشارة إلى الخطأ.

الأخطاء

EAGAIN
    حُدد SPLICE_F_NONBLOCK في flags أو وُسم أحد واصفات الملفات على أنه غير مانع (O_NONBLOCK)، وكانت العملية ستمنع.

EBADF
    واصف ملف واحد أو كلاهما غير صالح، أو ليس لديه وضع قراءة-كتابة مناسب.

EINVAL
    نظام الملفات الهدف لا يدعم الوصل.

EINVAL
    الملف الهدف مفتوح في وضع الإلحاق.

EINVAL
    لا يشير أي من واصفي الملف إلى أنبوب.

EINVAL
    أُعطيت إزاحة لجهاز غير قابل للبحث (مثل أنبوب).

EINVAL
    يشير fd_in و fd_out إلى نفس الأنبوب.

ENOMEM
    نفدت الذاكرة.

ESPIPE
    إما off_in أو off_out لم يكن NULL، ولكن واصف الملف المقابل يشير إلى أنبوب.

المعايير
لينكس.

التاريخ
لينكس 2.6.17، glibc 2.5.

في Linux 2.6.30 والإصدارات الأقدم، كان مطلوبًا أن يكون واحد بالضبط من fd_in و fd_out أنبوبًا. منذ Linux 2.6.31، قد يشير كلا الوسيطين إلى أنابيب.

ملاحظات
توفر استدعاءات النظام الثلاثة splice() و vmsplice(2) و tee(2) لبرامج مساحة المستخدم تحكمًا كاملاً في مخزن مؤقت عشوائي للنواة، يُنفذ داخل النواة باستخدام نفس نوع المخزن المؤقت المستخدم للأنبوب. بشكل عام، تؤدي استدعاءات النظام هذه المهام التالية:

splice()
    تنقل البيانات من المخزن المؤقت إلى واصف ملف عشوائي، أو العكس، أو من مخزن مؤقت إلى آخر.

tee(2)
    "تنسخ" البيانات من مخزن مؤقت إلى آخر.

vmsplice(2)
    "تنسخ" البيانات من مساحة المستخدم إلى المخزن المؤقت.

على الرغم من أننا نتحدث عن النسخ، إلا أن النسخ الفعلية تُتجنب عمومًا. تفعل النواة ذلك بتنفيذ مخزن أنبوب مؤقت كمجموعة من المؤشرات ذات العد المرجعي لصفحات ذاكرة النواة. تنشئ النواة "نسخًا" من الصفحات في مخزن مؤقت بإنشاء مؤشرات جديدة (للمخزن المؤقت الناتج) تشير إلى الصفحات، وزيادة أعداد المراجع للصفحات: تُنسخ المؤشرات فقط، وليس صفحات المخزن المؤقت.

يجب تعريف _FILE_OFFSET_BITS ليكون 64 في الكود الذي يستخدم off_in أو off_out غير فارغ أو الذي يأخذ عنوان splice، إذا كان الكود مخصصًا ليكون محمولاً إلى منصات x86 و ARM التقليدية 32 بت حيث يكون عرض off_t مبدئيًا 32 بت.

أمثلة
انظر tee(2) لمثال آخر.

    #define _GNU_SOURCE
    #define _FILE_OFFSET_BITS 64
    #include <err.h>
    #include <fcntl.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>

    int
    main(void)
    {
            int         fd;
            int         pfd[2];
            off_t       off;
            [[gnu::nonstring]]
    	const char  s[12] = "Hello, world";

            fd = open("out", O_WRONLY | O_CREAT | O_EXCL, 0666);
            if (fd == -1)
                    err(EXIT_FAILURE, "open");

            if (pipe(pfd) == -1)
                    err(EXIT_FAILURE, "pipe");

            if (write(pfd[1], s, sizeof(s)) != sizeof(s))
                    err(EXIT_FAILURE, "write");
            if (close(pfd[1]) == -1)
                    err(EXIT_FAILURE, "close");

            off = 10;
            if (splice(pfd[0], NULL, fd, &off, sizeof(s), 0) != sizeof(s))
                    err(EXIT_FAILURE, "splice");
            if (close(pfd[0]) == -1)
                    err(EXIT_FAILURE, "close");

            printf("New offset is %jd\n", (intmax_t) off);

            if (close(fd) == -1)
                    err(EXIT_FAILURE, "close");
            exit(EXIT_SUCCESS);
    }

انظر أيضًا
copy_file_range(2), sendfile(2), tee(2), vmsplice(2), pipe(7)

ترجمة
تُرجمت هذه الصفحة من الدليل بواسطة زايد السعيدي <zayed.alsaidi@gmail.com>

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 (https://www.gnu.org/licenses/gpl-3.0.html) أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

إذا وجدت أي أخطاء في ترجمة صفحة الدليل هذه، يرجى إرسال بريد إلكتروني إلى قائمة بريد المترجمين: kde-l10n-ar@kde.org.