]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Add _cupsGetClock private API, use it for cupsEnumDests (Issue #1084)
authorMichael R Sweet <msweet@msweet.org>
Thu, 3 Apr 2025 14:44:59 +0000 (10:44 -0400)
committerMichael R Sweet <msweet@msweet.org>
Thu, 3 Apr 2025 14:44:59 +0000 (10:44 -0400)
CHANGES.md
cups/Makefile
cups/clock.c [new file with mode: 0644]
cups/cups-private.h
cups/dest.c

index 6f4625d69c68781f9aeaf4be4b3d567103c2995f..640ddbfc671acfe6e7cc1801d58fd5f1ced19e68 100644 (file)
@@ -9,6 +9,7 @@ Changes in CUPS v2.4.12 (YYYY-MM-DD)
 - Added `NoSystem` SSLOptions value (Issue #1130)
 - The scheduler now logs a job's debugging history if the backend fails
   (Issue #1205)
+- Fixed a potential timing issue with `cupsEnumDests` (Issue #1084)
 - Fixed a potential "lost PPD" condition in the scheduler (Issue #1109)
 - Fixed a compressed file error handling bug (Issue #1070)
 - Fixed a bug in the make-and-model whitespace trimming code (Issue #1096)
index 1fa8557d7a28c7878306497029125d8f56519fb8..cf7b8f48793c16ec9ca776750681eb89ff60cd91 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Library Makefile for CUPS.
 #
-# Copyright © 2022-2024 by OpenPrinting.
+# Copyright © 2022-2025 by OpenPrinting.
 # Copyright © 2007-2021 by Apple Inc.
 # Copyright © 1997-2006 by Easy Software Products, all rights reserved.
 #
@@ -19,6 +19,7 @@ include ../Makedefs
 COREOBJS       =       \
                array.o \
                auth.o \
+               clock.o \
                debug.o \
                dest.o \
                dest-job.o \
diff --git a/cups/clock.c b/cups/clock.c
new file mode 100644 (file)
index 0000000..e0dcd5d
--- /dev/null
@@ -0,0 +1,114 @@
+//
+// Monotonic clock API for CUPS.
+//
+// Copyright © 2024-2025 by OpenPrinting.
+//
+// Licensed under Apache License v2.0.  See the file "LICENSE" for more
+// information.
+//
+
+#include "cups-private.h"
+
+
+//
+// Local globals...
+//
+
+static bool    cups_clock_init = false;// Clock initialized?
+static _cups_mutex_t cups_clock_mutex = _CUPS_MUTEX_INITIALIZER;
+                                       // Mutex to control access
+#ifdef _WIN32
+static ULONGLONG cups_first_tick;      // First tick count
+#else
+#  if defined(CLOCK_MONOTONIC) || defined(CLOCK_MONOTONIC_RAW)
+static struct timespec cups_first_clock;// First clock value
+#  endif // CLOCK_MONOTONIC || CLOCK_MONOTONIC_RAW
+static struct timeval cups_first_time; // First time value
+#endif // _WIN32
+
+
+//
+// '_cupsGetClock()' - Get a monotonic clock value in seconds.
+//
+// This function returns a monotonically increasing clock value in seconds.  The
+// first call will always return 0.0.  Subsequent calls will return the number
+// of seconds that have elapsed since the first call, regardless of system time
+// changes, sleep, etc.  The sub-second accuracy varies based on the operating
+// system and hardware but is typically 10ms or better.
+//
+
+double                                 // O - Elapsed seconds
+_cupsGetClock(void)
+{
+  double       secs;                   // Elapsed seconds
+#ifdef _WIN32
+  ULONGLONG    curtick;                // Current tick count
+#else
+#  ifdef CLOCK_MONOTONIC
+  struct timespec curclock;            // Current clock value
+#  endif // CLOCK_MONOTONIC
+  struct timeval curtime;              // Current time value
+#endif // _WIN32
+
+
+  _cupsMutexLock(&cups_clock_mutex);
+
+#ifdef _WIN32
+  // Get the current tick count in milliseconds...
+  curtick = GetTickCount64();
+
+  if (!cups_clock_init)
+  {
+    // First time through initialize the initial tick count...
+    cups_clock_init = true;
+    cups_first_tick = curtick;
+  }
+
+  // Convert ticks to seconds...
+  if (curtick < cups_first_tick)
+    secs = 0.0;
+  else
+    secs = 0.001 * (curtick - cups_first_tick);
+
+#else
+#  if defined(CLOCK_MONOTONIC) || defined(CLOCK_MONOTONIC_RAW)
+  // Get the current tick count in milliseconds...
+#    ifdef CLOCK_MONOTONIC_RAW
+  if (!clock_gettime(CLOCK_MONOTONIC_RAW, &curclock))
+#    else
+  if (!clock_gettime(CLOCK_MONOTONIC, &curclock))
+#    endif // CLOCK_MONOTONIC_RAW
+  {
+    if (!cups_clock_init)
+    {
+      // First time through initialize the initial clock value...
+      cups_clock_init  = true;
+      cups_first_clock = curclock;
+    }
+
+    // Convert clock value to seconds...
+    if ((secs = curclock.tv_sec - cups_first_clock.tv_sec + 0.000000001 * (curclock.tv_nsec - cups_first_clock.tv_nsec)) < 0.0)
+      secs = 0.0;
+  }
+  else
+#  endif // CLOCK_MONOTONIC || CLOCK_MONOTONIC_RAW
+  {
+    gettimeofday(&curtime, /*tzp*/NULL);
+
+    if (!cups_clock_init)
+    {
+      // First time through initialize the initial clock value...
+      cups_clock_init = true;
+      cups_first_time = curtime;
+    }
+
+    // Convert time value to seconds...
+    if ((secs = curtime.tv_sec - cups_first_time.tv_sec + 0.000001 * (curtime.tv_usec - cups_first_time.tv_usec)) < 0.0)
+      secs = 0.0;
+  }
+#endif // _WIN32
+
+  _cupsMutexUnlock(&cups_clock_mutex);
+
+  return (secs);
+}
index 3eca0da87d8654971177b099ef02b5526706185e..2da867ad9593442336f3e60c62884e82c92d995d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Private definitions for CUPS.
  *
- * Copyright © 2020-2024 by OpenPrinting.
+ * Copyright © 2020-2025 by OpenPrinting.
  * Copyright © 2007-2019 by Apple Inc.
  * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
  *
@@ -272,6 +272,7 @@ extern http_t               *_cupsConnect(void) _CUPS_PRIVATE;
 extern char            *_cupsCreateDest(const char *name, const char *info, const char *device_id, const char *device_uri, char *uri, size_t urisize) _CUPS_PRIVATE;
 extern ipp_attribute_t *_cupsEncodeOption(ipp_t *ipp, ipp_tag_t group_tag, _ipp_option_t *map, const char *name, const char *value) _CUPS_PRIVATE;
 extern int             _cupsGet1284Values(const char *device_id, cups_option_t **values) _CUPS_PRIVATE;
+extern double          _cupsGetClock(void) _CUPS_PRIVATE;
 extern const char      *_cupsGetDestResource(cups_dest_t *dest, unsigned flags, char *resource, size_t resourcesize) _CUPS_PRIVATE;
 extern int             _cupsGetDests(http_t *http, ipp_op_t op, const char *name, cups_dest_t **dests, cups_ptype_t type, cups_ptype_t mask) _CUPS_PRIVATE;
 extern const char      *_cupsGetPassword(const char *prompt) _CUPS_PRIVATE;
index 3eeb5093378c96176fb0acc56b0742b0347cfba5..470cff4b62db83e2bad848bcb66c7d8607021fce 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * User-defined destination (and option) support for CUPS.
  *
- * Copyright © 2020-2024 by OpenPrinting.
+ * Copyright © 2020-2025 by OpenPrinting.
  * Copyright © 2007-2019 by Apple Inc.
  * Copyright © 1997-2007 by Easy Software Products.
  *
@@ -9,10 +9,6 @@
  * information.
  */
 
-/*
- * Include necessary headers...
- */
-
 #include "cups-private.h"
 #include "debug-internal.h"
 #include <sys/stat.h>
@@ -119,7 +115,7 @@ typedef struct _cups_dnssd_device_s /* Enumerated device */
 typedef struct _cups_dnssd_resolve_s   /* Data for resolving URI */
 {
   int                  *cancel;        /* Pointer to "cancel" variable */
-  struct timeval       end_time;       /* Ending time */
+  double               end_time;       /* Ending time */
 } _cups_dnssd_resolve_t;
 #endif /* HAVE_DNSSD */
 
@@ -222,7 +218,7 @@ static const char   *cups_dnssd_resolve(cups_dest_t *dest, const char *uri,
 static int             cups_dnssd_resolve_cb(void *context);
 static void            cups_dnssd_unquote(char *dst, const char *src,
                                           size_t dstsize);
-static int             cups_elapsed(struct timeval *t);
+static int             cups_elapsed(double *t);
 #endif /* HAVE_DNSSD */
 static int              cups_enum_dests(http_t *http, unsigned flags, int msec, int *cancel, cups_ptype_t type, cups_ptype_t mask, cups_dest_cb_t cb, void *user_data);
 static int             cups_find_dest(const char *name, const char *instance,
@@ -3290,21 +3286,12 @@ cups_dnssd_resolve(
   * Resolve the URI...
   */
 
-  resolve.cancel = cancel;
-  gettimeofday(&resolve.end_time, NULL);
+  resolve.cancel   = cancel;
+  resolve.end_time = _cupsGetClock();
   if (msec > 0)
-  {
-    resolve.end_time.tv_sec  += msec / 1000;
-    resolve.end_time.tv_usec += (msec % 1000) * 1000;
-
-    while (resolve.end_time.tv_usec >= 1000000)
-    {
-      resolve.end_time.tv_sec ++;
-      resolve.end_time.tv_usec -= 1000000;
-    }
-  }
+    resolve.end_time += 0.001 * msec;
   else
-    resolve.end_time.tv_sec += 75;
+    resolve.end_time += 75.0;
 
   if (cb)
     (*cb)(user_data, CUPS_DEST_FLAGS_UNCONNECTED | CUPS_DEST_FLAGS_RESOLVING, dest);
@@ -3338,7 +3325,7 @@ cups_dnssd_resolve_cb(void *context)      /* I - Resolve data */
 {
   _cups_dnssd_resolve_t        *resolve = (_cups_dnssd_resolve_t *)context;
                                        /* Resolve data */
-  struct timeval       curtime;        /* Current time */
+  double       curtime;                /* Current time */
 
 
  /*
@@ -3355,13 +3342,11 @@ cups_dnssd_resolve_cb(void *context)    /* I - Resolve data */
   * Otherwise check the end time...
   */
 
-  gettimeofday(&curtime, NULL);
+  curtime = _cupsGetClock();
 
-  DEBUG_printf(("4cups_dnssd_resolve_cb: curtime=%d.%06d, end_time=%d.%06d", (int)curtime.tv_sec, (int)curtime.tv_usec, (int)resolve->end_time.tv_sec, (int)resolve->end_time.tv_usec));
+  DEBUG_printf(("4cups_dnssd_resolve_cb: curtime=%.6f, end_time=%.6f", curtime, resolve->end_time));
 
-  return (curtime.tv_sec < resolve->end_time.tv_sec ||
-          (curtime.tv_sec == resolve->end_time.tv_sec &&
-           curtime.tv_usec < resolve->end_time.tv_usec));
+  return (curtime < resolve->end_time);
 }
 
 
@@ -3404,15 +3389,15 @@ cups_dnssd_unquote(char       *dst,     /* I - Destination buffer */
  */
 
 static int                             /* O  - Elapsed time in milliseconds */
-cups_elapsed(struct timeval *t)                /* IO - Previous time */
+cups_elapsed(double *t)                        /* IO - Previous time */
 {
-  int                  msecs;          /* Milliseconds */
-  struct timeval       nt;             /* New time */
+  int          msecs;                  /* Milliseconds */
+  double       nt;                     /* New time */
 
 
-  gettimeofday(&nt, NULL);
+  nt = _cupsGetClock();
 
-  msecs = (int)(1000 * (nt.tv_sec - t->tv_sec) + (nt.tv_usec - t->tv_usec) / 1000);
+  msecs = (int)(1000.0 * (nt - *t));
 
   *t = nt;
 
@@ -3446,7 +3431,7 @@ cups_enum_dests(
   int           count,                  /* Number of queries started */
                 completed,              /* Number of completed queries */
                 remaining;              /* Remainder of timeout */
-  struct timeval curtime;               /* Current time */
+  double       curtime;                /* Current time */
   _cups_dnssd_data_t data;             /* Data for callback */
   _cups_dnssd_device_t *device;         /* Current device */
 #  ifdef HAVE_MDNSRESPONDER
@@ -3672,7 +3657,7 @@ cups_enum_dests(
   * Get Bonjour-shared printers...
   */
 
-  gettimeofday(&curtime, NULL);
+  curtime = _cupsGetClock();
 
 #  ifdef HAVE_MDNSRESPONDER
   if (DNSServiceCreateConnection(&data.main_ref) != kDNSServiceErr_NoError)