signal(7)

الاسم
إشارة - نظرة عامة على الإشارات

الوصف
يدعم لينكس كلاً من إشارات POSIX الموثوقة (يُشار إليها فيما يلي باسم "الإشارات القياسية") وإشارات POSIX للوقت الحقيقي.

  ترتيبات الإشارة
لكل إشارة ترتيب (disposition) حالي، يحدد كيفية سلوك العملية عند تسلمها لتلك الإشارة.

تحدد المدخلات في عمود "الإجراء" (Action) في الجدول أدناه الترتيب الافتراضي لكل إشارة، كما يلي:

إنهاء (Term)
    الإجراء الافتراضي هو إنهاء العملية.

تجاهل (Ign)
    الإجراء الافتراضي هو تجاهل الإشارة.

لب (Core)
    الإجراء الافتراضي هو إنهاء العملية وتفريغ اللب (انظر core(5)).

إيقاف (Stop)
    الإجراء الافتراضي هو إيقاف العملية.

متابعة (Cont)
    الإجراء المبدئي هو متابعة تنفيذ العملية إذا كانت متوقفة حالياً.

تستطيع العملية تغيير ترتيب الإشارة باستخدام sigaction(2) أو signal(2). (يعد الأخير أقل قابلية للنقل عند إنشاء معالج إشارة؛ راجع signal(2) للتفاصيل.) باستخدام استدعاءات النظام هذه، يمكن للعملية اختيار أحد السلوكيات التالية عند تسليم الإشارة: تنفيذ الإجراء المبدئي؛ أو تجاهل الإشارة؛ أو التقاط الإشارة بواسطة معالج إشارة، وهي دالة يحددها المبرمج تُستدعى آلياً عند تسليم الإشارة.

مبدئياً، يُستدعى معالج الإشارة في مكدس العملية العادي. من الممكن الترتيب بحيث يستخدم معالج الإشارة مكدساً بديلاً؛ راجع sigaltstack(2) لمناقشة كيفية القيام بذلك ومتى قد يكون مفيداً.

ترتيب الإشارة هو سمة خاصة بالعملية: في التطبيقات متعددة الخيوط، يكون ترتيب إشارة معينة هو نفسه لجميع الخيوط.

يرث الابن الذي تم إنشاؤه عبر fork(2) نسخة من ترتيبات إشارات والده. أثناء عملية execve(2)، يتم إعادة ضبط ترتيبات الإشارات التي يتم التعامل معها إلى الوضع الافتراضي؛ بينما تظل ترتيبات الإشارات المتجاهلة دون تغيير.

  إرسال إشارة
تسمح استدعاءات النظام ودوال المكتبة التالية للمستدعي بإرسال إشارة:

raise(3)
    يرسل إشارة إلى خيط الاستدعاء.

kill(2)
    يرسل إشارة إلى عملية محددة، أو إلى جميع أعضاء مجموعة عمليات محددة، أو إلى جميع العمليات في النظام.

pidfd_send_signal(2)
    يُرسل إشارة إلى عملية محددة بواسطة واصف ملف PID.

killpg(3)
    يُرسل إشارة إلى جميع أعضاء مجموعة عمليات محددة.

pthread_kill(3)
    يُرسل إشارة إلى خيط POSIX محدد في نفس عملية المستدعِي.

tgkill(2)
    يُرسل إشارة إلى خيط محدد داخل عملية معينة. (هذا هو استدعاء النظام المستخدم لتنفيذ pthread_kill(3).)

sigqueue(3)
    يُرسل إشارة وقت حقيقي مع بيانات مرفقة إلى عملية محددة.

  انتظار التقاط إشارة
تقوم استدعاءات النظام التالية بتعليق تنفيذ خيط الاستدعاء حتى يتم التقاط إشارة (أو حتى تقوم إشارة غير معالجة بإنهاء العملية):

pause(2)
    يعلق التنفيذ حتى يتم التقاط أي إشارة.

sigsuspend(2)
    يُغيّر قناع الإشارة مؤقتاً (انظر أدناه) ويُعلّق التنفيذ حتى تُلقط إحدى الإشارات غير المقنعة.

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

•   تُعلّق sigwaitinfo(2) و sigtimedwait(2) و sigwait(3) التنفيذ حتى تُسلّم إحدى الإشارات في مجموعة محددة. يعيد كل من هذه الاستدعاءات معلومات حول الإشارة المُسلّمة.

•   تعيد signalfd(2) واصف ملف يمكن استخدامه لقراءة معلومات حول الإشارات التي تُسلّم إلى المستدعِي. تحظر كل عملية read(2) من واصف الملف هذا التنفيذ حتى تُسلّم إحدى الإشارات في المجموعة المحددة في استدعاء signalfd(2) إلى المستدعِي. تحتوي الخبيئة التي تعيدها read(2) على هيكل يصف الإشارة.

  قناع الإشارة والإشارات المعلقة
قد تكون الإشارة محجوبة، وهذا يعني أنها لن تُسلّم حتى يتم إلغاء حجبها لاحقاً. يُقال عن الإشارة أنها معلقة في الفترة ما بين وقت توليدها ووقت تسليمها.

لكل خيط في العملية قناع إشارة مستقل، يحدد مجموعة الإشارات التي يحجبها الخيط حالياً. يمكن للخيط التحكم في قناع إشارته باستخدام pthread_sigmask(3). في التطبيقات التقليدية أحادية الخيوط، يمكن استخدام sigprocmask(2) للتحكم في قناع الإشارة.

يرث الابن المنشأ عبر fork(2) نسخة من قناع إشارات والده؛ ويتم الحفاظ على قناع الإشارات عبر عملية execve(2).

قد تكون الإشارة موجهة للعملية أو موجهة للخيط. الإشارة الموجهة للعملية هي تلك التي تستهدف العملية ككل (وبالتالي تكون معلقة لها). قد تكون الإشارة موجهة للعملية لأنها وُلدت بواسطة النواة لأسباب أخرى غير استثناءات العتاد، أو لأنها أُرسلت باستخدام kill(2) أو sigqueue(3). أما الإشارة الموجهة للخيط فهي التي تستهدف خيطاً معيناً. قد تكون الإشارة موجهة للخيط لأنها وُلدت نتيجة لتنفيذ تعليمات معينة بلغة الآلة أدت إلى إطلاق استثناء عتادي (مثل SIGSEGV للوصول غير الصالح للذاكرة، أو SIGFPE لخطأ رياضي)، أو لأنها استهدفت خيطاً محدداً باستخدام واجهات مثل tgkill(2) أو pthread_kill(3).

يمكن تسليم الإشارة الموجهة للعملية إلى أي خيط من الخيوط التي لا تحجب تلك الإشارة حالياً. إذا كان هناك أكثر من خيط لا يحجب الإشارة، تختار النواة خيطاً عشوائياً لتسليم الإشارة إليه.

يمكن للخيط الحصول على مجموعة الإشارات المعلقة لديه حالياً باستخدام sigpending(2). تتكون هذه المجموعة من اتحاد مجموعة الإشارات المعلقة الموجهة للعملية ومجموعة الإشارات المعلقة الموجهة لخيط الاستدعاء نفسه.

يكون لدى الابن المنشأ عبر fork(2) في البداية مجموعة إشارات معلقة فارغة؛ ويتم الحفاظ على مجموعة الإشارات المعلقة عبر عملية execve(2).

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

(1) تقوم النواة بالخطوات التحضيرية اللازمة لتنفيذ معالج الإشارة:

    (1.1)
        تُزال الإشارة من مجموعة الإشارات المعلقة.

    (1.2)
        إذا تم تثبيت معالج الإشارة عبر استدعاء sigaction(2) مع تحديد علم SA_ONSTACK وكان الخيط قد عرّف مكدساً بديلاً للإشارة (باستخدام sigaltstack(2))، فسيتم تثبيت ذلك المكدس.

    (1.3)
        يتم حفظ أجزاء مختلفة من السياق المتعلق بالإشارة في إطار خاص يتم إنشاؤه على المكدس. تتضمن المعلومات المحفوظة ما يلي:

        •   سجل عداد البرنامج (أي عنوان التعليمات التالية في البرنامج الرئيسي التي يجب تنفيذها عند عودة معالج الإشارة)؛

        •   حالة السجلات الخاصة بالمعمارية والمطلوبة لاستئناف البرنامج المقاطع؛

        •   قناع الإشارة الحالي للخيط؛

        •   إعدادات مكدس الإشارة البديل للخيط.

        إذا ثُبت معالج الإشارة باستخدام الراية SA_SIGINFO لـ sigaction(2)، فستكون المعلومات المذكورة أعلاه متاحة عبر كائن ucontext_t الذي يشير إليه المعامل الثالث لمعالج الإشارة. يعكس هذا الكائن الحالة التي أُرسلت عندها الإشارة، بدلاً من الحالة داخل المعالج؛ على سبيل المثال، لن يحتوي قناع الإشارات المحجوبة المخزن في هذا الكائن على قناع الإشارات الجديدة المحجوبة عبر sigaction(2).

    (1.4)
        تُضاف أي إشارات محددة في act->sa_mask عند تسجيل المعالج باستخدام sigaction(2) إلى قناع إشارة الخيط. كما تُضاف الإشارة التي يتم تسليمها حالياً إلى قناع الإشارة أيضاً، ما لم يتم تحديد SA_NODEFER عند تسجيل المعالج. وبالتالي تُحجب هذه الإشارات أثناء تنفيذ المعالج.

(2) تبني النواة إطاراً لمعالج الإشارة على المكدس. وتضبط عداد البرنامج للخيط ليشير إلى أول تعليمات دالة معالج الإشارة، وتعد عنوان العودة لتلك الدالة ليشير إلى جزء من كود وضع المستخدم يُعرف باسم "ترامبولين الإشارة" (موصوف في sigreturn(2)).

(3) تُعيد النواة التحكم إلى مساحة المستخدم، حيث يبدأ التنفيذ عند بداية دالة معالج الإشارة.

(4) عندما تعود دالة معالج الإشارة، ينتقل التحكم إلى كود الـ trampoline الخاص بالإشارة.

(5) يستدعي ترامبولين الإشارة sigreturn(2)، وهو استدعاء نظام يستخدم المعلومات الموجودة في إطار المكدس الذي أُنشئ في الخطوة 1 لاستعادة حالة الخيط كما كانت قبل استدعاء معالج الإشارة. يتم استعادة قناع إشارة الخيط وإعدادات مكدس الإشارة البديل كجزء من هذا الإجراء. عند اكتمال استدعاء sigreturn(2)، تعيد النواة التحكم إلى وضع المستخدم، ويستأنف الخيط تنفيذه من النقطة التي توقف عندها.

لاحظ أنه إذا لم يعد معالج الإشارة (على سبيل المثال، نُقل التحكم خارج المعالج باستخدام siglongjmp(3)، أو نفذ المعالج برنامجاً جديداً باستخدام execve(2))، فلن تُنفذ الخطوة النهائية. وبشكل خاص، تقع في مثل هذه السيناريوهات على عاتق المبرمج مسؤولية استعادة حالة قناع الإشارة (باستخدام sigprocmask(2))، إذا كان المطلوب إلغاء حجب الإشارات التي حُجبت عند الدخول إلى معالج الإشارة. (لاحظ أن siglongjmp(3) قد يستعيد قناع الإشارة أو لا يستعيده، اعتماداً على قيمة savesigs التي حُددت في استدعاء sigsetjmp(3) المقابل).

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

  الإشارات القياسية
يدعم لينكس الإشارات القياسية المدرجة أدناه. يشير العمود الثاني من الجدول إلى المعيار الذي حدد الإشارة (إن وجد): "P1990" تشير إلى أن الإشارة موصوفة في معيار POSIX.1-1990 الأصلي؛ و "P2001" تشير إلى أن الإشارة أُضيفت أو تغير تعريفها في SUSv2 و POSIX.1-2001. أما "P2024" فتشير إلى أن الإشارة أُضيفت أو تغير تعريفها في POSIX.1-2024.
الإشارة | المعيار | الإجراء | التعليق
SIGABRT | P1990 | لب (Core) | إشارة الإجهاض من abort(3)
SIGALRM | P1990 | إنهاء (Term) | إشارة الموقت من alarm(2)
SIGBUS | P2001 | لب (Core) | خطأ ناقل (وصول خاطئ للذاكرة)
SIGCHLD | P2001 | تجاهل (Ign) | توقف الطفل أو أُنهي أو استمر
SIGCLD | - | تجاهل (Ign) | مرادف لـ SIGCHLD
SIGCONT | P1990 | متابعة (Cont) | واصِل إذا كانت العملية متوقفة
SIGEMT | - | إنهاء (Term) | مصيدة محاكي
SIGFPE | P1990 | لب (Core) | عملية حسابية خاطئة
SIGHUP | P1990 | إنهاء (Term) | كُشف عن تعليق في الطرفية المتحكمة
 |  |  | أو موت العملية المتحكمة
SIGILL | P1990 | لب (Core) | تعليمة غير صالحة
SIGINFO | - |  | مرادف لـ SIGPWR
SIGINT | P1990 | إنهاء (Term) | مقاطعة من لوحة المفاتيح
SIGIO | - | إنهاء (Term) | الإدخال/الإخراج متاح الآن (4.2BSD)
SIGIOT | - | لب (Core) | مصيدة IOT. مرادف لـ SIGABRT
SIGKILL | P1990 | إنهاء (Term) | إشارة قتل
SIGLOST | - | إنهاء (Term) | فُقد قفل الملف (غير مستخدم)
SIGPIPE | P1990 | إنهاء (Term) | أنبوب مكسور: كتابة إلى أنبوب بدون
 |  |  | قراء؛ انظر pipe(7)
SIGPOLL | P2001 | إنهاء (Term) | حدث قابل للاستطلاع (Sys V)؛
 |  |  | مرادف لـ SIGIO
SIGPROF | P2001 | إنهاء (Term) | انتهى وقت مؤقت التشكيلة
SIGPWR | - | إنهاء (Term) | فشل الطاقة (System V)
SIGQUIT | P1990 | لب (Core) | إنهاء من لوحة المفاتيح
SIGSEGV | P1990 | لب (Core) | إشارة ذاكرة غير صالحة
SIGSTKFLT | - | إنهاء (Term) | خطأ في المكدس على المعالج المساعد (غير مستخدم)
SIGSTOP | P1990 | إيقاف (Stop) | أوقِف العملية
SIGTSTP | P1990 | إيقاف (Stop) | إيقاف مكتوب عند الطرفية
SIGSYS | P2001 | لب (Core) | استدعاء نظام سيئ (SVr4)؛
 |  |  | انظر أيضاً seccomp(2)
SIGTERM | P1990 | إنهاء (Term) | إشارة إنهاء
SIGTRAP | P2001 | لب (Core) | مصيدة تتبع/نقطة توقف
SIGTTIN | P1990 | إيقاف (Stop) | دخل طرفية لعملية خلفية
SIGTTOU | P1990 | إيقاف (Stop) | خرج طرفية لعملية خلفية
SIGUNUSED | - | لب (Core) | مرادف لـ SIGSYS
SIGURG | P2001 | تجاهل (Ign) | حالة عاجلة على المقبس (4.2BSD)
SIGUSR1 | P1990 | إنهاء (Term) | إشارة معرفة من المستخدم 1
SIGUSR2 | P1990 | إنهاء (Term) | إشارة معرفة من المستخدم 2
SIGVTALRM | P2001 | إنهاء (Term) | ساعة منبه افتراضية (4.2BSD)
SIGXCPU | P2001 | لب (Core) | تجاوز حد وقت المعالج (4.2BSD)؛
 |  |  | انظر setrlimit(2)
SIGXFSZ | P2001 | لب (Core) | تجاوز حد حجم الملف (4.2BSD)؛
 |  |  | انظر setrlimit(2)
SIGWINCH | P2024 | تجاهل (Ign) | إشارة تغيير حجم النافذة (4.3BSD, Sun)

لا يمكن التقاط الإشارتين SIGKILL و SIGSTOP، أو حجبهما، أو تجاهلهما.

حتى الإصدار 2.2 من لينكس وما قبله، كان السلوك المبدئي للإشارات SIGSYS و SIGXCPU و SIGXFSZ، و SIGBUS (على معماريات غير SPARC و MIPS) هو إنهاء العملية (بدون تفريغ الذاكرة core dump). (في بعض أنظمة يونكس الأخرى، الإجراء المبدئي لـ SIGXCPU و SIGXFSZ هو إنهاء العملية بدون تفريغ الذاكرة). يمتثل لينكس 2.4 لمتطلبات POSIX.1-2001 لهذه الإشارات، حيث ينهي العملية مع تفريغ الذاكرة.

لم تُحدد SIGEMT في POSIX.1-2001، ومع ذلك تظهر في معظم أنظمة يونكس الأخرى، حيث يكون إجراؤها المبدئي عادةً هو إنهاء العملية مع تفريغ الذاكرة.

عادةً ما تُتجاهل SIGPWR (التي لم تُحدد في POSIX.1-2001) مبدئياً في أنظمة UNIX الأخرى التي تظهر فيها.

تُتجاهل SIGIO (التي لم تُحدد في POSIX.1-2001) مبدئياً في عدة أنظمة UNIX أخرى.

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

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

  ترقيم الإشارات للإشارات القياسية
تُعطى القيمة العددية لكل إشارة في الجدول أدناه. كما هو موضح في الجدول، تمتلك العديد من الإشارات قيمًا عددية مختلفة في معماريات مختلفة. توضح القيمة العددية الأولى في كل صف من الجدول رقم الإشارة على x86 و ARM ومعظم المعماريات الأخرى؛ والقيمة الثانية لـ Alpha و SPARC؛ والثالثة لـ MIPS؛ والأخيرة لـ PARISC. تشير الشرطة (-) إلى أن الإشارة غائبة في المعمارية المقابلة.
الإشارة | x86/ARM | Alpha/ | MIPS | PARISC | ملاحظات
 | معظم الأنظمة الأخرى | SPARC
SIGHUP | 1 | 1 | 1 | 1
SIGINT | 2 | 2 | 2 | 2
SIGQUIT | 3 | 3 | 3 | 3
SIGILL | 4 | 4 | 4 | 4
SIGTRAP | 5 | 5 | 5 | 5
SIGABRT | 6 | 6 | 6 | 6
SIGIOT | 6 | 6 | 6 | 6
SIGBUS | 7 | 10 | 10 | 10
SIGEMT | - | 7 | 7 | -
SIGFPE | 8 | 8 | 8 | 8
SIGKILL | 9 | 9 | 9 | 9
SIGUSR1 | 10 | 30 | 16 | 16
SIGSEGV | 11 | 11 | 11 | 11
SIGUSR2 | 12 | 31 | 17 | 17
SIGPIPE | 13 | 13 | 13 | 13
SIGALRM | 14 | 14 | 14 | 14
SIGTERM | 15 | 15 | 15 | 15
SIGSTKFLT | 16 | - | - | 7
SIGCHLD | 17 | 20 | 18 | 18
SIGCLD | - | - | 18 | -
SIGCONT | 18 | 19 | 25 | 26
SIGSTOP | 19 | 17 | 23 | 24
SIGTSTP | 20 | 18 | 24 | 25
SIGTTIN | 21 | 21 | 26 | 27
SIGTTOU | 22 | 22 | 27 | 28
SIGURG | 23 | 16 | 21 | 29
SIGXCPU | 24 | 24 | 30 | 12
SIGXFSZ | 25 | 25 | 31 | 30
SIGVTALRM | 26 | 26 | 28 | 20
SIGPROF | 27 | 27 | 29 | 21
SIGWINCH | 28 | 28 | 20 | 23
SIGIO | 29 | 23 | 22 | 22
SIGPOLL |  |  |  |  | نفس SIGIO
SIGPWR | 30 | 29/- | 19 | 19
SIGINFO | - | 29/- | - | -
SIGLOST | - | -/29 | - | -
SIGSYS | 31 | 12 | 12 | 31
SIGUNUSED | 31 | - | - | 31

لاحظ ما يلي:

•   حيثما عُرفت، تكون SIGUNUSED مرادفة لـ SIGSYS. منذ الإصدار 2.26 من glibc، لم تعد SIGUNUSED معرفة في أي معمارية.

•   الإشارة 29 هي SIGINFO/SIGPWR (مرادفان لنفس القيمة) في Alpha ولكنها SIGLOST في SPARC.

  إشارات الوقت الحقيقي
بدءاً من لينكس 2.2، يدعم لينكس إشارات الوقت الحقيقي كما عُرفت في الأصل في ملحقات الوقت الحقيقي لـ POSIX.1b (والمضمنة الآن في POSIX.1-2001). يُحدد نطاق إشارات الوقت الحقيقي المدعومة بواسطة وحدات الماكرو SIGRTMIN و SIGRTMAX. يتطلب POSIX.1-2001 أن يدعم التنفيذ ما لا يقل عن _POSIX_RTSIG_MAX (8) من إشارات الوقت الحقيقي.

تدعم نواة لينكس نطاقاً من 33 إشارة وقت حقيقي مختلفة، مرقمة من 32 إلى 64. ومع ذلك، يستخدم تنفيذ خيوط glibc POSIX داخلياً إشارتي وقت حقيقي (لـ NPTL) أو ثلاث إشارات (لـ LinuxThreads) (انظر pthreads(7))، ويعدل قيمة SIGRTMIN بشكل مناسب (إلى 34 أو 35). ونظراً لأن نطاق إشارات الوقت الحقيقي المتاحة يختلف وفقاً لتنفيذ خيوط glibc (ويمكن أن يحدث هذا الاختلاف في وقت التشغيل وفقاً للنواة و glibc المتاحين)، وفي الواقع يختلف نطاق إشارات الوقت الحقيقي عبر أنظمة يونكس، فيجب على البرامج ألا تشير أبداً إلى إشارات الوقت الحقيقي باستخدام أرقام ثابتة، وبدلاً من ذلك يجب دائماً الإشارة إليها باستخدام الصيغة SIGRTMIN+n، وتضمين فحوصات مناسبة (في وقت التشغيل) للتأكد من أن SIGRTMIN+n لا يتجاوز SIGRTMAX.

خلافاً للإشارات القياسية، لا تملك إشارات الوقت الحقيقي معانٍ محددة مسبقاً: إذ يمكن استخدام كامل مجموعة إشارات الوقت الحقيقي لأغراض يحددها التطبيق.

الإجراء المبدئي لإشارة وقت حقيقي غير معالجة هو إنهاء العملية المستلمة.

تتميز إشارات الوقت الحقيقي بما يلي:

•   يمكن جدولة مثيلات متعددة من إشارات الوقت الحقيقي في طابور. وبالمقابل، إذا سُلمت مثيلات متعددة من إشارة قياسية بينما كانت تلك الإشارة محجوبة حالياً، فسيُجدول مثيل واحد فقط في الطابور.

•   إذا أُرسلت الإشارة باستخدام sigqueue(3)، فيمكن إرسال قيمة مصاحبة (إما عدد صحيح أو مؤشر) مع الإشارة. إذا أنشأت العملية المستلمة معالجاً لهذه الإشارة باستخدام الراية SA_SIGINFO لـ sigaction(2)، فيمكنها الحصول على هذه البيانات عبر حقل si_value في بنية siginfo_t الممرة كمعامل ثانٍ للمعالج. علاوة على ذلك، يمكن استخدام حقول si_pid و si_uid في هذه البنية للحصول على معرف العملية (PID) ومعرف المستخدم الحقيقي للعملية المرسلة للإشارة.

•   تُسلم إشارات الوقت الحقيقي بترتيب مضمون. إذ تُسلم مثيلات متعددة من إشارات الوقت الحقيقي من النوع نفسه بنفس ترتيب إرسالها. وإذا أُرسلت إشارات وقت حقيقي مختلفة إلى عملية ما، فتُسلم بدءاً من الإشارة ذات الرقم الأدنى. (أي أن الإشارات ذات الأرقام الدنيا لها الأولوية القصوى). وبالمقابل، إذا كانت هناك إشارات قياسية متعددة معلقة لعملية ما، فإن ترتيب تسليمها غير محدد.

إذا كانت كل من الإشارات القياسية وإشارات الوقت الحقيقي معلقة لعملية ما، فإن POSIX يترك الأمر غير محدد بشأن أيهما يُسلم أولاً. يعطي لينكس، مثل العديد من التنفيذات الأخرى، الأولوية للإشارات القياسية في هذه الحالة.

وفقاً لـ POSIX، يجب أن يسمح التنفيذ بوضع ما لا يقل عن _POSIX_SIGQUEUE_MAX (32) من إشارات الوقت الحقيقي في طابور لعملية ما. ومع ذلك، فإن لينكس يفعل ذلك بشكل مختلف. حتى الإصدار 2.6.7 من لينكس وما قبله، يفرض لينكس حداً على مستوى النظام لعدد إشارات الوقت الحقيقي المجدولة لجميع العمليات. يمكن عرض هذا الحد وتغييره (بامتيازات) عبر ملف /proc/sys/kernel/rtsig-max. ويمكن استخدام ملف ذي صلة، وهو /proc/sys/kernel/rtsig-nr، لمعرفة عدد إشارات الوقت الحقيقي المجدولة حالياً. في لينكس 2.6.8، استُبدلت واجهات /proc هذه بحد المورد RLIMIT_SIGPENDING، الذي يحدد حداً لكل مستخدم للإشارات المجدولة؛ انظر setrlimit(2) لمزيد من التفاصيل.

تطلبت إضافة إشارات الوقت الحقيقي توسيع بنية مجموعة الإشارات (sigset_t) من 32 إلى 64 بت. ونتيجة لذلك، استُبدلت استدعاءات نظام مختلفة باستدعاءات نظام جديدة تدعم مجموعات الإشارات الأكبر. استدعاءات النظام القديمة والجديدة هي كما يلي:
لينكس 2.0 وما قبله | لينكس 2.2 وما بعده
sigaction(2) | rt_sigaction(2)
sigpending(2) | rt_sigpending(2)
sigprocmask(2) | rt_sigprocmask(2)
sigreturn(2) | rt_sigreturn(2)
sigsuspend(2) | rt_sigsuspend(2)
sigtimedwait(2) | rt_sigtimedwait(2)

  مقاطعة استدعاءات النظام ودوال المكتبات بواسطة معالجات الإشارة
إذا استُدعي معالج إشارة بينما كان استدعاء نظام أو استدعاء دالة مكتبة محجوباً، فإما:

•   يُعاد تشغيل الاستدعاء آلياً بعد عودة معالج الإشارة؛ أو

•   يفشل الاستدعاء مع الخطأ EINTR.

يعتمد أي من هذين السلوكين سيحدث على الواجهة وما إذا كان قد أُنشئ معالج الإشارة باستخدام الراية SA_RESTART أم لا (انظر sigaction(2)). تختلف التفاصيل عبر أنظمة يونكس؛ وفيما يلي التفاصيل الخاصة بلينكس.

إذا قوطع استدعاء محجوب لإحدى الواجهات التالية بواسطة معالج إشارة، فسيُعاد تشغيل الاستدعاء آلياً بعد عودة معالج الإشارة إذا استُخدمت الراية SA_RESTART؛ وإلا فإن الاستدعاء يفشل مع الخطأ EINTR:

•   استدعاءات read(2) و readv(2) و write(2) و writev(2) و ioctl(2) على الأجهزة "البطيئة". الجهاز "البطيء" هو الجهاز الذي قد يُحجب فيه استدعاء الإدخال/الإخراج لوقت غير محدد، مثل الطرفية أو الأنبوب أو المقبس. إذا كان استدعاء إدخال/إخراج على جهاز بطيء قد نقل بالفعل بعض البيانات بحلول الوقت الذي قوطع فيه بواسطة معالج إشارة، فسيعود الاستدعاء بحالة نجاح (عادةً، عدد البايتات المنقولة). لاحظ أن القرص (المحلي) ليس جهازاً بطيئاً وفقاً لهذا التعريف؛ فعمليات الإدخال/الإخراج على أجهزة الأقراص لا تقاطعها الإشارات.

•   open(2)، إذا كان من الممكن حجبه (على سبيل المثال، عند فتح FIFO؛ انظر fifo(7)).

•   wait(2) و wait3(2) و wait4(2) و waitid(2) و waitpid(2).

•   واجهات المقبس: accept(2) و connect(2) و recv(2) و recvfrom(2) و recvmmsg(2) و recvmsg(2) و send(2) و sendto(2) و sendmsg(2)، ما لم يُضبط مهلة على المقبس (انظر أدناه).

•   واجهات قفل الملفات: flock(2) وعمليات F_SETLKW و F_OFD_SETLKW لـ fcntl(2)

•   واجهات طابور رسائل POSIX: ‏mq_receive(3) و mq_timedreceive(3) و mq_send(3) و mq_timedsend(3).

•   futex(2) FUTEX_WAIT (منذ لينكس 2.6.22؛ قبل ذلك، كان يفشل دائماً مع EINTR).

•   getrandom(2).

•   futex(2) FUTEX_WAIT_BITSET.

•   واجهات إشارات POSIX: ‏sem_wait(3) و sem_timedwait(3) (منذ لينكس 2.6.22؛ قبل ذلك، كانت تفشل دائماً مع EINTR).

•   read(2) من واصف ملف inotify(7) (منذ لينكس 3.8؛ قبل ذلك، كان يفشل دائماً مع EINTR).

لا تُستأنف الواجهات التالية أبداً بعد مقاطعتها بواسطة معالج إشارة، بغض النظر عن استخدام SA_RESTART؛ فهي تفشل دائماً مع الخطأ EINTR عندما يقاطعها معالج إشارة:

•   واجهات مقابس "الإدخال"، عندما تُضبط مهلة (SO_RCVTIMEO) على المقبس باستخدام setsockopt(2): accept(2) و recv(2) و recvfrom(2) و recvmmsg(2) (أيضاً مع معامل timeout غير صفري)، و recvmsg(2).

•   واجهات مقابس "الإخراج"، عندما تُضبط مهلة (SO_RCVTIMEO) على المقبس باستخدام setsockopt(2): connect(2) و send(2) و sendto(2) و sendmsg(2).

•   الواجهات المستخدمة لانتظار الإشارات: pause(2) و sigsuspend(2) و sigtimedwait(2) و sigwaitinfo(2).

•   واجهات مضاعفة واصف الملفات: epoll_wait(2) و epoll_pwait(2) و poll(2) و ppoll(2) و select(2) و pselect(2).

•   واجهات System V IPC: ‏msgrcv(2) و msgsnd(2) و semop(2) و semtimedop(2).

•   واجهات النوم: clock_nanosleep(2) و nanosleep(2) و usleep(3).

•   io_getevents(2).

لا تُستأنف دالة sleep(3) أبداً إذا قوطعت بواسطة معالج، ولكنها تعود بنجاح مع القيمة: عدد الثواني المتبقية للنوم.

في ظروف معينة، يمكن أن تؤدي ميزة إشعار مساحة المستخدم لـ seccomp(2) إلى إعادة تشغيل استدعاءات النظام التي لا تُستأنف عادةً بواسطة SA_RESTART؛ لمزيد من التفاصيل، انظر seccomp_unotify(2).

  مقاطعة استدعاءات النظام ودوال المكتبات بواسطة إشارات التوقف
في لينكس، حتى في غياب معالجات الإشارة، يمكن أن تفشل واجهات حجب معينة مع الخطأ EINTR بعد توقف العملية بواسطة إحدى إشارات التوقف ثم استئنافها عبر SIGCONT. هذا السلوك غير معتمد في POSIX.1، ولا يحدث في الأنظمة الأخرى.

واجهات لينكس التي تظهر هذا السلوك هي:

•   واجهات مقابس "الإدخال"، عندما تُضبط مهلة (SO_RCVTIMEO) على المقبس باستخدام setsockopt(2): accept(2) و recv(2) و recvfrom(2) و recvmmsg(2) (أيضاً مع معامل timeout غير صفري)، و recvmsg(2).

•   واجهات مقابس "الإخراج"، عندما تُضبط مهلة (SO_RCVTIMEO) على المقبس باستخدام setsockopt(2): connect(2) و send(2) و sendto(2) و sendmsg(2)، إذا ضُبطت مهلة إرسال (SO_SNDTIMEO).

•   epoll_wait(2) و epoll_pwait(2).

•   semop(2) و semtimedop(2).

•   sigtimedwait(2) و sigwaitinfo(2).

•   لينكس 3.7 وما قبله: read(2) من واصف ملف inotify(7)

•   لينكس 2.6.21 وما قبله: futex(2) FUTEX_WAIT و sem_timedwait(3) و sem_wait(3).

•   لينكس 2.6.8 وما قبله: msgrcv(2) و msgsnd(2).

•   لينكس 2.4 وما قبله: nanosleep(2).

المعايير
POSIX.1، ما لم يذكر خلاف ذلك.

ملاحظات
لمناقشة الدوال الآمنة للإشارات غير المتزامنة، انظر signal-safety(7).

يحتوي الملف /proc/pid/task/tid/status على حقول متنوعة توضح الإشارات التي يحجبها الخيط (SigBlk)، أو يلتقطها (SigCgt)، أو يتجاهلها (SigIgn). (مجموعة الإشارات التي تُلتقط أو تُتجاهل ستكون هي نفسها عبر جميع خيوط العملية). تُظهر حقول أخرى مجموعة الإشارات المعلقة الموجهة إلى الخيط (SigPnd) بالإضافة إلى مجموعة الإشارات المعلقة الموجهة إلى العملية ككل (ShdPnd). تُظهر الحقول المقابلة في /proc/pid/status المعلومات الخاصة بالخيط الرئيس. انظر proc(5) لمزيد من التفاصيل.

العلل
هناك ست إشارات يمكن إرسالها كنتيجة لاستثناء عتادي: SIGBUS و SIGEMT و SIGFPE و SIGILL و SIGSEGV و SIGTRAP. أي من هذه الإشارات يُسلم، لأي استثناء عتادي معين، ليس موثقاً ولا يبدو منطقياً دائماً.

على سبيل المثال، قد يؤدي الوصول غير الصالح للذاكرة الذي يتسبب في إرسال SIGSEGV في معمارية معالج واحدة إلى إرسال SIGBUS في معمارية أخرى، أو العكس.

ولمثال آخر، يؤدي استخدام تعليمة x86 int مع معامل ممنوع (أي رقم غير 3 أو 128) إلى إرسال SIGSEGV، على الرغم من أن SIGILL سيكون أكثر منطقية، وذلك بسبب كيفية إبلاغ المعالج عن العملية الممنوعة للنواة.

انظر أيضًا
kill(1), clone(2), getrlimit(2), kill(2), pidfd_send_signal(2), restart_syscall(2), rt_sigqueueinfo(2), setitimer(2), setrlimit(2), sgetmask(2), sigaction(2), sigaltstack(2), signal(2), signalfd(2), sigpending(2), sigprocmask(2), sigreturn(2), sigsuspend(2), sigwaitinfo(2), abort(3), bsd_signal(3), killpg(3), longjmp(3), pthread_sigqueue(3), raise(3), sigqueue(3), sigset(3), sigsetops(3), sigvec(3), sigwait(3), strsignal(3), swapcontext(3), sysv_signal(3), core(5), proc(5), nptl(7), pthreads(7), sigevent(3type)

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

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

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