Fix overflows in HAVE_XSYNC timestamp handling
Also, port to platforms lacking CLOCK_MONOTONIC and int64_t, and use 0 more consistently to represent missing timestamps. * src/xterm.h (struct x_display_info): Omit server_time_monotonic_p and server_time_offset if !HAVE_CLOCK_GETTIME since they are unused in that case. * src/xterm.h (struct x_display_info, struct x_output): * src/xterm.c (x_sync_get_monotonic_time) (x_sync_current_monotonic_time, x_sync_note_frame_times): Use int_fast64_t instead of int64_t as POSIX doesn't guarantee the latter. Similarly for uint_fast64_t. (x_sync_get_monotonic_time, x_sync_current_monotonic_time) (x_sync_note_frame_times, x_display_set_last_user_time): Check for integer overflow in time arithmetic. (CLOCK_MONOTONIC): Define to CLOCK_REALTIME if absent. (x_sync_current_monotonic_time): Check for clock_gettime failure and fall back on CLOCK_REALTIME if CLOCK_MONOTONIC does not work, which POSIX allows. (x_sync_current_monotonic_time, x_sync_note_frame_times) (x_display_set_last_user_time): Use 0 more consistently to represent missing timestamps.
This commit is contained in:
parent
97067349a8
commit
9bd91a3751
2 changed files with 50 additions and 38 deletions
78
src/xterm.c
78
src/xterm.c
|
@ -6714,9 +6714,9 @@ x_if_event (Display *dpy, XEvent *event_return,
|
|||
server timestamp TIMESTAMP. Return 0 if the necessary information
|
||||
is not available. */
|
||||
|
||||
static uint64_t
|
||||
static uint_fast64_t
|
||||
x_sync_get_monotonic_time (struct x_display_info *dpyinfo,
|
||||
uint64_t timestamp)
|
||||
uint_fast64_t timestamp)
|
||||
{
|
||||
if (dpyinfo->server_time_monotonic_p)
|
||||
return timestamp;
|
||||
|
@ -6725,19 +6725,29 @@ x_sync_get_monotonic_time (struct x_display_info *dpyinfo,
|
|||
if (!dpyinfo->server_time_offset)
|
||||
return 0;
|
||||
|
||||
return timestamp - dpyinfo->server_time_offset;
|
||||
uint_fast64_t t;
|
||||
return (INT_SUBTRACT_WRAPV (timestamp, dpyinfo->server_time_offset, &t)
|
||||
? 0 : t);
|
||||
}
|
||||
|
||||
/* Return the current monotonic time in the same format as a
|
||||
high-resolution server timestamp. */
|
||||
# ifndef CLOCK_MONOTONIC
|
||||
# define CLOCK_MONOTONIC CLOCK_REALTIME
|
||||
# endif
|
||||
|
||||
static uint64_t
|
||||
/* Return the current monotonic time in the same format as a
|
||||
high-resolution server timestamp, or 0 if not available. */
|
||||
|
||||
static uint_fast64_t
|
||||
x_sync_current_monotonic_time (void)
|
||||
{
|
||||
struct timespec time;
|
||||
|
||||
clock_gettime (CLOCK_MONOTONIC, &time);
|
||||
return time.tv_sec * 1000000 + time.tv_nsec / 1000;
|
||||
uint_fast64_t t;
|
||||
return (((clock_gettime (CLOCK_MONOTONIC, &time) != 0
|
||||
&& (CLOCK_MONOTONIC == CLOCK_REALTIME
|
||||
|| clock_gettime (CLOCK_REALTIME, &time) != 0))
|
||||
|| INT_MULTIPLY_WRAPV (time.tv_sec, 1000000, &t)
|
||||
|| INT_ADD_WRAPV (t, time.tv_nsec / 1000, &t))
|
||||
? 0 : t);
|
||||
}
|
||||
|
||||
/* Decode a _NET_WM_FRAME_DRAWN message and calculate the time it took
|
||||
|
@ -6747,7 +6757,7 @@ static void
|
|||
x_sync_note_frame_times (struct x_display_info *dpyinfo,
|
||||
struct frame *f, XEvent *event)
|
||||
{
|
||||
uint64_t low, high, time;
|
||||
uint_fast64_t low, high, time;
|
||||
struct x_output *output;
|
||||
|
||||
low = event->xclient.data.l[2];
|
||||
|
@ -6756,12 +6766,16 @@ x_sync_note_frame_times (struct x_display_info *dpyinfo,
|
|||
|
||||
time = x_sync_get_monotonic_time (dpyinfo, low | (high << 32));
|
||||
|
||||
if (time)
|
||||
output->last_frame_time = time - output->temp_frame_time;
|
||||
if (!time || !output->temp_frame_time
|
||||
|| INT_SUBTRACT_WRAPV (time, output->temp_frame_time,
|
||||
&output->last_frame_time))
|
||||
output->last_frame_time = 0;
|
||||
|
||||
#ifdef FRAME_DEBUG
|
||||
fprintf (stderr, "Drawing the last frame took: %lu ms (%lu)\n",
|
||||
output->last_frame_time / 1000, time);
|
||||
uint_fast64_t last_frame_ms = output->last_frame_time / 1000;
|
||||
fprintf (stderr,
|
||||
"Drawing the last frame took: %"PRIuFAST64" ms (%"PRIuFAST64")\n",
|
||||
last_frame_ms, time);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -6891,22 +6905,16 @@ x_sync_update_begin (struct frame *f)
|
|||
static void
|
||||
x_sync_trigger_fence (struct frame *f, XSyncValue value)
|
||||
{
|
||||
uint64_t n, low, high, idx;
|
||||
|
||||
/* Sync fences aren't supported by the X server. */
|
||||
if (FRAME_DISPLAY_INFO (f)->xsync_major < 3
|
||||
|| (FRAME_DISPLAY_INFO (f)->xsync_major == 3
|
||||
&& FRAME_DISPLAY_INFO (f)->xsync_minor < 1))
|
||||
return;
|
||||
|
||||
low = XSyncValueLow32 (value);
|
||||
high = XSyncValueHigh32 (value);
|
||||
|
||||
n = low | (high << 32);
|
||||
idx = (n / 4) % 2;
|
||||
bool idx = !! (XSyncValueLow32 (value) & 4);
|
||||
|
||||
#ifdef FRAME_DEBUG
|
||||
fprintf (stderr, "Triggering synchronization fence: %lu\n", idx);
|
||||
fprintf (stderr, "Triggering synchronization fence: %d\n", idx);
|
||||
#endif
|
||||
|
||||
XSyncTriggerFence (FRAME_X_DISPLAY (f),
|
||||
|
@ -7600,9 +7608,6 @@ x_display_set_last_user_time (struct x_display_info *dpyinfo, Time time,
|
|||
#ifndef USE_GTK
|
||||
struct frame *focus_frame;
|
||||
Time old_time;
|
||||
#if defined HAVE_XSYNC && defined HAVE_CLOCK_GETTIME
|
||||
uint64_t monotonic_time;
|
||||
#endif
|
||||
|
||||
focus_frame = dpyinfo->x_focus_frame;
|
||||
old_time = dpyinfo->last_user_time;
|
||||
|
@ -7620,19 +7625,26 @@ x_display_set_last_user_time (struct x_display_info *dpyinfo, Time time,
|
|||
{
|
||||
/* See if the current CLOCK_MONOTONIC time is reasonably close
|
||||
to the X server time. */
|
||||
monotonic_time = x_sync_current_monotonic_time ();
|
||||
uint_fast64_t monotonic_time = x_sync_current_monotonic_time ();
|
||||
uint_fast64_t monotonic_ms = monotonic_time / 1000;
|
||||
int_fast64_t diff_ms;
|
||||
|
||||
if (time * 1000 > monotonic_time - 500 * 1000
|
||||
&& time * 1000 < monotonic_time + 500 * 1000)
|
||||
dpyinfo->server_time_monotonic_p = true;
|
||||
else
|
||||
dpyinfo->server_time_monotonic_p
|
||||
= (monotonic_time != 0
|
||||
&& !INT_SUBTRACT_WRAPV (time, monotonic_ms, &diff_ms)
|
||||
&& -500 < diff_ms && diff_ms < 500);
|
||||
|
||||
if (!dpyinfo->server_time_monotonic_p)
|
||||
{
|
||||
/* Compute an offset that can be subtracted from the server
|
||||
time to estimate the monotonic time on the X server. */
|
||||
|
||||
dpyinfo->server_time_monotonic_p = false;
|
||||
dpyinfo->server_time_offset
|
||||
= ((int64_t) time * 1000) - monotonic_time;
|
||||
if (!monotonic_time
|
||||
|| INT_MULTIPLY_WRAPV (time, 1000, &dpyinfo->server_time_offset)
|
||||
|| INT_SUBTRACT_WRAPV (dpyinfo->server_time_offset,
|
||||
monotonic_time,
|
||||
&dpyinfo->server_time_offset))
|
||||
dpyinfo->server_time_offset = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
10
src/xterm.h
10
src/xterm.h
|
@ -828,14 +828,14 @@ struct x_display_info
|
|||
drag-and-drop emulation. */
|
||||
Time pending_dnd_time;
|
||||
|
||||
#if defined HAVE_XSYNC && !defined USE_GTK
|
||||
#if defined HAVE_XSYNC && !defined USE_GTK && defined HAVE_CLOCK_GETTIME
|
||||
/* Whether or not the server time is probably the same as
|
||||
"clock_gettime (CLOCK_MONOTONIC, ...)". */
|
||||
bool server_time_monotonic_p;
|
||||
|
||||
/* The time difference between the X server clock and the monotonic
|
||||
clock. */
|
||||
int64_t server_time_offset;
|
||||
clock, or 0 if unknown (FIXME: what if the difference is zero?). */
|
||||
int_fast64_t server_time_offset;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -1131,10 +1131,10 @@ struct x_output
|
|||
bool_bf use_vsync_p : 1;
|
||||
|
||||
/* The time (in microseconds) it took to draw the last frame. */
|
||||
uint64_t last_frame_time;
|
||||
uint_fast64_t last_frame_time;
|
||||
|
||||
/* A temporary time used to calculate that value. */
|
||||
uint64_t temp_frame_time;
|
||||
uint_fast64_t temp_frame_time;
|
||||
|
||||
#ifdef HAVE_XSYNCTRIGGERFENCE
|
||||
/* An array of two sync fences that are triggered in order after a
|
||||
|
|
Loading…
Add table
Reference in a new issue