timer_create(2)

الاسم
timer_create - إنشاء مؤقت POSIX لكل عملية

المكتبة
مكتبة الوقت الحقيقي (librt، -lrt)

موجز
#include <signal.h>           /* تعريف ثوابت SIGEV_* */
#include <time.h>

int timer_create(clockid_t clockid,
                 struct sigevent *_Nullable restrict sevp,
                 timer_t *restrict timerid);

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

timer_create():
    _POSIX_C_SOURCE >= 199309L

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

تحدد الوسيطة clockid الساعة التي يستخدمها المؤقت الجديد لقياس الوقت. يمكن تحديدها كأحد القيم التالية:

CLOCK_REALTIME
    ساعة وقت حقيقي قابلة للضبط على مستوى النظام.

CLOCK_MONOTONIC
    ساعة تزايدية رتيبة غير قابلة للضبط تقيس الوقت من نقطة غير محددة في الماضي لا تتغير بعد بدء تشغيل النظام.

CLOCK_PROCESS_CPUTIME_ID (منذ لينكس 2.6.12)
    ساعة تقيس وقت وحدة المعالجة المركزية (المستخدم والنظام) المستهلك بواسطة (جميع الخيوط في) العملية المستدعية.

CLOCK_THREAD_CPUTIME_ID (منذ لينكس 2.6.12)
    ساعة تقيس وقت وحدة المعالجة المركزية (المستخدم والنظام) المستهلك بواسطة الخيط المستدعي.

CLOCK_BOOTTIME (منذ لينكس 2.6.39)
    مثل CLOCK_MONOTONIC، هذه ساعة تتزايد برتابة. ومع ذلك، فبينما لا تقيس ساعة CLOCK_MONOTONIC الوقت أثناء تعليق النظام، فإن ساعة CLOCK_BOOTTIME تشمل الوقت الذي يكون فيه النظام معلقاً. هذا مفيد للتطبيقات التي تحتاج أن تكون مدركة للتعليق. ساعة CLOCK_REALTIME ليست مناسبة لمثل هذه التطبيقات، لأن تلك الساعة تتأثر بالتغيرات غير المستمرة في ساعة النظام.

CLOCK_REALTIME_ALARM (منذ لينكس 3.0)
    هذه الساعة تشبه CLOCK_REALTIME، لكنها ستوقظ النظام إذا كان معلقًا. يجب أن يتمتع المستدعِي بصلاحية CAP_WAKE_ALARM لضبط مؤقت لهذه الساعة.

CLOCK_BOOTTIME_ALARM (منذ لينكس 3.0)
    هذه الساعة تشبه CLOCK_BOOTTIME، لكنها ستوقظ النظام إذا كان معلقًا. يجب أن يتمتع المستدعِي بصلاحية CAP_WAKE_ALARM لضبط مؤقت لهذه الساعة.

CLOCK_TAI (منذ لينكس 3.10)
    ساعة على مستوى النظام مشتقة من وقت الساعة الجدارية ولكنها تحسب الثواني الكبيسة.

انظر clock_getres(2) لمزيد من التفاصيل حول الساعات المذكورة أعلاه.

بالإضافة إلى القيم أعلاه، يمكن تحديد clockid كـ clockid المُعاد بواسطة استدعاء clock_getcpuclockid(3) أو pthread_getcpuclockid(3).

تشير الوسيطة sevp إلى بنية sigevent تحدد كيف ينبغي إعلام المستدعي عند انتهاء المؤقت. للتعريف والتفاصيل العامة لهذه البنية، انظر sigevent(3type).

يمكن أن يأخذ الحقل sevp.sigev_notify القيم التالية:

SIGEV_NONE
    لا تُعلم بشكل غير متزامن عند انتهاء المؤقت. يمكن مراقبة تقدم المؤقت باستخدام timer_gettime(2).

SIGEV_SIGNAL
    عند انتهاء المؤقت، يُولد الإشارة sigev_signo للعملية. انظر sigevent(3type) للتفاصيل العامة. سيُضبط الحقل si_code من بنية siginfo_t إلى SI_TIMER. في أي نقطة زمنية، يُصطف إشارة واحدة على الأكثر للعملية لمؤقت معين؛ انظر timer_getoverrun(2) لمزيد من التفاصيل.

SIGEV_THREAD
    عند انتهاء المؤقت، يُستدعى sigev_notify_function كما لو كانت دالة بدء خيط جديد. انظر sigevent(3type) للتفاصيل.

SIGEV_THREAD_ID (خاص بلينكس)
    كما في SIGEV_SIGNAL، لكن الإشارة موجهة إلى الخيط الذي يُعطى معرفه في sigev_notify_thread_id، والذي يجب أن يكون خيطًا في نفس العملية مثل المستدعي. يحدد الحقل sigev_notify_thread_id معرف خيط النواة، أي القيمة المُعادة بواسطة clone(2) أو gettid(2). هذه العلامة مخصصة للاستخدام فقط من قبل مكتبات الخيوط.

تحديد sevp كـ NULL يعادل تحديد مؤشر لبنية sigevent حيث sigev_notify هو SIGEV_SIGNAL، وsigev_signo هو SIGALRM، وsigev_value.sival_int هو معرف المؤقت.

قيمة الإرجاع
عند النجاح، تُعيد timer_create() 0، ويُوضع معرف المؤقت الجديد في *timerid. عند الفشل، تُعيد -1، ويُضبط errno للإشارة إلى الخطأ.

الأخطاء

EAGAIN
    خطأ مؤقت أثناء تخصيص النواة لبنى المؤقت.

EINVAL
    معرف الساعة، أو sigev_notify، أو sigev_signo، أو sigev_notify_thread_id غير صالح.

ENOMEM
    تعذر تخصيص الذاكرة.

ENOTSUP
    لا تدعم النواة إنشاء مؤقت مقابل clockid هذا.

EPERM
    كان clockid هو CLOCK_REALTIME_ALARM أو CLOCK_BOOTTIME_ALARM ولكن المستدعي لم يمتلك قدرة CAP_WAKE_ALARM.

الإصدارات

  الاختلافات بين مكتبة C والنواة
جزء من تنفيذ واجهة برمجة تطبيقات مؤقتات POSIX يُوفر بواسطة glibc. على وجه الخصوص:

•   معظم وظائف SIGEV_THREAD مُنفذة داخل glibc، وليس النواة. (هذا ضروري، لأن الخيط المشارك في معالجة الإعلام هو خيط يجب إدارته بواسطة تنفيذ خيوط POSIX لمكتبة C.) على الرغم من أن الإعلام المُسلم للعملية يكون عبر خيط، داخليًا يستخدم تنفيذ NPTL قيمة sigev_notify من SIGEV_THREAD_ID مع إشارة زمن حقيقي محجوزة بواسطة التنفيذ (انظر nptl(7)).

•   تنفيذ الحالة المبدئية حيث evp هو NULL يُعالج داخل glibc، الذي يستدعي استدعاء النظام الأساسي مع بنية sigevent مملوءة بشكل مناسب.

•   معرفات المؤقت المُقدمة على مستوى المستخدم تُحافظ عليها glibc، التي تُخطط هذه المعرفات إلى معرفات المؤقت المستخدمة بواسطة النواة.

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

التاريخ
لينكس 2.6. POSIX.1-2001.

قبل لينكس 2.6، وفرت glibc تطبيقًا غير مكتمل في مساحة المستخدم (مؤقتات CLOCK_REALTIME فقط) باستخدام خيوط POSIX، وقبل glibc 2.17، يتراجع التطبيق إلى هذه التقنية على الأنظمة التي تشغل أنوية أقدم من لينكس 2.6.

ملاحظات
يمكن للبرنامج إنشاء مؤقتات دورية متعددة باستخدام timer_create().

لا تُورث المؤقتات إلى الطفل الناتج عن fork(2)، ويتم نزع سلاحها وحذفها أثناء execve(2).

يخصص النواة مسبقًا "إشارة زمن حقيقي في طابور" لكل مؤقت يُنشأ باستخدام timer_create(). وبالتالي، يُحدد عدد المؤقتات بحد المورد RLIMIT_SIGPENDING (انظر setrlimit(2)).

تُعرف المؤقتات التي ينشئها timer_create() باسم "مؤقتات POSIX (الدورية)". تتكون واجهة برمجة تطبيقات مؤقتات POSIX من الواجهات التالية:

timer_create()
    إنشاء مؤقت.

timer_settime(2)
    تسليح (بدء) أو نزع سلاح (إيقاف) مؤقت.

timer_gettime(2)
    جلب الوقت المتبقي حتى انتهاء المؤقت التالي، بالإضافة إلى إعداد الفاصل الزمني للمؤقت.

timer_getoverrun(2)
    إرجاع عدد التجاوزات لآخر انتهاء مؤقت.

timer_delete(2)
    نزع سلاح وحذف مؤقت.

منذ لينكس 3.10، يمكن استخدام الملف /proc/pid/timers لسرد مؤقتات POSIX للعملية ذات PID pid. انظر proc(5) لمزيد من المعلومات.

منذ لينكس 4.10، دعم مؤقتات POSIX هو خيار قابل للتكوين ومُفعّل مبدئيًا. يمكن تعطيل دعم النواة عبر الخيار CONFIG_POSIX_TIMERS.

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

في تشغيل المثال التالي، ينام البرنامج لمدة ثانية واحدة، بعد إنشاء مؤقت بتردد 100 نانو ثانية. بحلول وقت رفع حجب الإشارة وتسليمها، حدث حوالي عشرة ملايين تجاوز.

    $ ./a.out 1 100;
    Establishing handler for signal 34
    Blocking signal 34
    timer ID is 0x804c008
    Sleeping for 1 seconds
    Unblocking signal 34
    Caught signal 34
        sival_ptr = 0xbfb174f4;     *sival_ptr = 0x804c008
        overrun count = 10004886

  مصدر البرنامج
    #include <err.h>
    #include <signal.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <unistd.h>

    #define CLOCKID CLOCK_REALTIME
    #define SIG SIGRTMIN

    static void
    print_siginfo(siginfo_t *si)
    {
        int      or;
        timer_t  *tidp;

        tidp = si->si_value.sival_ptr;

        printf("    sival_ptr = %p; ", si->si_value.sival_ptr);
        printf("    *sival_ptr = %#jx\n", (uintmax_t) *tidp);

        or = timer_getoverrun(*tidp);
        if (or == -1)
            err(EXIT_FAILURE, "timer_getoverrun");

        printf("    overrun count = %d\n", or);
    }

    static void
    handler(int sig, siginfo_t *si, void *uc)
    {
        /* Note: calling printf() from a signal handler is not safe
           (and should not be done in production programs), since
           printf() is not async-signal-safe; see signal-safety(7).
           Nevertheless, we use printf() here as a simple way of
           showing that the handler was called.  */

        printf("Caught signal %d\n", sig);
        print_siginfo(si);
        signal(sig, SIG_IGN);
    }

    int
    main(int argc, char *argv[])
    {
        timer_t            timerid;
        sigset_t           mask;
        long long          freq_nanosecs;
        struct sigevent    sev;
        struct sigaction   sa;
        struct itimerspec  its;

        if (argc != 3) {
            fprintf(stderr, "Usage: %s <sleep-secs> <freq-nanosecs>\n",
                    argv[0]);
            exit(EXIT_FAILURE);
        }

        /* Establish handler for timer signal.  */

        printf("Establishing handler for signal %d\n", SIG);
        sa.sa_flags = SA_SIGINFO;
        sa.sa_sigaction = handler;
        sigemptyset(&sa.sa_mask);
        if (sigaction(SIG, &sa, NULL) == -1)
            err(EXIT_FAILURE, "sigaction");

        /* Block timer signal temporarily.  */

        printf("Blocking signal %d\n", SIG);
        sigemptyset(&mask);
        sigaddset(&mask, SIG);
        if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1)
            err(EXIT_FAILURE, "sigprocmask");

        /* Create the timer.  */

        sev.sigev_notify = SIGEV_SIGNAL;
        sev.sigev_signo = SIG;
        sev.sigev_value.sival_ptr = &timerid;
        if (timer_create(CLOCKID, &sev, &timerid) == -1)
            err(EXIT_FAILURE, "timer_create");

        printf("timer ID is %#jx\n", (uintmax_t) timerid);

        /* Start the timer.  */

        freq_nanosecs = atoll(argv[2]);
        its.it_value.tv_sec = freq_nanosecs / 1000000000;
        its.it_value.tv_nsec = freq_nanosecs % 1000000000;
        its.it_interval.tv_sec = its.it_value.tv_sec;
        its.it_interval.tv_nsec = its.it_value.tv_nsec;

        if (timer_settime(timerid, 0, &its, NULL) == -1)
             err(EXIT_FAILURE, "timer_settime");

        /* Sleep for a while; meanwhile, the timer may expire
           multiple times.  */

        printf("Sleeping for %d seconds\n", atoi(argv[1]));
        sleep(atoi(argv[1]));

        /* Unlock the timer signal, so that timer notification
           can be delivered.  */

        printf("Unblocking signal %d\n", SIG);
        if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
            err(EXIT_FAILURE, "sigprocmask");

        exit(EXIT_SUCCESS);
    }

انظر أيضًا
clock_gettime(2), setitimer(2), timer_delete(2), timer_getoverrun(2), timer_settime(2), timerfd_create(2), clock_getcpuclockid(3), pthread_getcpuclockid(3), pthreads(7), sigevent(3type), signal(7), time(7)

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

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

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