readv(2)

الاسم
readv, writev, preadv, pwritev, preadv2, pwritev2 - قراءة أو كتابة بيانات في مخازن متعددة

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

موجز
#include <sys/uio.h>

ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);

ssize_t preadv(int fd, const struct iovec *iov, int iovcnt,
                off_t offset);
ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt,
                off_t offset);

ssize_t preadv2(int fd, const struct iovec *iov, int iovcnt,
                off_t offset, int flags);
ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt,
                off_t offset, int flags);

    متطلبات ماكروات اختبار الميزات لـ glibc (انظر feature_test_macros(7)):

preadv(), pwritev():
    منذ glibc 2.19:
        _DEFAULT_SOURCE
    glibc 2.19 وما قبله:
        _BSD_SOURCE

الوصف
استدعاء النظام readv() يقرأ iovcnt مخزنا من الملف المرتبط بوصف الملف fd إلى المخازن الموصوفة بواسطة iov ("إدخال مبعثر").

استدعاء النظام writev() يكتب iovcnt مخزنا من البيانات الموصوفة بواسطة iov إلى الملف المرتبط بوصف الملف fd ("إخراج مجمع").

المؤشر iov يشير إلى مصفوفة من بنى iovec، الموصوفة في iovec(3type).

استدعاء النظام readv() يعمل تماما مثل read(2) باستثناء أن مخازن متعددة تُملأ.

استدعاء النظام writev() يعمل تماما مثل write(2) باستثناء أن مخازن متعددة تُكتب.

تُعالج المخازن بترتيب المصفوفة. هذا يعني أن readv() يملأ iov[0] بالكامل قبل الانتقال إلى iov[1]، وهكذا. (إذا كانت البيانات غير كافية، فقد لا تُملأ جميع المخازن المشار إليها بواسطة iov.) وبالمثل، writev() يكتب المحتوى الكامل لـ iov[0] قبل الانتقال إلى iov[1]، وهكذا.

نقل البيانات الذي ينفذه readv() و writev() هو ذري: البيانات التي يكتبها writev() تُكتب ككتلة واحدة لا تختلط بمخرجات من عمليات كتابة في عمليات أخرى؛ وبالمثل، readv() مضمون لقراءة كتلة متجاورة من البيانات من الملف، بغض النظر عن عمليات القراءة المنفذة في خيوط أو عمليات أخرى لها واصفات ملفات تشير إلى نفس وصف الملف المفتوح (انظر open(2)).

  preadv() و pwritev()
استدعاء النظام preadv() يجمع وظائف readv() و pread(2). ينفذ نفس مهمة readv()، لكنه يضيف وسيطة رابعة، offset، التي تحدد إزاحة الملف التي ستنفذ عندها عملية الإدخال.

استدعاء النظام pwritev() يجمع وظائف writev() و pwrite(2). ينفذ نفس مهمة writev()، لكنه يضيف وسيطة رابعة، offset، التي تحدد إزاحة الملف التي ستنفذ عندها عملية الإخراج.

إزاحة الملف لا تتغير بواسطة استدعاءات النظام هذه. الملف المشار إليه بواسطة fd يجب أن يكون قادرا على البحث.

  preadv2() و pwritev2()
استدعاءات النظام هذه مشابهة لاستدعاءات preadv() و pwritev()، لكنها تضيف وسيطة خامسة، flags، التي تعدل السلوك على أساس كل استدعاء.

على عكس preadv() و pwritev()، إذا كانت وسيطة offset هي -1، فإن إزاحة الملف الحالية تُستخدم وتُحدث.

وسيطة flags تحتوي على OR بتوي لصفر أو أكثر من الأعلام التالية:

RWF_DSYNC (منذ Linux 4.7)
    يوفر مكافئا لكل كتابة لعلم O_DSYNC في open(2). هذا العلم ذو معنى فقط لـ pwritev2()، وتأثيره ينطبق فقط على نطاق البيانات الذي يكتبه استدعاء النظام.

RWF_HIPRI (منذ Linux 4.6)
    قراءة/كتابة ذات أولوية عالية. يسمح لأنظمة الملفات القائمة على الكتل باستخدام استقصاء الجهاز، مما يوفر زمن وصول أقل، لكنه قد يستخدم موارد إضافية. (حاليا، هذه الميزة قابلة للاستخدام فقط على واصف ملف مفتوح باستخدام علم O_DIRECT.)

RWF_SYNC (منذ Linux 4.7)
    يوفر مكافئا لكل كتابة لعلم O_SYNC في open(2). هذا العلم ذو معنى فقط لـ pwritev2()، وتأثيره ينطبق فقط على نطاق البيانات الذي يكتبه استدعاء النظام.

RWF_NOWAIT (منذ لينكس 4.14)
    لا تنتظر البيانات غير المتاحة فورا. إذا تم تحديد هذا العلم، فإن استدعاء النظام preadv2() سيعود فورا إذا كان سيضطر لقراءة بيانات من التخزين الخلفي أو انتظار قفل. إذا تمت قراءة بعض البيانات بنجاح، فسيعيد عدد البايتات المقروءة. إذا لم تُقرأ أي بايتات، فسيعيد -1 ويضبط errno على EAGAIN (لكن انظر BUGS). حاليا، هذا العلم ذو معنى فقط لـ preadv2().

RWF_APPEND (منذ لينكس 4.16)
    يوفر مكافئا لكل كتابة لعلم O_APPEND في open(2). هذا العلم ذو معنى فقط لـ pwritev2()، وتأثيره ينطبق فقط على نطاق البيانات الذي يكتبه استدعاء النظام. وسيطة offset لا تؤثر على عملية الكتابة؛ البيانات تُلحق دائما بنهاية الملف. مع ذلك، إذا كانت وسيطة offset هي -1، فإن إزاحة الملف الحالية تُحدث.

RWF_NOAPPEND (منذ لينكس 6.9)
    لا تلتزم بعلم O_APPEND في open(2). هذا العلم ذو معنى فقط لـ pwritev2(). تاريخيا، التزم Linux بعلم O_APPEND إذا تم ضبطه وتجاهل وسيطة الإزاحة، وهو خطأ. بالنسبة لـ pwritev2()، وسيطة offset تُلتزم بها كما هو متوقع إذا تم ضبط علم RWF_NOAPPEND، تماما كما لو أن علم O_APPEND لم يُضبط.

RWF_ATOMIC (منذ لينكس 6.11)
    يتطلب أن تُصدر عمليات الكتابة إلى الملفات العادية في أنظمة الملفات القائمة على الكتل مع حماية ضد الكتابة الممزقة. تعني حماية الكتابة الممزقة أنه في حالة انقطاع التيار الكهربائي أو أي عطل آخر في الأجهزة، سيتم تخزين جميع البيانات من عملية الكتابة أو لا شيء منها، ولكن لا يتم أبدًا خلط البيانات القديمة والجديدة. هذه العلامة ذات معنى فقط لـ pwritev2()، وتأثيرها ينطبق فقط على نطاق البيانات الذي كتبته استدعاء النظام. يجب أن يكون إجمالي طول الكتابة قوة للعدد 2 وأن يكون بحجم في النطاق [stx_atomic_write_unit_min, stx_atomic_write_unit_max]. يجب أن تكون الكتابة عند إزاحة محاذاة طبيعيًا داخل الملف بالنسبة لإجمالي طول الكتابة. على سبيل المثال، يُسمح بكتابة بطول 32KiB عند إزاحة ملف 32KiB، ومع ذلك لا يُسمح بكتابة بطول 32KiB عند إزاحة ملف 48KiB. الحد الأعلى لـ iovcnt لـ pwritev2() يُعطى بالقيمة في stx_atomic_write_segments_max. تعمل حماية الكتابة الممزقة فقط مع علامة O_DIRECT، أي أن عمليات الكتابة المخزنة غير مدعومة. لضمان الاتساق من الكتابة بين حالة الملف في الذاكرة الأساسية وجهاز التخزين، يجب تحديد O_SYNC أو O_DSYNC لـ open(2). يتم توفير نفس ضمانات الإدخال/الإخراج المتزامنة كما هو موصوف في open(2) عند استخدام هذه العلامات أو علاماتها المكافئة واستدعاءات النظام (على سبيل المثال، إذا تم تحديد RWF_SYNC لـ pwritev2()).

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

    بالإضافة إلى ذلك، سيتم بدء أي نطاق تم توسيخه بواسطة عملية كتابة مع تعيين RWF_DONTCACHE للكتابة الخلفية. هذا مشابه لاستدعاء sync_file_range(2) مع SYNC_FILE_RANGE_WRITE لبدء الكتابة الخلفية على النطاق المحدد. RWF_DONTCACHE هو تلميح، أو أفضل جهد، حيث لا يتم تقديم ضمانات صارمة على حالة خبيئة الصفحات بمجرد اكتمال العملية.

    إذا تم استخدامه على نظام ملفات أو جهاز كتلة لا يدعمه، فسيعيد -1، وسيتم تعيين errno إلى EOPNOTSUPP.

قيمة الإرجاع
عند النجاح، تعيد readv() و preadv() و preadv2() عدد البايتات المقروءة؛ تعيد writev() و pwritev() و pwritev2() عدد البايتات المكتوبة.

لاحظ أنه ليس خطأً إذا قامت مكالمة ناجحة بنقل بايتات أقل مما هو مطلوب (راجع read(2) و write(2)).

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

الأخطاء
الأخطاء هي كما هو معطى لـ read(2) و write(2). علاوة على ذلك، يمكن أن تفشل preadv() و preadv2() و pwritev() و pwritev2() أيضًا لنفس أسباب lseek(2). بالإضافة إلى ذلك، يتم تعريف الأخطاء التالية:

EINVAL
    مجموع قيم iov_len يفيض قيمة ssize_t.

EINVAL
    إذا تم تحديد RWF_ATOMIC، فإن مجموعة مجموع قيم iov_len وقيمة offset لا تتوافق مع قواعد حماية الكتابة الممزقة للطول والإزاحة.

EINVAL
    عدد المتجهات، iovcnt، أقل من الصفر أو أكبر من الحد الأقصى المسموح به. إذا تم تحديد RWF_ATOMIC، فإن هذا الحد الأقصى يُعطى بقيمة stx_atomic_write_segments_max من statx.

EOPNOTSUPP
    تم تعيين RWF_DONTCACHE في flags والملف لا يدعمه.

EOPNOTSUPP
    تم تحديد علامة غير معروفة في flags.

الإصدارات

  الاختلافات بين مكتبة C والنواة
استدعاءات النظام الخام preadv() و pwritev() لها تواقيع استدعاء تختلف قليلاً عن تلك الخاصة بوظائف الغلاف لمكتبة سي لجنو الموضحة في الملخص. الوسيطة الأخيرة، offset، يتم فكها بواسطة وظائف الغلاف إلى وسيطتين في استدعاءات النظام:

unsigned long pos_l, unsigned long pos

تحتوي هذه الوسيطات، على التوالي، على البتات 32 ذات الترتيب المنخفض والبتات 32 ذات الترتيب العالي من offset.

المعايير

readv()
writev()
    POSIX.1-2024.

preadv()
pwritev()
    BSD.

preadv2()
pwritev2()
    لينكس.

التاريخ

readv()
writev()
    POSIX.1-2001،‏ 4.4BSD (ظهر أولاً في 4.2BSD).

preadv()
pwritev()
    لينكس 2.6.30، glibc 2.10.

preadv2()
pwritev2()
    لينكس 4.6، glibc 2.26.

  الاختلافات التاريخية بين مكتبة سي والنواة
للتعامل مع حقيقة أن IOV_MAX كان منخفضًا جدًا في الإصدارات المبكرة من لينكس، قامت وظائف الغلاف لـ glibc لـ readv() و writev() ببعض العمل الإضافي إذا اكتشفت أن استدعاء النظام الأساسي فشل بسبب تجاوز هذا الحد. في حالة readv()، قامت وظيفة الغلاف بتخصيص مخزن مؤقت مؤقت كبير بما يكفي لجميع العناصر المحددة بواسطة iov، ومررت هذا المخزن في استدعاء لـ read(2)، ونسخت البيانات من المخزن إلى المواقع المحددة بواسطة حقول iov_base لعناصر iov، ثم حررت المخزن. قامت وظيفة الغلاف لـ writev() بتنفيذ المهمة المماثلة باستخدام مخزن مؤقت مؤقت واستدعاء لـ write(2).

اختفت الحاجة إلى هذا الجهد الإضافي في وظائف الغلاف لـ glibc مع لينكس 2.2 والإصدارات الأحدث. ومع ذلك، استمرت glibc في توفير هذا السلوك حتى glibc 2.10. بدءًا من glibc 2.9، توفر وظائف الغلاف هذا السلوك فقط إذا اكتشفت المكتبة أن النظام يعمل بنواة لينكس أقدم من لينكس 2.6.18 (إصدار نواة تم اختياره بشكل تعسفي). ومنذ glibc 2.20 (التي تتطلب حدًا أدنى من لينكس 2.6.32)، تقوم وظائف الغلاف لـ glibc دائمًا باستدعاء استدعاءات النظام مباشرة.

ملاحظات
يسمح POSIX.1 للتنفيذ بوضع حد على عدد العناصر التي يمكن تمريرها في iov. يمكن للتنفيذ الإعلان عن حده عن طريق تعريف IOV_MAX في <limits.h> أو في وقت التشغيل عبر القيمة المعادة من sysconf(_SC_IOV_MAX). في أنظمة لينكس الحديثة، الحد هو 1024. في أيام لينكس 2.0، كان هذا الحد 16.

العلل
لينكس 5.9 ولينكس 5.10 بهما خطأ حيث قد تعيد preadv2() مع علامة RWF_NOWAIT القيمة 0 حتى عندما لا تكون في نهاية الملف.

أمثلة
يوضح نموذج الكود التالي استخدام writev():

    char          *str0 = "hello ";
    char          *str1 = "world\n";
    ssize_t       nwritten;
    struct iovec  iov[2];

    iov[0].iov_base = str0;
    iov[0].iov_len = strlen(str0);
    iov[1].iov_base = str1;
    iov[1].iov_len = strlen(str1);

    nwritten = writev(STDOUT_FILENO, iov, 2);

انظر أيضًا
pread(2)، read(2)، write(2)

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

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

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