sigaction(2)

الاسم
sigaction, rt_sigaction - فحص وتغيير إجراء الإشارة

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

موجز
#include <signal.h>

int sigaction(int signum,
              const struct sigaction *_Nullable restrict act,
              struct sigaction *_Nullable restrict oldact);

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

sigaction():
    _POSIX_C_SOURCE

siginfo_t:
    _POSIX_C_SOURCE >= 199309L

الوصف
تُستخدم استدعاء النظام sigaction() لتغيير الإجراء الذي تتخذه العملية عند استلام إشارة محددة. (انظر signal(7) للحصول على نظرة عامة على الإشارات.)

يحدد signum الإشارة ويمكن أن يكون أي إشارة صالحة باستثناء SIGKILL و SIGSTOP.

إذا كان act ليس NULL، فسيُثبت الإجراء الجديد للإشارة signum من act. إذا كان oldact ليس NULL، فسيُحفظ الإجراء السابق في oldact.

تُعرف بنية sigaction بشيء يشبه ما يلي:

    struct sigaction {
        void     (*sa_handler)(int);
        void     (*sa_sigaction)(int, siginfo_t *, void *);
        sigset_t   sa_mask;
        int        sa_flags;
        void     (*sa_restorer)(void);
    };

في بعض البنيات، تدخل "union" في الأمر: لا تعين قيمًا لكل من sa_handler و sa_sigaction معًا.

الحقل sa_restorer ليس مخصصًا لاستخدام التطبيقات. (لا تحدد POSIX حقلاً باسم sa_restorer.) يمكن العثور على بعض التفاصيل الإضافية حول الغرض من هذا الحقل في sigreturn(2).

يحدد sa_handler الإجراء المراد ربطه بـ signum ويمكن أن يكون واحدًا مما يلي:

•   SIG_DFL للإجراء المبدئي.

•   SIG_IGN لتجاهل هذه الإشارة.

•   مؤشر إلى دالة معالجة الإشارة. تستقبل هذه الدالة رقم الإشارة كمعامل وحيد لها.

إذا حُدد SA_SIGINFO في sa_flags، فإن sa_sigaction (بدلاً من sa_handler) يحدد دالة معالجة الإشارة لـ signum. تستقبل هذه الدالة ثلاثة معاملات، كما هو موضح أدناه.

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

يحدد sa_flags مجموعة من الوسوم التي تعدل سلوك الإشارة. وتُشكل عبر عملية OR بتية لصفر أو أكثر مما يلي:

SA_NOCLDSTOP
    إذا كان signum هو SIGCHLD، فلا تستقبل إشعارًا عندما تتوقف العمليات الابنة (أي عندما تتلقى إحدى الإشارات SIGSTOP أو SIGTSTP أو SIGTTIN أو SIGTTOU) أو تستأنف العمل (أي تتلقى SIGCONT) (انظر wait(2)). هذا الوسم ذو مغزى فقط عند إنشاء معالج لـ SIGCHLD.

SA_NOCLDWAIT (منذ لينكس 2.6)
    إذا كان signum هو SIGCHLD، فلا تحول الأبناء إلى زومبي (zombies) عند إنهائهم. انظر أيضًا waitpid(2). هذا الوسم ذو مغزى فقط عند إنشاء معالج لـ SIGCHLD، أو عند ضبط نزوع تلك الإشارة إلى SIG_DFL.

    إذا ضُبط الوسم SA_NOCLDWAIT عند إنشاء معالج لـ SIGCHLD، فإن POSIX.1 تترك الأمر غير محدد عما إذا كانت إشارة SIGCHLD ستُولد عند إنهاء العملية الابنة. في لينكس، تُولد إشارة SIGCHLD في هذه الحالة؛ وفي بعض التطبيقات الأخرى، لا تُولد.

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

    SA_NOMASK هو مرادف قديم وغير معياري لهذا الوسم.

SA_ONSTACK
    استدعِ معالج الإشارة على مكدس إشارات بديل يوفره sigaltstack(2). إذا لم يكن المكدس البديل متاحًا، فسيُستخدم المكدس المبدئي. هذا الوسم ذو مغزى فقط عند إنشاء معالج إشارة.

SA_RESETHAND
    استعد إجراء الإشارة إلى الإجراء المبدئي عند الدخول إلى معالج الإشارة. هذا الوسم ذو مغزى فقط عند إنشاء معالج إشارة.

    SA_ONESHOT هو مرادف قديم وغير معياري لهذا الوسم.

SA_RESTART
    وفّر سلوكًا متوافقًا مع دلالات إشارات BSD عبر جعل بعض استدعاءات النظام قابلة لإعادة التشغيل عبر الإشارات. هذا الوسم ذو مغزى فقط عند إنشاء معالج إشارة. انظر signal(7) لمناقشة حول إعادة تشغيل استدعاءات النظام.

SA_RESTORER
    ليس مخصصًا لاستخدام التطبيقات. يُستخدم هذا الوسم بواسطة مكتبات سي للإشارة إلى أن الحقل sa_restorer يحتوي على عنوان "signal trampoline". انظر sigreturn(2) لمزيد من التفاصيل.

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

SA_UNSUPPORTED (منذ لينكس 5.11)
    يُستخدم للاستقصاء الآلي عن دعم بتات الوسوم.

    إذا نجحت محاولة لتسجيل معالج مع ضبط هذا الوسم في act->sa_flags إلى جانب وسوم أخرى قد لا تدعمها النواة، وأدى استدعاء sigaction() يليه مباشرة يحدد نفس رقم الإشارة ومع معامل oldact غير صفري (non-NULL) إلى أن يكون SA_UNSUPPORTED خاليًا في oldact->sa_flags، حينها يمكن استخدام oldact->sa_flags كقناع بتات يصف أي من الوسوم التي قد تكون غير مدعومة هي في الواقع مدعومة. انظر قسم "الاستقصاء الآلي عن دعم بتات الوسوم" أدناه لمزيد من التفاصيل.

SA_EXPOSE_TAGBITS (منذ لينكس 5.11)
    عادةً، عند تسليم إشارة، تُمسح مجموعة من بتات الوسوم الخاصة بالبنية المعمارية من حقل si_addr في siginfo_t. إذا ضُبط هذا الوسم، فستُحفظ مجموعة فرعية محددة معماريًا من بتات الوسوم في si_addr.

    البرامج التي تحتاج إلى أن تكون متوافقة مع إصدارات لينكس الأقدم من 5.11 يجب أن تستخدم SA_UNSUPPORTED للاستقصاء عن الدعم.

  معامل siginfo_t لمعالج SA_SIGINFO
عندما يُحدد وسم SA_SIGINFO في act.sa_flags، يُمرر عنوان معالج الإشارة عبر حقل act.sa_sigaction. يأخذ هذا المعالج ثلاثة معاملات، كما يلي:

    void
    handler(int sig, siginfo_t *info, void *ucontext)
    {
        ...
    }

هذه المعاملات الثلاثة هي كما يلي

sig رقم الإشارة التي تسببت في استدعاء المعالج.

info
    مؤشر إلى siginfo_t، وهو بنية تحتوي على معلومات إضافية حول الإشارة، كما هو موضح أدناه.

ucontext
    هذا مؤشر إلى بنية ucontext_t، مسبوك إلى void *. تحتوي البنية التي يشير إليها هذا الحقل على معلومات سياق الإشارة التي حُفظت في مكدس مساحة المستخدم بواسطة النواة؛ لمزيد من التفاصيل، انظر sigreturn(2). يمكن العثور على مزيد من المعلومات حول بنية ucontext_t في getcontext(3) و signal(7). عادةً، لا تستخدم دالة المعالج المعامل الثالث.

نوع البيانات siginfo_t هو بنية بالحقول التالية:

    siginfo_t {
        int      si_signo;     /* رقم الإشارة */
        int      si_errno;     /* قيمة errno */
        int      si_code;      /* رمز الإشارة */
        int      si_trapno;    /* رقم المصيدة الذي سبب الإشارة
                                  المولدة عتاديًا
                                  (غير مستخدم في أغلب البنيات) */
        pid_t    si_pid;       /* معرف العملية المرسلة */
        uid_t    si_uid;       /* معرف المستخدم الحقيقي للعملية المرسلة */
        int      si_status;    /* قيمة الخروج أو الإشارة */
        clock_t  si_utime;     /* وقت المستخدم المستهلك */
        clock_t  si_stime;     /* وقت النظام المستهلك */
        union sigval si_value; /* قيمة الإشارة */
        int      si_int;       /* إشارة POSIX.1b */
        void    *si_ptr;       /* إشارة POSIX.1b */
        int      si_overrun;   /* عدد تجاوزات المؤقت؛
                                  مؤقتات POSIX.1b */
        int      si_timerid;   /* معرف المؤقت؛ مؤقتات POSIX.1b */
        void    *si_addr;      /* موقع الذاكرة الذي سبب الخطأ */
        long     si_band;      /* حدث الحزمة (كان int في
                                  glibc 2.3.2 وما قبلها) */
        int      si_fd;        /* واصف الملف */
        short    si_addr_lsb;  /* البت الأقل أهمية للعنوان
                                  (منذ لينكس 2.6.32) */
        void    *si_lower;     /* الحد الأدنى عند حدوث انتهاك العنوان
                                  (منذ لينكس 3.19) */
        void    *si_upper;     /* الحد الأعلى عند حدوث انتهاك العنوان
                                  (منذ لينكس 3.19) */
        int      si_pkey;      /* مفتاح الحماية في PTE الذي سبب
                                  الخطأ (منذ لينكس 4.6) */
        void    *si_call_addr; /* عنوان تعليمة استدعاء النظام
                                  (منذ لينكس 3.5) */
        int      si_syscall;   /* رقم استدعاء النظام المحاول
                                  (منذ لينكس 3.5) */
        unsigned int si_arch;  /* بنية استدعاء النظام المحاول
                                  (منذ لينكس 3.5) */
    }

تُعرف الحقول si_signo و si_errno و si_code لجميع الإشارات. (الحقل si_errno غير مستخدم بشكل عام في لينكس.) قد تكون بقية البنية عبارة عن "union"، لذا ينبغي قراءة الحقول ذات المعنى للإشارة المحددة فقط:

•   الإشارات المرسلة بواسطة kill(2) و sigqueue(3) تملأ si_pid و si_uid. بالإضافة إلى ذلك، تملأ الإشارات المرسلة بواسطة sigqueue(3) الحقلين si_int و si_ptr بالقيم التي يحددها مرسل الإشارة؛ انظر sigqueue(3) لمزيد من التفاصيل.

•   الإشارات المرسلة بواسطة مؤقتات POSIX.1b (منذ لينكس 2.6) تملأ si_overrun و si_timerid. حقل si_timerid هو معرف داخلي تستخدمه النواة لتحديد المؤقت؛ وهو ليس نفس معرف المؤقت الذي يعيده timer_create(2). حقل si_overrun هو عدد تجاوزات المؤقت؛ وهي نفس المعلومات التي تُحصل عليها باستدعاء timer_getoverrun(2). هذه الحقول هي امتدادات غير معيارية للينكس.

•   الإشارات المرسلة لإشعار طابور الرسائل (انظر وصف SIGEV_SIGNAL في mq_notify(3)) تملأ si_int/si_ptr بقيمة sigev_value المزودة لـ mq_notify(3)؛ وتملأ si_pid بمعرف العملية لمرسل الرسالة؛ و si_uid بمعرف المستخدم الحقيقي لمرسل الرسالة.

•   إشارة SIGCHLD تملأ الحقول si_pid و si_uid و si_status و si_utime و si_stime، موفرة معلومات حول العملية الابنة. حقل si_pid هو معرف العملية للابن؛ و si_uid هو معرف المستخدم الحقيقي للابن. يحتوي حقل si_status على حالة خروج الابن (إذا كان si_code هو CLD_EXITED)، أو رقم الإشارة التي تسببت في تغيير حالة العملية. يحتوي si_utime و si_stime على وقت CPU للمستخدم والنظام الذي استهلكته العملية الابنة؛ ولا تشمل هذه الحقول الأوقات التي استهلكها الأبناء الذين تم انتظارهم (على عكس getrusage(2) و times(2)). حتى إصدار لينكس 2.6، ومنذ إصدار لينكس 2.6.27، تبلغ هذه الحقول عن وقت CPU بوحدات sysconf(_SC_CLK_TCK). في أنوية لينكس 2.6 قبل الإصدار 2.6.27، تسبب خطأ برمي في جعل هذه الحقول تبلغ عن الوقت بوحدات "system jiffy" (القابلة للضبط) (انظر time(7)).

•   إشارات SIGILL و SIGFPE و SIGSEGV و SIGBUS و SIGTRAP تملأ si_addr بعنوان الخطأ. في بعض البنيات المعمارية، تملأ هذه الإشارات أيضًا حقل si_trapno.

    بعض الأخطاء الفرعية لـ SIGBUS، وخاصة BUS_MCEERR_AO و BUS_MCEERR_AR، تملأ أيضًا si_addr_lsb. يشير هذا الحقل إلى البت الأقل أهمية للعنوان المبلغ عنه وبالتالي مدى التلف. على سبيل المثال، إذا تفت صفحة كاملة، فسيحتوي si_addr_lsb على log2(sysconf(_SC_PAGESIZE)). عندما تُسلم SIGTRAP استجابة لحدث ptrace(2) (PTRACE_EVENT_foo)، فلا يُملأ si_addr، ولكن يُملأ si_pid و si_uid بمعرف العملية ومعرف المستخدم المسؤولين عن تسليم المصيدة. في حالة seccomp(2)، ستظهر العملية المتتبعة كأنها هي التي سلمت الحدث. BUS_MCEERR_* و si_addr_lsb هي امتدادات خاصة بلينكس.

    الخطأ الفرعي SEGV_BNDERR لـ SIGSEGV يملأ si_lower و si_upper.

    الخطأ الفرعي SEGV_PKUERR لـ SIGSEGV يملأ si_pkey.

•   إشارة SIGIO/SIGPOLL (الاسمان مترادفان في لينكس) تملأ الحقلين si_band و si_fd. حدث si_band هو قناع بتات يحتوي على نفس القيم التي يملؤها poll(2) في حقل revents. يشير حقل si_fd إلى واصف الملف الذي وقع له حدث I/O؛ لمزيد من التفاصيل، انظر وصف F_SETSIG في fcntl(2).

•   إشارة SIGSYS، التي تُولد (منذ لينكس 3.5) عندما يعيد مرشح seccomp القيمة SECCOMP_RET_TRAP، تملأ الحقول si_call_addr و si_syscall و si_arch و si_errno وحقولاً أخرى كما هو موضح في seccomp(2).

  حقل si_code
حقل si_code داخل معامل siginfo_t الذي يُمرر إلى معالج إشارة SA_SIGINFO هو قيمة (وليس قناع بتات) تشير إلى سبب إرسال هذه الإشارة. لحدث ptrace(2)، سيحتوي si_code على SIGTRAP ويكون حدث ptrace في البايت العالي:

    (SIGTRAP | PTRACE_EVENT_foo << 8).

بالنسبة للأحداث التي ليست من نوع ptrace(2)، فإن القيم التي يمكن أن تظهر في si_code موصوفة في بقية هذا القسم. منذ glibc 2.20، تُحصل على تعريفات أغلب هذه الرموز من <signal.h> عبر تعريف ماكروات اختبار الميزات (قبل تضمين أي ملف ترويسة) كما يلي:

•   _XOPEN_SOURCE بالقيمة 500 أو أكبر؛

•   _XOPEN_SOURCE و _XOPEN_SOURCE_EXTENDED؛ أو

•   _POSIX_C_SOURCE بالقيمة 200809L أو أكبر.

بالنسبة لثوابت TRAP_*، تتوفر تعريفات الرموز فقط في الحالتين الأوليين. قبل glibc 2.20، لم يكن يلزم وجود ماكروات اختبار ميزات للحصول على هذه الرموز.

لإشارة عادية، توضح القائمة التالية القيم التي يمكن وضعها في si_code لأي إشارة، مع ذكر سبب توليد الإشارة.

    SI_USER
        kill(2).

    SI_KERNEL
        أُرسلت بواسطة النواة.

    SI_QUEUE
        sigqueue(3).

    SI_TIMER
        انتهت صلاحية مؤقت POSIX، أو setitimer(2) أو alarm(2).

    SI_MESGQ (منذ لينكس 2.6.6)
        تغيرت حالة طابور رسائل POSIX؛ انظر mq_notify(3).

    SI_ASYNCIO
        اكتملت عملية AIO.

    SI_SIGIO
        صفّت SIGIO (حتى إصدار لينكس 2.2 فقط؛ بدءًا من لينكس 2.4 فصاعدًا تملأ SIGIO/SIGPOLL قيمة si_code كما هو موضح أدناه).

    SI_TKILL (منذ لينكس 2.4.19)
        tkill(2) أو tgkill(2).

    SI_ASYNCNL
        اكتمل البحث غير المتزامن عن الاسم.

يمكن وضع القيم التالية في si_code لإشارة SIGILL:

    ILL_ILLOPC
        رمز عملية غير صالح.

    ILL_ILLOPN
        معامل غير صالح.

    ILL_ILLADR
        نمط عنونة غير صالح.

    ILL_ILLTRP
        فخ غير صالح.

    ILL_PRVOPC
        رمز عملية ذو امتياز.

    ILL_PRVREG
        مسجل ذو امتياز.

    ILL_COPROC
        خطأ في المعالج المساعد.

    ILL_BADSTK
        خطأ داخلي في المكدس.

يمكن وضع القيم التالية في si_code لإشارة SIGFPE:

    FPE_INTDIV
        قسمة عدد صحيح على صفر.

    FPE_INTOVF
        طاف العدد الصحيح.

    FPE_FLTDIV
        قسمة عدد ذو فاصلة عائمة على صفر.

    FPE_FLTOVF
        طاف العدد ذو الفاصلة العائمة.

    FPE_FLTUND
        انحسر العدد ذو الفاصلة العائمة.

    FPE_FLTRES
        نتيجة غير دقيقة للعدد ذو الفاصلة العائمة.

    FPE_FLTINV
        عملية غير صالحة للعدد ذو الفاصلة العائمة.

    FPE_FLTSUB
        الدليل خارج النطاق.

    FPE_FLTUNK (منذ لينكس 4.17)
        استثناء غير مشخص في الفاصلة العائمة.

    FPE_CONDTRAP (لـ PARISC فقط)
        فخ عند تحقق شرط.

يمكن وضع القيم التالية في si_code لإشارة SIGSEGV:

    SEGV_MAPERR
        العنوان غير مربوط بكائن.

    SEGV_ACCERR
        صلاحيات غير صالحة للكائن المربوط.

    SEGV_BNDERR (منذ لينكس 3.19)
        فشلت فحوصات حدود العنوان.

    SEGV_PKUERR (منذ لينكس 4.6)
        رُفض الوصول بواسطة مفاتيح حماية الذاكرة. انظر pkeys(7). مفتاح الحماية الذي طُبق على هذا الوصول متاح عبر si_pkey.

    SEGV_ACCADI (منذ لينكس 4.17؛ لـ SPARC فقط)
        سلامة بيانات التطبيق (ADI) غير مفعلة للكائن المربوط.

    SEGV_ADIDERR (منذ لينكس 4.17؛ لـ SPARC فقط)
        خطأ في كشف تلف الذاكرة المزعج.

    SEGV_ADIPERR (منذ لينكس 4.17؛ لـ SPARC فقط)
        استثناء دقيق في كشف تلف الذاكرة.

    SEGV_MTEAERR (منذ لينكس 5.10؛ لـ ARM فقط)
        خطأ غير متزامن في ملحق وسم الذاكرة (MTE).

    SEGV_MTESERR (منذ لينكس 5.10؛ لـ ARM فقط)
        استثناء متزامن في ملحق وسم الذاكرة (MTE).

    SEGV_CPERR (منذ لينكس 6.10)
        خطأ في حماية التحكم.

يمكن وضع القيم التالية في si_code لإشارة SIGBUS:

    BUS_ADRALN
        محاذاة عنوان غير صالحة.

    BUS_ADRERR
        عنوان فيزيائي غير موجود.

    BUS_OBJERR
        خطأ عتادي خاص بالكائن.

    BUS_MCEERR_AR (منذ لينكس 2.6.32)
        استُهلك خطأ عتادي في الذاكرة عند فحص الآلة؛ الإجراء مطلوب.

    BUS_MCEERR_AO (منذ لينكس 2.6.32)
        كُشف عن خطأ عتادي في الذاكرة في العملية ولكنه لم يُستهلك؛ الإجراء اختياري.

يمكن وضع القيم التالية في si_code لإشارة SIGTRAP:

    TRAP_BRKPT
        نقطة توقف العملية.

    TRAP_TRACE
        فخ تتبع العملية.

    TRAP_BRANCH (منذ لينكس 2.4؛ لـ IA64 فقط)
        فخ تفرع العملية المتخذ.

    TRAP_HWBKPT (منذ لينكس 2.4؛ لـ IA64 فقط)
        نقطة توقف/مراقبة عتادية.

    TRAP_UNK (منذ لينكس 4.18)
        فخ غير مشخص.

    TRAP_PERF (منذ لينكس 5.13 وجليبنك 2.43)
        حدث Perf مع sigtrap=1.

يمكن وضع القيم التالية في si_code لإشارة SIGCHLD:

    CLD_EXITED
        خرجت العملية الابنة.

    CLD_KILLED
        قُتلت العملية الابنة.

    CLD_DUMPED
        أُنهيت العملية الابنة بشكل غير طبيعي.

    CLD_TRAPPED
        وقعت العملية الابنة المُتتبعة في فخ.

    CLD_STOPPED
        توقف الابن.

    CLD_CONTINUED (منذ لينكس 2.6.9)
        استمر الابن المتوقف.

يمكن وضع القيم التالية في si_code لإشارة SIGIO/SIGPOLL:

    POLL_IN
        مدخلات البيانات متاحة.

    POLL_OUT
        خبيئات المخرجات متاحة.

    POLL_MSG
        رسالة المدخلات متاحة.

    POLL_ERR
        خطأ إدخال/إخراج.

    POLL_PRI
        مدخلات عالية الأولوية متاحة.

    POLL_HUP
        فُصل الجهاز.

يمكن وضع القيم التالية في si_code لإشارة SIGSYS:

    SYS_SECCOMP (منذ لينكس 3.5 وglibc 2.43)
        أُطلق بواسطة قاعدة مرشح seccomp(2).

    SYS_USER_DISPATCH (منذ لينكس 5.11 وglibc 2.43)
        أُطلق إرسال مستخدم استدعاء النظام (Syscall user dispatch).

يمكن وضع القيمة التالية في si_code لإشارة SIGEMT:

    EMT_TAGOVF (SPARC فقط)
        طفح الوسم.

  سبر دعم بتات الأعلام ديناميكيًا
يقبل استدعاء sigaction() في لينكس تعيين بتات غير معروفة في act->sa_flags دون خطأ. سلوك النواة بدءًا من لينكس 5.11 هو أن استدعاء sigaction() ثانٍ سيمسح البتات غير المعروفة من oldact->sa_flags. ومع ذلك، تاريخيًا، كان استدعاء sigaction() ثانٍ يترك تلك البتات معينة في oldact->sa_flags عادةً.

هذا يعني أن دعم الأعلام الجديدة لا يمكن كشفه ببساطة عبر اختبار علم في sa_flags، ويجب على البرنامج اختبار مسح SA_UNSUPPORTED قبل الاعتماد على محتويات sa_flags.

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

في النوى التي لا تدعم علمًا محددًا، يكون سلوك النواة كما لو أن العلم لم يُعين، حتى لو عُين العلم في act->sa_flags.

الأعلام SA_NOCLDSTOP وSA_NOCLDWAIT وSA_SIGINFO وSA_ONSTACK وSA_RESTART وSA_NODEFER وSA_RESETHAND، وإذا كانت معرّفة بواسطة البنية، SA_RESTORER، قد لا تُسبر بشكل موثوق باستخدام هذه الآلية، لأنها قُدمت قبل لينكس 5.11. ومع ذلك، وبشكل عام، قد تفترض البرامج أن هذه الأعلام مدعومة، بما أنها دُعمت جميعًا منذ لينكس 2.6، الذي أُصدر في عام 2003.

انظر قسم الأمثلة أدناه للحصول على عرض توضيحي لاستخدام SA_UNSUPPORTED.

قيمة الإرجاع
يعيد sigaction() القيمة 0 عند النجاح؛ وعند الخطأ، يُعاد -1، ويُضبط errno للإشارة إلى الخطأ.

الأخطاء

EFAULT
    يشير act أو oldact إلى ذاكرة ليست جزءًا صالحًا من مساحة عناوين العملية.

EINVAL
    حُددت إشارة غير صالحة. سيُولد هذا أيضًا إذا أُجريت محاولة لتغيير الإجراء الخاص بـ SIGKILL أو SIGSTOP، واللذين لا يمكن صيدهما أو تجاهلهما.

الإصدارات

  الاختلافات بين مكتبة C والنواة
تعطي دالة تغليف glibc لـ sigaction() خطأ (EINVAL) عند محاولات تغيير ترتيب إشارتي الزمن الحقيقي المستخدمتين داخليًا بواسطة تنفيذ خيوط NPTL. راجع nptl(7) للتفاصيل.

في البنيات التي يقع فيها ترامبولين الإشارة (signal trampoline) في مكتبة C، تضع دالة تغليف glibc لـ sigaction() عنوان كود الترامبولين في حقل act.sa_restorer وتعين العلم SA_RESTORER في حقل act.sa_flags. راجع sigreturn(2).

سُمي استدعاء نظام لينكس الأصلي sigaction(). ومع ذلك، مع إضافة إشارات الزمن الحقيقي في لينكس 2.2، لم يعد نوع sigset_t ثابت الحجم (32 بت) الذي يدعمه استدعاء النظام ذاك مناسبًا للغرض. وبناءً عليه، أُضيف استدعاء نظام جديد، rt_sigaction()، لدعم نوع sigset_t الموسع. يأخذ استدعاء النظام الجديد وسيطًا رابعًا، size_t sigsetsize، والذي يحدد الحجم بالبايت لمجموعات الإشارات في act.sa_mask وoldact.sa_mask. يُطلب حاليًا أن تكون قيمة هذا الوسيط sizeof(sigset_t) (وإلا سينتج الخطأ EINVAL). تخفي دالة تغليف sigaction() في glibc هذه التفاصيل عنا، وتستدعي rt_sigaction() بشفافية عندما توفره النواة.

المعايير
POSIX.1-2024.

التاريخ
POSIX.1-2001، SVr4.

منع معيار POSIX.1-1990 ضبط إجراء SIGCHLD على SIG_IGN. سمح POSIX.1-2001 وما بعده بهذا الاحتمال، بحيث يمكن استخدام تجاهل SIGCHLD لمنع إنشاء العمليات الزومبي (انظر wait(2)). ومع ذلك، تختلف سلوكيات BSD و System V التاريخية فيما يخص تجاهل SIGCHLD، لذا فإن الطريقة الوحيدة المحمولة تمامًا لضمان عدم تحول الأبناء المنتهين إلى زومبي هي صيد إشارة SIGCHLD وتنفيذ wait(2) أو ما شابه.

حدد POSIX.1-1990 العلم SA_NOCLDSTOP فقط. أضاف POSIX.1-2001 الأعلام SA_NOCLDWAIT وSA_NODEFER وSA_ONSTACK وSA_RESETHAND وSA_RESTART وSA_SIGINFO كملحقات XSI. نقل POSIX.1-2008 الأعلام SA_NODEFER وSA_RESETHAND وSA_RESTART وSA_SIGINFO إلى المواصفات الأساسية. قد يكون استخدام هذه القيم الأخيرة في sa_flags أقل قابلية للنقل في التطبيقات الموجهة لتنفيذات يونكس القديمة.

العلم SA_RESETHAND متوافق مع علم SVr4 الذي يحمل الاسم نفسه.

العلم SA_NODEFER متوافق مع علم SVr4 الذي يحمل الاسم نفسه في النوى 1.3.9 وما بعدها. في النوى الأقدم، سمح تنفيذ لينكس باستلام أي إشارة، وليس فقط تلك التي نثبتها (مما يتجاوز فعليًا أي إعدادات لـ sa_mask).

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

وفقًا لـ POSIX، يكون سلوك العملية غير محدد بعد تجاهلها لإشارة SIGFPE أو SIGILL أو SIGSEGV التي لم تُنتج بواسطة kill(2) أو raise(3). قسمة الأعداد الصحيحة على صفر لها نتيجة غير محددة. في بعض البنيات ستنتج إشارة SIGFPE. (كما أن قسمة أصغر عدد صحيح سالب على -1 قد تنتج SIGFPE). تجاهل هذه الإشارة قد يؤدي إلى حلقة مفرغة.

يمكن استدعاء sigaction() مع وسيط ثانٍ NULL للاستعلام عن معالج الإشارة الحالي. يمكن استخدامه أيضًا للتحقق مما إذا كانت إشارة معينة صالحة للآلة الحالية عبر استدعائه مع وسيطين ثانٍ وثالث قيمتهما NULL.

لا يمكن حجب SIGKILL أو SIGSTOP (عن طريق تحديدهما في sa_mask). تُتجاهل محاولات القيام بذلك بصمت.

انظر sigsetops(3) للحصول على تفاصيل حول معالجة مجموعات الإشارات.

انظر signal-safety(7) للحصول على قائمة بالدوال الآمنة للإشارات غير المتزامنة (async-signal-safe) التي يمكن استدعاؤها بأمان من داخل معالج الإشارة.

يضمن معيار POSIX فقط SI_TIMER للإشارات التي أُنشئت بواسطة timer_create(2). التنفيذات حرة في توفيرها أيضًا لأنواع أخرى من الموقتات. سلوك لينكس يطابق NetBSD.

  غير موثق
قبل تقديم SA_SIGINFO، كان من الممكن أيضًا الحصول على بعض المعلومات الإضافية حول الإشارة. نُفذ ذلك عبر توفير معالج إشارة sa_handler مع وسيط ثانٍ من النوع struct sigcontext، وهو نفس الهيكل الذي يُمرر في حقل uc_mcontext لهيكل ucontext الذي يُمرر (عبر مؤشر) في الوسيط الثالث لمعالج sa_sigaction. انظر مصادر نواة لينكس ذات الصلة للتفاصيل. هذا الاستخدام مهجور الآن.

العلل
عند إيصال إشارة ناتجة عن استثناء عتادي مع معالج SA_SIGINFO، لا توفر النواة دائمًا قيمًا ذات معنى لجميع حقول siginfo_t ذات الصلة بتلك الإشارة. على سبيل المثال، عندما تُستدعى تعليمات x86 int مع وسيط محظور (أي رقم غير 3 أو 128)، تُوصل إشارة SIGSEGV، ولكن حقول siginfo_t الممررة لمعالج الإشارة تكون جميعها مضبوطة على الصفر باستثناء si_signo وsi_code، حتى لو كان ينبغي ضبط حقول أخرى (على سبيل المثال، يجب أن يكون si_addr غير صفري لجميع إشارات SIGSEGV).

حتى لينكس 2.6.13 (بما في ذلك هذا الإصدار)، كان تحديد SA_NODEFER في sa_flags يمنع ليس فقط حجب الإشارة الموصلة أثناء تنفيذ المعالج، ولكن أيضًا الإشارات المحددة في sa_mask. أُصلحت هذه العلة في لينكس 2.6.14.

أمثلة
انظر mprotect(2).

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

    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>

    static void
    handler(int signo, siginfo_t *info, void *context)
    {
        struct sigaction oldact;

        if (sigaction(SIGSEGV, NULL, &oldact) == -1
            || (oldact.sa_flags & SA_UNSUPPORTED)
            || !(oldact.sa_flags & SA_EXPOSE_TAGBITS))
        {
            _exit(EXIT_FAILURE);
        }
        _exit(EXIT_SUCCESS);
    }

    int
    main(void)
    {
        struct sigaction act = { 0 };

        act.sa_flags = SA_SIGINFO | SA_UNSUPPORTED | SA_EXPOSE_TAGBITS;
        act.sa_sigaction = &handler;
        if (sigaction(SIGSEGV, &act, NULL) == -1) {
            perror("sigaction");
            exit(EXIT_FAILURE);
        }

        raise(SIGSEGV);
    }

انظر أيضًا
kill(1)، kill(2)، pause(2)، pidfd_send_signal(2)، restart_syscall(2)، seccomp(2)، sigaltstack(2)، signal(2)، signalfd(2)، sigpending(2)، sigprocmask(2)، sigreturn(2)، sigsuspend(2)، wait(2)، killpg(3)، raise(3)، siginterrupt(3)، sigqueue(3)، sigsetops(3)، sigvec(3)، core(5)، signal(7)

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

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

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