setjmp(3)

الاسم
setjmp, sigsetjmp, longjmp, siglongjmp - تنفيذ قفزة غير محلية

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

موجز
#include <setjmp.h>

int setjmp(jmp_buf env);
int sigsetjmp(sigjmp_buf env, int savesigs);

[[noreturn]] void longjmp(jmp_buf env, int val);
[[noreturn]] void siglongjmp(sigjmp_buf env, int val);

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

setjmp(): انظر التاريخ.

sigsetjmp():
    _POSIX_C_SOURCE

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

تحفظ الدالة setjmp() معلومات متنوعة عن بيئة الاستدعاء (عادةً، مؤشر المكدس، مؤشر التعليمات، وربما قيم سجلات أخرى وقناع الإشارة) في المخزن المؤقت env لاستخدامها لاحقًا بواسطة longjmp(). في هذه الحالة، تُرجع setjmp() 0.

تستخدم الدالة longjmp() المعلومات المحفوظة في env لإعادة التحكم إلى النقطة التي استُدعيت فيها setjmp() واستعادة ("إرجاع") المكدس إلى حالته وقت استدعاء setjmp(). بالإضافة إلى ذلك، واعتمادًا على التنفيذ (انظر الملاحظات والتاريخ)، قد تُستعاد قيم بعض السجلات الأخرى وقناع إشارة العملية إلى حالتها وقت استدعاء setjmp().

بعد longjmp() ناجحة، يستمر التنفيذ كما لو أن setjmp() قد عادت مرة ثانية. يمكن تمييز هذا الإرجاع "المزيف" عن استدعاء setjmp() حقيقي لأن الإرجاع "المزيف" يُرجع القيمة المقدمة في val. إذا مرر المبرمج القيمة 0 في val عن طريق الخطأ، فسيرجع الإرجاع "المزيف" 1 بدلاً من ذلك.

  sigsetjmp() و siglongjmp()
تنفذ sigsetjmp() و siglongjmp() أيضًا قفزات غير محلية، لكنها توفر معالجة متوقعة لقناع إشارة العملية.

إذا وفقط إذا كانت قيمة المعامل savesigs المقدم إلى sigsetjmp() غير صفرية، يُحفظ قناع الإشارة الحالي للعملية في env وسيُستعاد إذا نُفذت siglongjmp() لاحقًا باستخدام هذا env.

قيمة الإرجاع
تُرجع setjmp() و sigsetjmp() 0 عند استدعائهما مباشرة؛ عند الإرجاع "المزيف" الذي يحدث بعد longjmp() أو siglongjmp()، تُرجع القيمة غير الصفرية المحددة في val.

لا تُرجع الدالتان longjmp() أو siglongjmp() أي قيمة.

السمات
للاطلاع على شرح للمصطلحات المستخدمة في هذا القسم، انظر attributes(7).
الواجهة | السمة | القيمة
setjmp()، sigsetjmp() | سلامة الخيوط | MT-Safe
longjmp()، siglongjmp() | سلامة الخيوط | MT-Safe

المعايير

setjmp()
longjmp()
    C11, POSIX.1-2008.

sigsetjmp()
siglongjmp()
    POSIX.1-2008.

التاريخ

setjmp()
longjmp()
    POSIX.1-2001، C89.

sigsetjmp()
siglongjmp()
    POSIX.1-2001.

لا يُحدد POSIX ما إذا كانت setjmp() ستحفظ قناع الإشارة (لاستعادته لاحقًا أثناء longjmp()). في System V لن تفعل. في 4.3BSD ستفعل، وهناك دالة _setjmp() لن تفعل. يعتمد السلوك تحت Linux على إصدار glibc وإعداد وحدات اختبار الميزات. قبل glibc 2.19، تتبع setjmp() سلوك System V مبدئيًا، ولكن يُوفر سلوك BSD إذا تم تعريف وحدة اختبار الميزات _BSD_SOURCE صراحةً ولم يتم تعريف أي من _POSIX_SOURCE أو _POSIX_C_SOURCE أو _XOPEN_SOURCE أو _GNU_SOURCE أو _SVID_SOURCE. منذ glibc 2.19، يُظهر <setjmp.h> فقط إصدار System V من setjmp(). يجب على البرامج التي تحتاج دلالات BSD استبدال استدعاءات setjmp() باستدعاءات sigsetjmp() مع معامل savesigs غير صفري.

ملاحظات
يمكن أن تكون setjmp() و longjmp() مفيدة للتعامل مع الأخطاء داخل استدعاءات دوال متداخلة بعمق أو للسماح لمعالج إشارة بتمرير التحكم إلى نقطة محددة في البرنامج، بدلاً من العودة إلى النقطة التي قاطع فيها المعالج البرنامج الرئيس. في الحالة الأخيرة، إذا أردت حفظ واستعادة أقنعة الإشارة بشكل محمول، استخدم sigsetjmp() و siglongjmp(). انظر أيضًا مناقشة قابلية قراءة البرنامج أدناه.

تحذيرات
قد يُحسّن المترجم المتغيرات إلى سجلات، وقد تستعيد longjmp() قيم سجلات أخرى بالإضافة إلى مؤشر المكدس وعداد البرنامج. وبالتالي، تكون قيم المتغيرات التلقائية غير محددة بعد استدعاء longjmp() إذا استوفت جميع المعايير التالية:

•   هي محلية للدالة التي أجرت استدعاء setjmp() المقابل؛

•   تتغير قيمها بين استدعاءات setjmp() و longjmp()؛ و

•   لم تُصرّح على أنها volatile.

تنطبق ملاحظات مماثلة على siglongjmp().

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

مما يزيد الصعوبة، قد لا تكون استدعاءات setjmp() و longjmp() حتى في نفس وحدة الكود المصدري.

باختصار، يمكن للقفزات غير المحلية أن تجعل البرامج أصعب في الفهم والصيانة، ويجب استخدام بديل إذا أمكن.

  سلوك غير محدد
إذا عادت الدالة التي استدعت setjmp() قبل استدعاء longjmp()، يكون السلوك غير محدد. من المؤكد أن ينتج نوع من الفوضى الخفية أو الواضحة.

إذا، في برنامج متعدد الخيوط، استخدم استدعاء longjmp() مخزن env مؤقتًا تمت تهيئته بواسطة استدعاء setjmp() في خيط مختلف، يكون السلوك غير محدد.

يضيف التصحيح التقني POSIX.1-2008 رقم 2 longjmp() و siglongjmp() إلى قائمة الدوال الآمنة للإشارات غير المتزامنة. ومع ذلك، يوصي المعيار بتجنب استخدام هذه الدوال من معالجات الإشارات ويستمر في الإشارة إلى أنه إذا تم استدعاء هذه الدوال من معالج إشارة قاطع استدعاءًا لدالة غير آمنة للإشارات غير المتزامنة (أو ما يعادله، مثل الخطوات المكافئة لـ exit(3) التي تحدث عند العودة من الاستدعاء الأولي لـ main())، يكون السلوك غير محدد إذا أجرى البرنامج لاحقًا استدعاءًا لدالة غير آمنة للإشارات غير المتزامنة. الطريقة الوحيدة لتجنب السلوك غير المحدد هي ضمان أحد ما يلي:

•   بعد القفز الطويل من معالج الإشارة، لا يستدعي البرنامج أي دوال غير آمنة للإشارات غير المتزامنة ولا يعود من الاستدعاء الأولي لـ main().

•   يجب حظر أي إشارة يقوم معالجها بقفزة طويلة أثناء كل استدعاء لدالة غير آمنة للإشارات غير المتزامنة ولا تُستدعى دوال غير آمنة للإشارات غير المتزامنة بعد العودة من الاستدعاء الأولي لـ main().

انظر أيضًا
signal(7), signal-safety(7)

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

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

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