Skip to content

Commit 9d41450

Browse files
committed
Add _cupsGetClock private API, use it for cupsEnumDests (Issue #1084)
1 parent 46711ea commit 9d41450

5 files changed

Lines changed: 137 additions & 35 deletions

File tree

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Changes in CUPS v2.4.12 (YYYY-MM-DD)
99
- Added `NoSystem` SSLOptions value (Issue #1130)
1010
- The scheduler now logs a job's debugging history if the backend fails
1111
(Issue #1205)
12+
- Fixed a potential timing issue with `cupsEnumDests` (Issue #1084)
1213
- Fixed a potential "lost PPD" condition in the scheduler (Issue #1109)
1314
- Fixed a compressed file error handling bug (Issue #1070)
1415
- Fixed a bug in the make-and-model whitespace trimming code (Issue #1096)

cups/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#
22
# Library Makefile for CUPS.
33
#
4-
# Copyright © 2022-2024 by OpenPrinting.
4+
# Copyright © 2022-2025 by OpenPrinting.
55
# Copyright © 2007-2021 by Apple Inc.
66
# Copyright © 1997-2006 by Easy Software Products, all rights reserved.
77
#
@@ -19,6 +19,7 @@ include ../Makedefs
1919
COREOBJS = \
2020
array.o \
2121
auth.o \
22+
clock.o \
2223
debug.o \
2324
dest.o \
2425
dest-job.o \

cups/clock.c

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
//
2+
// Monotonic clock API for CUPS.
3+
//
4+
// Copyright © 2024-2025 by OpenPrinting.
5+
//
6+
// Licensed under Apache License v2.0. See the file "LICENSE" for more
7+
// information.
8+
//
9+
10+
#include "cups-private.h"
11+
12+
13+
//
14+
// Local globals...
15+
//
16+
17+
static bool cups_clock_init = false;// Clock initialized?
18+
static _cups_mutex_t cups_clock_mutex = _CUPS_MUTEX_INITIALIZER;
19+
// Mutex to control access
20+
#ifdef _WIN32
21+
static ULONGLONG cups_first_tick; // First tick count
22+
#else
23+
# if defined(CLOCK_MONOTONIC) || defined(CLOCK_MONOTONIC_RAW)
24+
static struct timespec cups_first_clock;// First clock value
25+
# endif // CLOCK_MONOTONIC || CLOCK_MONOTONIC_RAW
26+
static struct timeval cups_first_time; // First time value
27+
#endif // _WIN32
28+
29+
30+
//
31+
// '_cupsGetClock()' - Get a monotonic clock value in seconds.
32+
//
33+
// This function returns a monotonically increasing clock value in seconds. The
34+
// first call will always return 0.0. Subsequent calls will return the number
35+
// of seconds that have elapsed since the first call, regardless of system time
36+
// changes, sleep, etc. The sub-second accuracy varies based on the operating
37+
// system and hardware but is typically 10ms or better.
38+
//
39+
40+
double // O - Elapsed seconds
41+
_cupsGetClock(void)
42+
{
43+
double secs; // Elapsed seconds
44+
#ifdef _WIN32
45+
ULONGLONG curtick; // Current tick count
46+
#else
47+
# ifdef CLOCK_MONOTONIC
48+
struct timespec curclock; // Current clock value
49+
# endif // CLOCK_MONOTONIC
50+
struct timeval curtime; // Current time value
51+
#endif // _WIN32
52+
53+
54+
_cupsMutexLock(&cups_clock_mutex);
55+
56+
#ifdef _WIN32
57+
// Get the current tick count in milliseconds...
58+
curtick = GetTickCount64();
59+
60+
if (!cups_clock_init)
61+
{
62+
// First time through initialize the initial tick count...
63+
cups_clock_init = true;
64+
cups_first_tick = curtick;
65+
}
66+
67+
// Convert ticks to seconds...
68+
if (curtick < cups_first_tick)
69+
secs = 0.0;
70+
else
71+
secs = 0.001 * (curtick - cups_first_tick);
72+
73+
#else
74+
# if defined(CLOCK_MONOTONIC) || defined(CLOCK_MONOTONIC_RAW)
75+
// Get the current tick count in milliseconds...
76+
# ifdef CLOCK_MONOTONIC_RAW
77+
if (!clock_gettime(CLOCK_MONOTONIC_RAW, &curclock))
78+
# else
79+
if (!clock_gettime(CLOCK_MONOTONIC, &curclock))
80+
# endif // CLOCK_MONOTONIC_RAW
81+
{
82+
if (!cups_clock_init)
83+
{
84+
// First time through initialize the initial clock value...
85+
cups_clock_init = true;
86+
cups_first_clock = curclock;
87+
}
88+
89+
// Convert clock value to seconds...
90+
if ((secs = curclock.tv_sec - cups_first_clock.tv_sec + 0.000000001 * (curclock.tv_nsec - cups_first_clock.tv_nsec)) < 0.0)
91+
secs = 0.0;
92+
}
93+
else
94+
# endif // CLOCK_MONOTONIC || CLOCK_MONOTONIC_RAW
95+
{
96+
gettimeofday(&curtime, /*tzp*/NULL);
97+
98+
if (!cups_clock_init)
99+
{
100+
// First time through initialize the initial clock value...
101+
cups_clock_init = true;
102+
cups_first_time = curtime;
103+
}
104+
105+
// Convert time value to seconds...
106+
if ((secs = curtime.tv_sec - cups_first_time.tv_sec + 0.000001 * (curtime.tv_usec - cups_first_time.tv_usec)) < 0.0)
107+
secs = 0.0;
108+
}
109+
#endif // _WIN32
110+
111+
_cupsMutexUnlock(&cups_clock_mutex);
112+
113+
return (secs);
114+
}

cups/cups-private.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* Private definitions for CUPS.
33
*
4-
* Copyright © 2020-2024 by OpenPrinting.
4+
* Copyright © 2020-2025 by OpenPrinting.
55
* Copyright © 2007-2019 by Apple Inc.
66
* Copyright © 1997-2007 by Easy Software Products, all rights reserved.
77
*
@@ -272,6 +272,7 @@ extern http_t *_cupsConnect(void) _CUPS_PRIVATE;
272272
extern char *_cupsCreateDest(const char *name, const char *info, const char *device_id, const char *device_uri, char *uri, size_t urisize) _CUPS_PRIVATE;
273273
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;
274274
extern int _cupsGet1284Values(const char *device_id, cups_option_t **values) _CUPS_PRIVATE;
275+
extern double _cupsGetClock(void) _CUPS_PRIVATE;
275276
extern const char *_cupsGetDestResource(cups_dest_t *dest, unsigned flags, char *resource, size_t resourcesize) _CUPS_PRIVATE;
276277
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;
277278
extern const char *_cupsGetPassword(const char *prompt) _CUPS_PRIVATE;

cups/dest.c

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
/*
22
* User-defined destination (and option) support for CUPS.
33
*
4-
* Copyright © 2020-2024 by OpenPrinting.
4+
* Copyright © 2020-2025 by OpenPrinting.
55
* Copyright © 2007-2019 by Apple Inc.
66
* Copyright © 1997-2007 by Easy Software Products.
77
*
88
* Licensed under Apache License v2.0. See the file "LICENSE" for more
99
* information.
1010
*/
1111

12-
/*
13-
* Include necessary headers...
14-
*/
15-
1612
#include "cups-private.h"
1713
#include "debug-internal.h"
1814
#include <sys/stat.h>
@@ -119,7 +115,7 @@ typedef struct _cups_dnssd_device_s /* Enumerated device */
119115
typedef struct _cups_dnssd_resolve_s /* Data for resolving URI */
120116
{
121117
int *cancel; /* Pointer to "cancel" variable */
122-
struct timeval end_time; /* Ending time */
118+
double end_time; /* Ending time */
123119
} _cups_dnssd_resolve_t;
124120
#endif /* HAVE_DNSSD */
125121

@@ -222,7 +218,7 @@ static const char *cups_dnssd_resolve(cups_dest_t *dest, const char *uri,
222218
static int cups_dnssd_resolve_cb(void *context);
223219
static void cups_dnssd_unquote(char *dst, const char *src,
224220
size_t dstsize);
225-
static int cups_elapsed(struct timeval *t);
221+
static int cups_elapsed(double *t);
226222
#endif /* HAVE_DNSSD */
227223
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);
228224
static int cups_find_dest(const char *name, const char *instance,
@@ -3290,21 +3286,12 @@ cups_dnssd_resolve(
32903286
* Resolve the URI...
32913287
*/
32923288

3293-
resolve.cancel = cancel;
3294-
gettimeofday(&resolve.end_time, NULL);
3289+
resolve.cancel = cancel;
3290+
resolve.end_time = _cupsGetClock();
32953291
if (msec > 0)
3296-
{
3297-
resolve.end_time.tv_sec += msec / 1000;
3298-
resolve.end_time.tv_usec += (msec % 1000) * 1000;
3299-
3300-
while (resolve.end_time.tv_usec >= 1000000)
3301-
{
3302-
resolve.end_time.tv_sec ++;
3303-
resolve.end_time.tv_usec -= 1000000;
3304-
}
3305-
}
3292+
resolve.end_time += 0.001 * msec;
33063293
else
3307-
resolve.end_time.tv_sec += 75;
3294+
resolve.end_time += 75.0;
33083295

33093296
if (cb)
33103297
(*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 */
33383325
{
33393326
_cups_dnssd_resolve_t *resolve = (_cups_dnssd_resolve_t *)context;
33403327
/* Resolve data */
3341-
struct timeval curtime; /* Current time */
3328+
double curtime; /* Current time */
33423329

33433330

33443331
/*
@@ -3355,13 +3342,11 @@ cups_dnssd_resolve_cb(void *context) /* I - Resolve data */
33553342
* Otherwise check the end time...
33563343
*/
33573344

3358-
gettimeofday(&curtime, NULL);
3345+
curtime = _cupsGetClock();
33593346

3360-
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));
3347+
DEBUG_printf(("4cups_dnssd_resolve_cb: curtime=%.6f, end_time=%.6f", curtime, resolve->end_time));
33613348

3362-
return (curtime.tv_sec < resolve->end_time.tv_sec ||
3363-
(curtime.tv_sec == resolve->end_time.tv_sec &&
3364-
curtime.tv_usec < resolve->end_time.tv_usec));
3349+
return (curtime < resolve->end_time);
33653350
}
33663351

33673352

@@ -3404,15 +3389,15 @@ cups_dnssd_unquote(char *dst, /* I - Destination buffer */
34043389
*/
34053390

34063391
static int /* O - Elapsed time in milliseconds */
3407-
cups_elapsed(struct timeval *t) /* IO - Previous time */
3392+
cups_elapsed(double *t) /* IO - Previous time */
34083393
{
3409-
int msecs; /* Milliseconds */
3410-
struct timeval nt; /* New time */
3394+
int msecs; /* Milliseconds */
3395+
double nt; /* New time */
34113396

34123397

3413-
gettimeofday(&nt, NULL);
3398+
nt = _cupsGetClock();
34143399

3415-
msecs = (int)(1000 * (nt.tv_sec - t->tv_sec) + (nt.tv_usec - t->tv_usec) / 1000);
3400+
msecs = (int)(1000.0 * (nt - *t));
34163401

34173402
*t = nt;
34183403

@@ -3446,7 +3431,7 @@ cups_enum_dests(
34463431
int count, /* Number of queries started */
34473432
completed, /* Number of completed queries */
34483433
remaining; /* Remainder of timeout */
3449-
struct timeval curtime; /* Current time */
3434+
double curtime; /* Current time */
34503435
_cups_dnssd_data_t data; /* Data for callback */
34513436
_cups_dnssd_device_t *device; /* Current device */
34523437
# ifdef HAVE_MDNSRESPONDER
@@ -3672,7 +3657,7 @@ cups_enum_dests(
36723657
* Get Bonjour-shared printers...
36733658
*/
36743659

3675-
gettimeofday(&curtime, NULL);
3660+
curtime = _cupsGetClock();
36763661

36773662
# ifdef HAVE_MDNSRESPONDER
36783663
if (DNSServiceCreateConnection(&data.main_ref) != kDNSServiceErr_NoError)

0 commit comments

Comments
 (0)