From: Michael R Sweet Date: Thu, 3 Apr 2025 14:44:59 +0000 (-0400) Subject: Add _cupsGetClock private API, use it for cupsEnumDests (Issue #1084) X-Git-Tag: v2.4.12~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9d41450c18fe01b6ef739ebc70b4c6acee1cf72b;p=thirdparty%2Fcups.git Add _cupsGetClock private API, use it for cupsEnumDests (Issue #1084) --- diff --git a/CHANGES.md b/CHANGES.md index 6f4625d69c..640ddbfc67 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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) diff --git a/cups/Makefile b/cups/Makefile index 1fa8557d7a..cf7b8f4879 100644 --- a/cups/Makefile +++ b/cups/Makefile @@ -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 index 0000000000..e0dcd5dc6c --- /dev/null +++ b/cups/clock.c @@ -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); +} diff --git a/cups/cups-private.h b/cups/cups-private.h index 3eca0da87d..2da867ad95 100644 --- a/cups/cups-private.h +++ b/cups/cups-private.h @@ -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; diff --git a/cups/dest.c b/cups/dest.c index 3eeb509337..470cff4b62 100644 --- a/cups/dest.c +++ b/cups/dest.c @@ -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 @@ -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)