clock_getres(2)

الاسم
clock_getres, clock_gettime, clock_settime - دوال الساعة والوقت

المكتبة
مكتبة C القياسية (libc, -lc)، منذ glibc 2.17

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

موجز
#include <time.h>

int clock_getres(clockid_t clockid, struct timespec *_Nullable res);

int clock_gettime(clockid_t clockid, struct timespec *tp);
int clock_settime(clockid_t clockid, const struct timespec *tp);

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

clock_getres()، clock_gettime()، clock_settime():
    _POSIX_C_SOURCE >= 199309L

الوصف
تجد الدالة clock_getres() دقة (إحكام) الساعة المحددة clockid، وإذا كان res غير NULL، تخزنه في struct timespec المشار إليه بواسطة res. تعتمد دقة الساعات على التنفيذ ولا يمكن تكوينها بواسطة عملية معينة. إذا كانت قيمة الوقت المشار إليها بواسطة الوسيطة tp للدالة clock_settime() ليست مضاعفًا لـ res، فسيتم اقتطاعها إلى مضاعف لـ res.

تسترجع الدالتان clock_gettime() و clock_settime() وقت الساعة المحددة clockid وتضبطانه.

الوسيطتان res و tp هما بنيتان من نوع timespec(3).

الوسيطة clockid هي معرف الساعة المحددة التي سيتم العمل عليها. قد تكون الساعة على مستوى النظام وبالتالي مرئية لجميع العمليات، أو لكل عملية إذا كانت تقيس الوقت فقط داخل عملية واحدة.

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

قد يتم تنفيذ ساعات إضافية. تفسير قيم الوقت المقابلة والتأثير على الموقتات غير محدد.

تدعم الإصدارات الحديثة بما فيه الكفاية من glibc ونواة لينكس الساعات التالية:

CLOCK_REALTIME
    ساعة قابلة للضبط على مستوى النظام تقيس الوقت الحقيقي (أي وقت الحائط). يتطلب ضبط هذه الساعة صلاحيات مناسبة. تتأثر هذه الساعة بالقفزات غير المستمرة في وقت النظام (مثلًا، إذا قام مسؤول النظام بتغيير الساعة يدويًا)، وبضبط التردد الذي تقوم به NTP والتطبيقات المماثلة عبر adjtime(3)، adjtimex(2)، clock_adjtime(2)، و ntp_adjtime(3). تحسب هذه الساعة عادةً عدد الثواني منذ 1970-01-01 00:00:00 التوقيت العالمي المنسق (UTC) باستثناء أنها تتجاهل الثواني الكبيسة؛ بالقرب من ثانية كبيسة، يتم ضبطها عادةً بواسطة NTP للبقاء متزامنة تقريبًا مع UTC.

CLOCK_REALTIME_ALARM (منذ لينكس 3.0؛ خاص بلينكس)
    مثل CLOCK_REALTIME، ولكن قابل للضبط فقط بشكل غير مباشر عن طريق ضبط CLOCK_REALTIME، ويتصرف بشكل مختلف إذا كان النظام معلقًا. انظر timer_create(2).

CLOCK_REALTIME_COARSE (منذ لينكس 2.6.32؛ خاص بلينكس)
    نسخة أسرع ولكن أقل دقة من CLOCK_REALTIME. قابل للضبط فقط بشكل غير مباشر عن طريق ضبط CLOCK_REALTIME. استخدمه عندما تحتاج إلى طوابع زمنية سريعة جدًا، ولكن ليست دقيقة. يتطلب دعمًا لكل بنية، وربما أيضًا دعم بنية لهذه العلامة في vdso(7).

CLOCK_TAI (منذ لينكس 3.10؛ خاص بلينكس)
    ساعة على مستوى النظام مشتقة من وقت الحائط ولكنها تحسب الثواني الكبيسة. لا تواجه هذه الساعة تعديلات الساعة الناتجة عن إدراج الثواني الكبيسة كما تفعل CLOCK_REALTIME. تحسب الثواني منذ 1970-01-01 00:00 TAI (1969-12-31 23:59:50 UTC)، لذا فإن حقبتها تسبق حقبة CLOCK_REALTIME بعشر ثوانٍ. ومع ذلك، يتطلب تنفيذها مساعدة من NTP، وإذا لم تكن هذه المساعدة متاحة، فإنها تتصرف مثل CLOCK_REALTIME بدلاً من ذلك.

    علاقتها بـ CLOCK_REALTIME للطوابع الزمنية قبل 1972 تقريبية فقط، حيث تم تقديم نظام الثواني الكبيسة في 1972-01-01. نظرًا لأنه من المخطط إيقاف الثواني الكبيسة، فمن المحتمل أن تظل قيمتها من الآن فصاعدًا أكبر بـ 37 ثانية بالضبط من قيمة CLOCK_REALTIME لسنوات عديدة، وبعد ذلك من المحتمل أن يتم ضبط إزاحتها عن CLOCK_REALTIME بواسطة آلية أخرى غير محددة بعد. قابلة للضبط فقط بشكل غير مباشر عن طريق ضبط CLOCK_REALTIME.

    يرمز الاختصار TAI إلى العبارة الفرنسية "temps atomique international"، أو التوقيت الذري الدولي.

CLOCK_MONOTONIC
    ساعة غير قابلة للضبط على مستوى النظام تمثل الوقت الرتيب منذ—كما هو موصوف بواسطة POSIX—"نقطة غير محددة في الماضي". على لينكس، تتوافق تلك النقطة مع عدد الثواني التي كان النظام يعمل فيها منذ تشغيله.

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

CLOCK_MONOTONIC_COARSE (منذ لينكس 2.6.32؛ خاص بلينكس)
    نسخة أسرع ولكن أقل دقة من CLOCK_MONOTONIC. استخدمه عندما تحتاج إلى طوابع زمنية سريعة جدًا، ولكن ليست دقيقة. يتطلب دعمًا لكل بنية، وربما أيضًا دعم بنية لهذه العلامة في vdso(7).

CLOCK_MONOTONIC_RAW (منذ لينكس 2.6.28؛ خاص بلينكس)
    مشابه لـ CLOCK_MONOTONIC، ولكنه يوفر الوصول إلى وقت خام قائم على العتاد لا يخضع لضبط التردد. لا تحسب هذه الساعة الوقت الذي يكون فيه النظام معلقًا.

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

CLOCK_BOOTTIME_ALARM (منذ لينكس 3.0؛ خاص بلينكس)
    مثل CLOCK_BOOTTIME، لكنه يتصرف بشكل مختلف إذا كان النظام معلقًا. انظر timer_create(2).

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

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

ينفذ لينكس أيضًا مثيلات ساعة ديناميكية كما هو موضح أدناه.

  الساعات الديناميكية
بالإضافة إلى معرفات الساعة بنمط System-V المرمزة بشكل ثابت الموصوفة أعلاه، يدعم لينكس أيضًا عمليات ساعة POSIX على أجهزة حرفية معينة. تسمى هذه الأجهزة ساعات "ديناميكية"، وهي مدعومة منذ لينكس 2.6.39.

باستخدام وحدات الماكرو المناسبة، يمكن تحويل واصفات الملفات المفتوحة إلى معرفات ساعة وتمريرها إلى clock_gettime() و clock_settime() و clock_adjtime(2). يوضح المثال التالي كيفية تحويل واصف ملف إلى معرف ساعة ديناميكي.

    #define CLOCKFD 3
    #define FD_TO_CLOCKID(fd)   ((~(clockid_t) (fd) << 3) | CLOCKFD)
    #define CLOCKID_TO_FD(clk)  ((unsigned int) ~((clk) >> 3))

    struct timespec ts;
    clockid_t clkid;
    int fd;

    fd = open("/dev/ptp0", O_RDWR);
    clkid = FD_TO_CLOCKID(fd);
    clock_gettime(clkid, &ts);

قيمة الإرجاع
تعيد clock_gettime() و clock_settime() و clock_getres() 0 عند النجاح. عند الخطأ، يتم إرجاع -1 ويتم تعيين errno للإشارة إلى الخطأ.

الأخطاء

EACCES
    لا يمتلك clock_settime() إذن الكتابة لجهاز الساعة POSIX الديناميكي المشار إليه.

EFAULT
    يشير tp إلى خارج مساحة العنوان القابلة للوصول.

EINVAL
    clockid المحدد غير صالح لأحد سببين. إما أن القيمة الموجبة المرمزة بشكل ثابت بنمط System-V خارج النطاق، أو أن معرف الساعة الديناميكي لا يشير إلى مثيل صالح لكائن ساعة.

EINVAL
    (clock_settime()): tp.tv_sec سالب أو tp.tv_nsec خارج النطاق [0, 999,999,999].

EINVAL
    clockid المحدد في استدعاء لـ clock_settime() ليس ساعة قابلة للضبط.

EINVAL (منذ لينكس 4.3)
    حاول استدعاء لـ clock_settime() مع clockid بقيمة CLOCK_REALTIME ضبط الوقت على قيمة أقل من القيمة الحالية لساعة CLOCK_MONOTONIC.

ENODEV
    اختفى الجهاز القابل للتبديل السريع (مثل USB على سبيل المثال) الممثل بواسطة clk_id ديناميكي بعد فتح جهازه الحرفي.

ENOTSUP
    العملية غير مدعومة من قبل جهاز الساعة POSIX الديناميكي المحدد.

EOVERFLOW
    الطابع الزمني لن يتسع في نطاق time_t. يمكن أن يحدث هذا إذا تم تشغيل ملف تنفيذي مع time_t 32 بت على نواة 64 بت عندما يكون الوقت 2038-01-19 03:14:08 UTC أو لاحقًا. ومع ذلك، عندما يكون وقت النظام خارج نطاق time_t في حالات أخرى، يكون السلوك غير محدد.

EPERM
    لا يمتلك clock_settime() الإذن لضبط الساعة المشار إليها.

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

الإصدارات
يحدد POSIX.1 ما يلي:

    ضبط قيمة ساعة CLOCK_REALTIME عبر clock_settime() لن يكون له أي تأثير على الخيوط المحظورة في انتظار خدمة وقت نسبي بناءً على هذه الساعة، بما في ذلك دالة nanosleep()؛ ولا على انتهاء صلاحية المؤقتات النسبية بناءً على هذه الساعة. وبالتالي، ستنتهي صلاحية خدمات الوقت هذه عندما ينقضي الفاصل الزمني النسبي المطلوب، بغض النظر عن القيمة الجديدة أو القديمة للساعة.

وفقًا لـ POSIX.1-2001، يمكن لعملية ذات "امتيازات مناسبة" ضبط ساعتي CLOCK_PROCESS_CPUTIME_ID و CLOCK_THREAD_CPUTIME_ID باستخدام clock_settime(). في لينكس، هذه الساعات غير قابلة للضبط (أي لا توجد عملية لها "امتيازات مناسبة").

  الاختلافات بين مكتبة C والنواة
في بعض البنى، يتم توفير تطبيق لـ clock_gettime() في vdso(7).

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

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

في أنظمة POSIX التي تتوفر فيها هذه الدوال، يتم تعريف الرمز _POSIX_TIMERS في <unistd.h> بقيمة أكبر من 0. يجعل POSIX.1-2008 هذه الدوال إلزامية.

تشير الرموز _POSIX_MONOTONIC_CLOCK و _POSIX_CPUTIME و _POSIX_THREAD_CPUTIME إلى أن CLOCK_MONOTONIC و CLOCK_PROCESS_CPUTIME_ID و CLOCK_THREAD_CPUTIME_ID متوفرة. (انظر أيضًا sysconf(3).)

جعل POSIX.1-2024 CLOCK_MONOTONIC إلزاميًا.

  ملاحظة تاريخية لأنظمة SMP
قبل أن يضيف لينكس دعم النواة لـ CLOCK_PROCESS_CPUTIME_ID و CLOCK_THREAD_CPUTIME_ID، نفذت glibc هذه الساعات على العديد من المنصات باستخدام مسجلات المؤقت من وحدات المعالجة المركزية (TSC على i386، AR.ITC على Itanium). قد تختلف هذه المسجلات بين وحدات المعالجة المركزية، وكنتيجة لذلك قد تعيد هذه الساعات نتائج زائفة إذا تم ترحيل عملية إلى وحدة معالجة مركزية أخرى.

إذا كانت وحدات المعالجة المركزية في نظام SMP تمتلك مصادر ساعة مختلفة، فلا توجد طريقة للحفاظ على ترابط بين مسجلات المؤقت لأن كل وحدة معالجة مركزية ستعمل بتردد مختلف قليلاً. إذا كان الأمر كذلك، فإن clock_getcpuclockid(0) سيعيد ENOENT للإشارة إلى هذه الحالة. عندها ستكون الساعتان مفيدتين فقط إذا أمكن ضمان بقاء عملية على وحدة معالجة مركزية معينة.

لا تبدأ المعالجات في نظام SMP جميعها في نفس الوقت تمامًا، وبالتالي تعمل مسجلات المؤقت عادةً بإزاحة. تتضمن بعض البنيات كودًا يحاول الحد من هذه الإزاحات عند الإقلاع. ومع ذلك، لا يمكن للكود ضمان ضبط الإزاحات بدقة. لا تحتوي glibc على أحكام للتعامل مع هذه الإزاحات (على عكس نواة لينكس). عادةً ما تكون هذه الإزاحات صغيرة، وبالتالي قد تكون التأثيرات ضئيلة في معظم الحالات.

منذ glibc 2.4، تتجنب دوال التغليف لاستدعاءات النظام الموصوفة في هذه الصفحة المشاكل المذكورة أعلاه باستخدام تنفيذ النواة لـ CLOCK_PROCESS_CPUTIME_ID و CLOCK_THREAD_CPUTIME_ID، على الأنظمة التي توفر مثل هذا التنفيذ (أي لينكس 2.6.12 والإصدارات الأحدث).

أمثلة
يوضح البرنامج أدناه استخدام clock_gettime() و clock_getres() مع ساعات مختلفة. هذا مثال لما قد نراه عند تشغيل البرنامج:

    $ ./clock_times x;
    CLOCK_REALTIME : 1585985459.446 (18356 days +  7h 30m 59s)
         resolution:          0.000000001
    CLOCK_TAI      : 1585985496.447 (18356 days +  7h 31m 36s)
         resolution:          0.000000001
    CLOCK_MONOTONIC:      52395.722 (14h 33m 15s)
         resolution:          0.000000001
    CLOCK_BOOTTIME :      72691.019 (20h 11m 31s)
         resolution:          0.000000001

  مصدر البرنامج
    /* clock_times.c

       Licensed under GNU General Public License v2 or later.
    */
    #define _XOPEN_SOURCE 600
    #include <stdbool.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <time.h>

    #define SECS_IN_DAY (24 * 60 * 60)

    static void
    displayClock(clockid_t clock, const char *name, bool showRes)
    {
        long             days;
        struct timespec  ts;

        if (clock_gettime(clock, &ts) == -1) {
            perror("clock_gettime");
            exit(EXIT_FAILURE);
        }

        printf("%-15s: %10jd.%03ld (", name,
               (intmax_t) ts.tv_sec, ts.tv_nsec / 1000000);

        days = ts.tv_sec / SECS_IN_DAY;
        if (days > 0)
            printf("%ld days + ", days);

        printf("%2dh %2dm %2ds",
               (int) (ts.tv_sec % SECS_IN_DAY) / 3600,
               (int) (ts.tv_sec % 3600) / 60,
               (int) ts.tv_sec % 60);
        printf(")\n");

        if (clock_getres(clock, &ts) == -1) {
            perror("clock_getres");
            exit(EXIT_FAILURE);
        }

        if (showRes)
            printf("     resolution: %10jd.%09ld\n",
                   (intmax_t) ts.tv_sec, ts.tv_nsec);
    }

    int
    main(int argc, char *[])
    {
        bool showRes = argc > 1;

        displayClock(CLOCK_REALTIME, "CLOCK_REALTIME", showRes);
    #ifdef CLOCK_TAI
        displayClock(CLOCK_TAI, "CLOCK_TAI", showRes);
    #endif
        displayClock(CLOCK_MONOTONIC, "CLOCK_MONOTONIC", showRes);
    #ifdef CLOCK_BOOTTIME
        displayClock(CLOCK_BOOTTIME, "CLOCK_BOOTTIME", showRes);
    #endif
        exit(EXIT_SUCCESS);
    }

انظر أيضًا
date(1), gettimeofday(2), settimeofday(2), time(2), adjtime(3), clock_getcpuclockid(3), ctime(3), ftime(3), pthread_getcpuclockid(3), sysconf(3), timespec(3), time(7), time_namespaces(7), vdso(7), hwclock(8)

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

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

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