Back to index

glibc  2.9
tst-timer4.c
Go to the documentation of this file.
00001 /* Tests for POSIX timer implementation.
00002    Copyright (C) 2004 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Jakub Jelinek <jakub@redhat.com>, 2004
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public License as
00008    published by the Free Software Foundation; either version 2.1 of the
00009    License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; see the file COPYING.LIB.  If not,
00018    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019    Boston, MA 02111-1307, USA.  */
00020 
00021 #include <errno.h>
00022 #include <signal.h>
00023 #include <stdio.h>
00024 #include <string.h>
00025 #include <time.h>
00026 #include <unistd.h>
00027 #if _POSIX_THREADS
00028 # include <pthread.h>
00029 
00030 # ifndef TEST_CLOCK
00031 #  define TEST_CLOCK        CLOCK_REALTIME
00032 # endif
00033 
00034 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
00035 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
00036 
00037 timer_t timer_none, timer_sig1, timer_sig2, timer_thr1, timer_thr2;
00038 
00039 int thr1_cnt, thr1_err;
00040 union sigval thr1_sigval;
00041 struct timespec thr1_ts;
00042 
00043 static void
00044 thr1 (union sigval sigval)
00045 {
00046   pthread_mutex_lock (&lock);
00047   thr1_err = clock_gettime (TEST_CLOCK, &thr1_ts);
00048   if (thr1_cnt >= 5)
00049     {
00050       struct itimerspec it = { };
00051       thr1_err |= timer_settime (timer_thr1, 0, &it, NULL);
00052     }
00053   thr1_sigval = sigval;
00054   ++thr1_cnt;
00055   pthread_cond_signal (&cond);
00056   pthread_mutex_unlock (&lock);
00057 }
00058 
00059 int thr2_cnt, thr2_err;
00060 union sigval thr2_sigval;
00061 size_t thr2_guardsize;
00062 struct timespec thr2_ts;
00063 
00064 static void
00065 thr2 (union sigval sigval)
00066 {
00067   pthread_attr_t nattr;
00068   int err = 0;
00069   size_t guardsize = -1;
00070   int ret = pthread_getattr_np (pthread_self (), &nattr);
00071   if (ret)
00072     {
00073       errno = ret;
00074       printf ("*** pthread_getattr_np failed: %m\n");
00075       err = 1;
00076     }
00077   else
00078     {
00079       ret = pthread_attr_getguardsize (&nattr, &guardsize);
00080       if (ret)
00081         {
00082           errno = ret;
00083           printf ("*** pthread_attr_getguardsize failed: %m\n");
00084           err = 1;
00085         }
00086       if (pthread_attr_destroy (&nattr) != 0)
00087         {
00088           puts ("*** pthread_attr_destroy failed");
00089           err = 1;
00090         }
00091     }
00092   pthread_mutex_lock (&lock);
00093   thr2_err = clock_gettime (TEST_CLOCK, &thr2_ts) | err;
00094   if (thr2_cnt >= 5)
00095     {
00096       struct itimerspec it = { };
00097       thr2_err |= timer_settime (timer_thr2, 0, &it, NULL);
00098     }
00099   thr2_sigval = sigval;
00100   ++thr2_cnt;
00101   thr2_guardsize = guardsize;
00102   pthread_cond_signal (&cond);
00103   pthread_mutex_unlock (&lock);
00104 }
00105 
00106 volatile int sig1_cnt, sig1_err;
00107 volatile union sigval sig1_sigval;
00108 struct timespec sig1_ts;
00109 
00110 static void
00111 sig1_handler (int sig, siginfo_t *info, void *ctx)
00112 {
00113   int err = 0;
00114   if (sig != SIGRTMIN) err |= 1 << 0;
00115   if (info->si_signo != SIGRTMIN) err |= 1 << 1;
00116   if (info->si_code != SI_TIMER) err |= 1 << 2;
00117   if (clock_gettime (TEST_CLOCK, &sig1_ts) != 0)
00118     err |= 1 << 3;
00119   if (sig1_cnt >= 5)
00120     {
00121       struct itimerspec it = { };
00122       if (timer_settime (timer_sig1, 0, &it, NULL))
00123        err |= 1 << 4;
00124     }
00125   sig1_err |= err;
00126   sig1_sigval = info->si_value;
00127   ++sig1_cnt;
00128 }
00129 
00130 volatile int sig2_cnt, sig2_err;
00131 volatile union sigval sig2_sigval;
00132 struct timespec sig2_ts;
00133 
00134 static void
00135 sig2_handler (int sig, siginfo_t *info, void *ctx)
00136 {
00137   int err = 0;
00138   if (sig != SIGRTMIN + 1) err |= 1 << 0;
00139   if (info->si_signo != SIGRTMIN + 1) err |= 1 << 1;
00140   if (info->si_code != SI_TIMER) err |= 1 << 2;
00141   if (clock_gettime (TEST_CLOCK, &sig2_ts) != 0)
00142     err |= 1 << 3;
00143   if (sig2_cnt >= 5)
00144     {
00145       struct itimerspec it = { };
00146       if (timer_settime (timer_sig2, 0, &it, NULL))
00147        err |= 1 << 4;
00148     }
00149   sig2_err |= err;
00150   sig2_sigval = info->si_value;
00151   ++sig2_cnt;
00152 }
00153 
00154 /* Check if end is later or equal to start + nsec.  */
00155 static int
00156 check_ts (const char *name, const struct timespec *start,
00157          const struct timespec *end, long msec)
00158 {
00159   struct timespec ts = *start;
00160 
00161   ts.tv_sec += msec / 1000000;
00162   ts.tv_nsec += (msec % 1000000) * 1000;
00163   if (ts.tv_nsec >= 1000000000)
00164     {
00165       ++ts.tv_sec;
00166       ts.tv_nsec -= 1000000000;
00167     }
00168   if (end->tv_sec < ts.tv_sec
00169       || (end->tv_sec == ts.tv_sec && end->tv_nsec < ts.tv_nsec))
00170     {
00171       printf ("\
00172 *** timer %s invoked too soon: %ld.%09ld instead of expected %ld.%09ld\n",
00173              name, (long) end->tv_sec, end->tv_nsec,
00174              (long) ts.tv_sec, ts.tv_nsec);
00175       return 1;
00176     }
00177   else
00178     return 0;
00179 }
00180 
00181 #define TIMEOUT 15
00182 #define TEST_FUNCTION do_test ()
00183 static int
00184 do_test (void)
00185 {
00186   int result = 0;
00187 
00188 #ifdef TEST_CLOCK_MISSING
00189   const char *missing = TEST_CLOCK_MISSING (TEST_CLOCK);
00190   if (missing != NULL)
00191     {
00192       printf ("%s missing, skipping test\n", missing);
00193       return 0;
00194     }
00195 #endif
00196 
00197   struct timespec ts;
00198   if (clock_gettime (TEST_CLOCK, &ts) != 0)
00199     {
00200       printf ("*** clock_gettime failed: %m\n");
00201       result = 1;
00202     }
00203   else
00204     printf ("clock_gettime returned timespec = { %ld, %ld }\n",
00205            (long) ts.tv_sec, ts.tv_nsec);
00206 
00207   if (clock_getres (TEST_CLOCK, &ts) != 0)
00208     {
00209       printf ("*** clock_getres failed: %m\n");
00210       result = 1;
00211     }
00212   else
00213     printf ("clock_getres returned timespec = { %ld, %ld }\n",
00214            (long) ts.tv_sec, ts.tv_nsec);
00215 
00216   struct sigevent ev;
00217   memset (&ev, 0x11, sizeof (ev));
00218   ev.sigev_notify = SIGEV_NONE;
00219   if (timer_create (TEST_CLOCK, &ev, &timer_none) != 0)
00220     {
00221       printf ("*** timer_create for timer_none failed: %m\n");
00222       return 1;
00223     }
00224 
00225   struct sigaction sa = { .sa_sigaction = sig1_handler,
00226                        .sa_flags = SA_SIGINFO };
00227   sigemptyset (&sa.sa_mask);
00228   sigaction (SIGRTMIN, &sa, NULL);
00229   sa.sa_sigaction = sig2_handler;
00230   sigaction (SIGRTMIN + 1, &sa, NULL);
00231 
00232   memset (&ev, 0x22, sizeof (ev));
00233   ev.sigev_notify = SIGEV_SIGNAL;
00234   ev.sigev_signo = SIGRTMIN;
00235   ev.sigev_value.sival_ptr = &ev;
00236   if (timer_create (TEST_CLOCK, &ev, &timer_sig1) != 0)
00237     {
00238       printf ("*** timer_create for timer_sig1 failed: %m\n");
00239       return 1;
00240     }
00241 
00242   memset (&ev, 0x33, sizeof (ev));
00243   ev.sigev_notify = SIGEV_SIGNAL;
00244   ev.sigev_signo = SIGRTMIN + 1;
00245   ev.sigev_value.sival_int = 163;
00246   if (timer_create (TEST_CLOCK, &ev, &timer_sig2) != 0)
00247     {
00248       printf ("*** timer_create for timer_sig2 failed: %m\n");
00249       return 1;
00250     }
00251 
00252   memset (&ev, 0x44, sizeof (ev));
00253   ev.sigev_notify = SIGEV_THREAD;
00254   ev.sigev_notify_function = thr1;
00255   ev.sigev_notify_attributes = NULL;
00256   ev.sigev_value.sival_ptr = &ev;
00257   if (timer_create (TEST_CLOCK, &ev, &timer_thr1) != 0)
00258     {
00259       printf ("*** timer_create for timer_thr1 failed: %m\n");
00260       return 1;
00261     }
00262 
00263   pthread_attr_t nattr;
00264   if (pthread_attr_init (&nattr)
00265       || pthread_attr_setguardsize (&nattr, 0))
00266     {
00267       puts ("*** pthread_attr_t setup failed");
00268       result = 1;
00269     }
00270 
00271   memset (&ev, 0x55, sizeof (ev));
00272   ev.sigev_notify = SIGEV_THREAD;
00273   ev.sigev_notify_function = thr2;
00274   ev.sigev_notify_attributes = &nattr;
00275   ev.sigev_value.sival_int = 111;
00276   if (timer_create (TEST_CLOCK, &ev, &timer_thr2) != 0)
00277     {
00278       printf ("*** timer_create for timer_thr2 failed: %m\n");
00279       return 1;
00280     }
00281 
00282   int ret = timer_getoverrun (timer_thr1);
00283   if (ret != 0)
00284     {
00285       if (ret == -1)
00286        printf ("*** timer_getoverrun failed: %m\n");
00287       else
00288        printf ("*** timer_getoverrun returned %d != 0\n", ret);
00289       result = 1;
00290     }
00291 
00292   struct itimerspec it;
00293   it.it_value.tv_sec = 0;
00294   it.it_value.tv_nsec = -26;
00295   it.it_interval.tv_sec = 0;
00296   it.it_interval.tv_nsec = 0;
00297   if (timer_settime (timer_sig1, 0, &it, NULL) == 0)
00298     {
00299       puts ("*** timer_settime with negative tv_nsec unexpectedly succeeded");
00300       result = 1;
00301     }
00302   else if (errno != EINVAL)
00303     {
00304       printf ("*** timer_settime with negative tv_nsec did not fail with "
00305              "EINVAL: %m\n");
00306       result = 1;
00307     }
00308 
00309   it.it_value.tv_nsec = 100000;
00310   it.it_interval.tv_nsec = 1000000000;
00311   if (timer_settime (timer_sig2, 0, &it, NULL) == 0)
00312     {
00313       puts ("\
00314 *** timer_settime with tv_nsec 1000000000 unexpectedly succeeded");
00315       result = 1;
00316     }
00317   else if (errno != EINVAL)
00318     {
00319       printf ("*** timer_settime with tv_nsec 1000000000 did not fail with "
00320              "EINVAL: %m\n");
00321       result = 1;
00322     }
00323 
00324 #if 0
00325   it.it_value.tv_nsec = 0;
00326   it.it_interval.tv_nsec = -26;
00327   if (timer_settime (timer_thr1, 0, &it, NULL) != 0)
00328     {
00329       printf ("\
00330 !!! timer_settime with it_value 0 it_interval invalid failed: %m\n");
00331       /* FIXME: is this mandated by POSIX?
00332       result = 1; */
00333     }
00334 
00335   it.it_interval.tv_nsec = 3000000000;
00336   if (timer_settime (timer_thr2, 0, &it, NULL) != 0)
00337     {
00338       printf ("\
00339 !!! timer_settime with it_value 0 it_interval invalid failed: %m\n");
00340       /* FIXME: is this mandated by POSIX?
00341       result = 1; */
00342     }
00343 #endif
00344 
00345   struct timespec startts;
00346   if (clock_gettime (TEST_CLOCK, &startts) != 0)
00347     {
00348       printf ("*** clock_gettime failed: %m\n");
00349       result = 1;
00350     }
00351 
00352   it.it_value.tv_nsec = 100000000;
00353   it.it_interval.tv_nsec = 0;
00354   if (timer_settime (timer_none, 0, &it, NULL) != 0)
00355     {
00356       printf ("*** timer_settime timer_none failed: %m\n");
00357       result = 1;
00358     }
00359 
00360   it.it_value.tv_nsec = 200000000;
00361   if (timer_settime (timer_thr1, 0, &it, NULL) != 0)
00362     {
00363       printf ("*** timer_settime timer_thr1 failed: %m\n");
00364       result = 1;
00365     }
00366 
00367   it.it_value.tv_nsec = 300000000;
00368   if (timer_settime (timer_thr2, 0, &it, NULL) != 0)
00369     {
00370       printf ("*** timer_settime timer_thr2 failed: %m\n");
00371       result = 1;
00372     }
00373 
00374   it.it_value.tv_nsec = 400000000;
00375   if (timer_settime (timer_sig1, 0, &it, NULL) != 0)
00376     {
00377       printf ("*** timer_settime timer_sig1 failed: %m\n");
00378       result = 1;
00379     }
00380 
00381   it.it_value.tv_nsec = 500000000;
00382   if (TEMP_FAILURE_RETRY (timer_settime (timer_sig2, 0, &it, NULL)) != 0)
00383     {
00384       printf ("*** timer_settime timer_sig2 failed: %m\n");
00385       result = 1;
00386     }
00387 
00388   pthread_mutex_lock (&lock);
00389   while (thr1_cnt == 0 || thr2_cnt == 0)
00390     pthread_cond_wait (&cond, &lock);
00391   pthread_mutex_unlock (&lock);
00392 
00393   while (sig1_cnt == 0 || sig2_cnt == 0)
00394     {
00395       ts.tv_sec = 0;
00396       ts.tv_nsec = 100000000;
00397       nanosleep (&ts, NULL);
00398     }
00399 
00400   pthread_mutex_lock (&lock);
00401 
00402   if (thr1_cnt != 1)
00403     {
00404       printf ("*** thr1 not called exactly once, but %d times\n", thr1_cnt);
00405       result = 1;
00406     }
00407   else if (thr1_err)
00408     {
00409       puts ("*** an error occurred in thr1");
00410       result = 1;
00411     }
00412   else if (thr1_sigval.sival_ptr != &ev)
00413     {
00414       printf ("*** thr1_sigval.sival_ptr %p != %p\n",
00415              thr1_sigval.sival_ptr, &ev);
00416       result = 1;
00417     }
00418   else if (check_ts ("thr1", &startts, &thr1_ts, 200000))
00419     result = 1;
00420 
00421   if (thr2_cnt != 1)
00422     {
00423       printf ("*** thr2 not called exactly once, but %d times\n", thr2_cnt);
00424       result = 1;
00425     }
00426   else if (thr2_err)
00427     {
00428       puts ("*** an error occurred in thr2");
00429       result = 1;
00430     }
00431   else if (thr2_sigval.sival_int != 111)
00432     {
00433       printf ("*** thr2_sigval.sival_ptr %d != 111\n", thr2_sigval.sival_int);
00434       result = 1;
00435     }
00436   else if (check_ts ("thr2", &startts, &thr2_ts, 300000))
00437     result = 1;
00438   else if (thr2_guardsize != 0)
00439     {
00440       printf ("*** thr2 guardsize %zd != 0\n", thr2_guardsize);
00441       result = 1;
00442     }
00443 
00444   pthread_mutex_unlock (&lock);
00445 
00446   if (sig1_cnt != 1)
00447     {
00448       printf ("*** sig1 not called exactly once, but %d times\n", sig1_cnt);
00449       result = 1;
00450     }
00451   else if (sig1_err)
00452     {
00453       printf ("*** errors occurred in sig1 handler %x\n", sig1_err);
00454       result = 1;
00455     }
00456   else if (sig1_sigval.sival_ptr != &ev)
00457     {
00458       printf ("*** sig1_sigval.sival_ptr %p != %p\n",
00459              sig1_sigval.sival_ptr, &ev);
00460       result = 1;
00461     }
00462   else if (check_ts ("sig1", &startts, &sig1_ts, 400000))
00463     result = 1;
00464 
00465   if (sig2_cnt != 1)
00466     {
00467       printf ("*** sig2 not called exactly once, but %d times\n", sig2_cnt);
00468       result = 1;
00469     }
00470   else if (sig2_err)
00471     {
00472       printf ("*** errors occurred in sig2 handler %x\n", sig2_err);
00473       result = 1;
00474     }
00475   else if (sig2_sigval.sival_int != 163)
00476     {
00477       printf ("*** sig2_sigval.sival_ptr %d != 163\n", sig2_sigval.sival_int);
00478       result = 1;
00479     }
00480   else if (check_ts ("sig2", &startts, &sig2_ts, 500000))
00481     result = 1;
00482 
00483   if (timer_gettime (timer_none, &it) != 0)
00484     {
00485       printf ("*** timer_gettime timer_none failed: %m\n");
00486       result = 1;
00487     }
00488   else if (it.it_value.tv_sec || it.it_value.tv_nsec
00489           || it.it_interval.tv_sec || it.it_interval.tv_nsec)
00490     {
00491       printf ("\
00492 *** timer_gettime timer_none returned { %ld.%09ld, %ld.%09ld }\n",
00493              (long) it.it_value.tv_sec, it.it_value.tv_nsec,
00494              (long) it.it_interval.tv_sec, it.it_interval.tv_nsec);
00495       result = 1;
00496     }
00497 
00498   if (clock_gettime (TEST_CLOCK, &startts) != 0)
00499     {
00500       printf ("*** clock_gettime failed: %m\n");
00501       result = 1;
00502     }
00503 
00504   it.it_value.tv_sec = 1;
00505   it.it_value.tv_nsec = 0;
00506   it.it_interval.tv_sec = 0;
00507   it.it_interval.tv_nsec = 100000000;
00508   if (timer_settime (timer_none, 0, &it, NULL) != 0)
00509     {
00510       printf ("*** timer_settime timer_none failed: %m\n");
00511       result = 1;
00512     }
00513 
00514   it.it_value.tv_nsec = 100000000;
00515   it.it_interval.tv_nsec = 200000000;
00516   if (timer_settime (timer_thr1, 0, &it, NULL) != 0)
00517     {
00518       printf ("*** timer_settime timer_thr1 failed: %m\n");
00519       result = 1;
00520     }
00521 
00522   it.it_value.tv_nsec = 200000000;
00523   it.it_interval.tv_nsec = 300000000;
00524   if (timer_settime (timer_thr2, 0, &it, NULL) != 0)
00525     {
00526       printf ("*** timer_settime timer_thr2 failed: %m\n");
00527       result = 1;
00528     }
00529 
00530   it.it_value.tv_nsec = 300000000;
00531   it.it_interval.tv_nsec = 400000000;
00532   if (timer_settime (timer_sig1, 0, &it, NULL) != 0)
00533     {
00534       printf ("*** timer_settime timer_sig1 failed: %m\n");
00535       result = 1;
00536     }
00537 
00538   it.it_value.tv_nsec = 400000000;
00539   it.it_interval.tv_nsec = 500000000;
00540   if (TEMP_FAILURE_RETRY (timer_settime (timer_sig2, 0, &it, NULL)) != 0)
00541     {
00542       printf ("*** timer_settime timer_sig2 failed: %m\n");
00543       result = 1;
00544     }
00545 
00546   pthread_mutex_lock (&lock);
00547   while (thr1_cnt < 6 || thr2_cnt < 6)
00548     pthread_cond_wait (&cond, &lock);
00549   pthread_mutex_unlock (&lock);
00550 
00551   while (sig1_cnt < 6 || sig2_cnt < 6)
00552     {
00553       ts.tv_sec = 0;
00554       ts.tv_nsec = 100000000;
00555       nanosleep (&ts, NULL);
00556     }
00557 
00558   pthread_mutex_lock (&lock);
00559 
00560   if (thr1_err)
00561     {
00562       puts ("*** an error occurred in thr1");
00563       result = 1;
00564     }
00565   else if (check_ts ("thr1", &startts, &thr1_ts, 1100000 + 4 * 200000))
00566     result = 1;
00567 
00568   if (thr2_err)
00569     {
00570       puts ("*** an error occurred in thr2");
00571       result = 1;
00572     }
00573   else if (check_ts ("thr2", &startts, &thr2_ts, 1200000 + 4 * 300000))
00574     result = 1;
00575   else if (thr2_guardsize != 0)
00576     {
00577       printf ("*** thr2 guardsize %zd != 0\n", thr2_guardsize);
00578       result = 1;
00579     }
00580 
00581   pthread_mutex_unlock (&lock);
00582 
00583   if (sig1_err)
00584     {
00585       printf ("*** errors occurred in sig1 handler %x\n", sig1_err);
00586       result = 1;
00587     }
00588   else if (check_ts ("sig1", &startts, &sig1_ts, 1300000 + 4 * 400000))
00589     result = 1;
00590 
00591   if (sig2_err)
00592     {
00593       printf ("*** errors occurred in sig2 handler %x\n", sig2_err);
00594       result = 1;
00595     }
00596   else if (check_ts ("sig2", &startts, &sig2_ts, 1400000 + 4 * 500000))
00597     result = 1;
00598 
00599   if (timer_gettime (timer_none, &it) != 0)
00600     {
00601       printf ("*** timer_gettime timer_none failed: %m\n");
00602       result = 1;
00603     }
00604   else if (it.it_interval.tv_sec || it.it_interval.tv_nsec != 100000000)
00605     {
00606       printf ("\
00607 !!! second timer_gettime timer_none returned it_interval %ld.%09ld\n",
00608              (long) it.it_interval.tv_sec, it.it_interval.tv_nsec);
00609       /* FIXME: For now disabled.
00610       result = 1; */
00611     }
00612 
00613   if (timer_delete (timer_none) != 0)
00614     {
00615       printf ("*** timer_delete for timer_none failed: %m\n");
00616       result = 1;
00617     }
00618 
00619   if (timer_delete (timer_sig1) != 0)
00620     {
00621       printf ("*** timer_delete for timer_sig1 failed: %m\n");
00622       result = 1;
00623     }
00624 
00625   if (timer_delete (timer_sig2) != 0)
00626     {
00627       printf ("*** timer_delete for timer_sig2 failed: %m\n");
00628       result = 1;
00629     }
00630 
00631   if (timer_delete (timer_thr1) != 0)
00632     {
00633       printf ("*** timer_delete for timer_thr1 failed: %m\n");
00634       result = 1;
00635     }
00636 
00637   if (timer_delete (timer_thr2) != 0)
00638     {
00639       printf ("*** timer_delete for timer_thr2 failed: %m\n");
00640       result = 1;
00641     }
00642   return result;
00643 }
00644 #else
00645 # define TEST_FUNCTION 0
00646 #endif
00647 
00648 #include "../test-skeleton.c"