From: Rémi Bernon rbernon@codeweavers.com
The client should check that the lower SEQUENCE_MASK_BITS are zero before reading the data and confirm that the number is unchanged when it's finished.
Based on a patch by Huw Davies huw@codeweavers.com. --- server/protocol.def | 5 +++++ server/queue.c | 46 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/server/protocol.def b/server/protocol.def index 7c39a1ba0b0..244bdf7b4a7 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -888,10 +888,15 @@ struct shared_cursor
struct desktop_shared_memory { + unsigned int seq; /* sequence number - server updating if (seq_no & SEQUENCE_MASK) != 0 */ struct shared_cursor cursor; /* global cursor information */ }; typedef volatile struct desktop_shared_memory desktop_shm_t;
+/* Bits that must be clear for client to read */ +#define SEQUENCE_MASK_BITS 4 +#define SEQUENCE_MASK ((1UL << SEQUENCE_MASK_BITS) - 1) + /****************************************************************/ /* Request declarations */
diff --git a/server/queue.c b/server/queue.c index e67362b1fbd..ae9acadb396 100644 --- a/server/queue.c +++ b/server/queue.c @@ -233,6 +233,46 @@ static unsigned int last_input_time; static cursor_pos_t cursor_history[64]; static unsigned int cursor_history_latest;
+#if defined(__i386__) || defined(__x86_64__) + +#define SHARED_WRITE_BEGIN( x ) \ + do { \ + volatile unsigned int __seq = *(x); \ + assert( (__seq & SEQUENCE_MASK) != SEQUENCE_MASK ); \ + *(x) = ++__seq; \ + } while(0) + +#define SHARED_WRITE_END( x ) \ + do { \ + volatile unsigned int __seq = *(x); \ + assert( (__seq & SEQUENCE_MASK) != 0 ); \ + if ((__seq & SEQUENCE_MASK) > 1) __seq--; \ + else __seq += SEQUENCE_MASK; \ + *(x) = __seq; \ + } while(0) + +#else + +#define SHARED_WRITE_BEGIN( x ) \ + do { \ + assert( (*(x) & SEQUENCE_MASK) != SEQUENCE_MASK ); \ + if ((__atomic_add_fetch( x, 1, __ATOMIC_RELAXED ) & SEQUENCE_MASK) == 1) \ + __atomic_thread_fence( __ATOMIC_RELEASE ); \ + } while(0) + +#define SHARED_WRITE_END( x ) \ + do { \ + assert( (*(x) & SEQUENCE_MASK) != 0 ); \ + if ((*(x) & SEQUENCE_MASK) > 1) \ + __atomic_sub_fetch( x, 1, __ATOMIC_RELAXED ); \ + else { \ + __atomic_thread_fence( __ATOMIC_RELEASE ); \ + __atomic_add_fetch( x, SEQUENCE_MASK, __ATOMIC_RELAXED ); \ + } \ + } while(0) + +#endif + static void queue_hardware_message( struct desktop *desktop, struct message *msg, int always_queue ); static void free_message( struct message *msg );
@@ -464,13 +504,17 @@ static int update_desktop_cursor_window( struct desktop *desktop, user_handle_t static int update_desktop_cursor_pos( struct desktop *desktop, user_handle_t win, int x, int y ) { int updated; + unsigned int time = get_tick_count();
x = max( min( x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); y = max( min( y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); updated = (desktop->shared->cursor.x != x || desktop->shared->cursor.y != y); + + SHARED_WRITE_BEGIN( &desktop->shared->seq ); desktop->shared->cursor.x = x; desktop->shared->cursor.y = y; - desktop->shared->cursor.last_change = get_tick_count(); + desktop->shared->cursor.last_change = time; + SHARED_WRITE_END( &desktop->shared->seq );
if (!win || !is_window_visible( win ) || is_window_transparent( win )) win = shallow_window_from_point( desktop, x, y );