From 8c17307f95f2967c8258ba3b5c845eac25815ab4 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Thu, 12 Mar 2015 03:14:38 +0100 Subject: [PATCH] Added patch to implement proper locking of keystate and synchronization with desktop thread. --- README.md | 4 +- debian/changelog | 1 + patches/patchinstall.sh | 8 +- ...-to-global-key-state-when-thread-doe.patch | 58 ------- ...-a-helper-function-to-update-the-thr.patch | 88 +++++++++++ ...-locking-and-synchronization-of-keys.patch | 144 ++++++++++++++++++ patches/server-Key_State/definition | 2 + 7 files changed, 244 insertions(+), 61 deletions(-) delete mode 100644 patches/server-Key_State/0001-server-Fall-back-to-global-key-state-when-thread-doe.patch create mode 100644 patches/server-Key_State/0001-server-Introduce-a-helper-function-to-update-the-thr.patch create mode 100644 patches/server-Key_State/0002-server-Implement-locking-and-synchronization-of-keys.patch diff --git a/README.md b/README.md index 2a094ebe..fb31d041 100644 --- a/README.md +++ b/README.md @@ -38,9 +38,11 @@ Wine. All those differences are also documented on the Included bug fixes and improvements =================================== -**Bugfixes and features included in the next upcoming release [1]:** +**Bugfixes and features included in the next upcoming release [3]:** +* Fix caps lock state issues with multiple processes ([Wine Bug #35907](https://bugs.winehq.org/show_bug.cgi?id=35907)) * Fix multithreading issues with fullscreen clipping ([Wine Bug #38087](https://bugs.winehq.org/show_bug.cgi?id=38087)) +* Implement locking and synchronization of key states ([Wine Bug #31899](https://bugs.winehq.org/show_bug.cgi?id=31899)) **Bugs fixed in Wine Staging 1.7.38 [190]:** diff --git a/debian/changelog b/debian/changelog index 197a1db6..fb7aff7f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,7 @@ wine-staging (1.7.39) UNRELEASED; urgency=low * Added patch for tests of RtlIpv6StringToAddress, RtlIpv{4,6}StringToAddressEx (by Mark Jansen). * Added patch to fix multithreading issues with fullscreen clipping. * Added patch with tests for VerQueryValueA (by Mark Jansen). + * Added patch to implement proper locking of keystate and synchronization with desktop thread. * Removed patch to avoid hardcoded values for sizeof(GUID) (accepted upstream). -- Sebastian Lackner Mon, 09 Mar 2015 16:52:35 +0100 diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 830093bd..be6eea2d 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -3537,14 +3537,18 @@ fi # | # | This patchset fixes the following Wine bugs: # | * [#27238] Fallback to global key state for threads without a queue +# | * [#31899] Implement locking and synchronization of key states +# | * [#35907] Fix caps lock state issues with multiple processes # | # | Modified files: # | * server/queue.c # | if test "$enable_server_Key_State" -eq 1; then - patch_apply server-Key_State/0001-server-Fall-back-to-global-key-state-when-thread-doe.patch + patch_apply server-Key_State/0001-server-Introduce-a-helper-function-to-update-the-thr.patch + patch_apply server-Key_State/0002-server-Implement-locking-and-synchronization-of-keys.patch ( - echo '+ { "Sebastian Lackner", "server: Fall back to global key state when thread doesn'\''t have a queue.", 1 },'; + echo '+ { "Sebastian Lackner", "server: Introduce a helper function to update the thread_input key state.", 1 },'; + echo '+ { "Sebastian Lackner", "server: Implement locking and synchronization of keystate buffer.", 1 },'; ) >> "$patchlist" fi diff --git a/patches/server-Key_State/0001-server-Fall-back-to-global-key-state-when-thread-doe.patch b/patches/server-Key_State/0001-server-Fall-back-to-global-key-state-when-thread-doe.patch deleted file mode 100644 index 052f853c..00000000 --- a/patches/server-Key_State/0001-server-Fall-back-to-global-key-state-when-thread-doe.patch +++ /dev/null @@ -1,58 +0,0 @@ -From c908afaed01d4ca53ef66a7fb649402f9ae1a3d8 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Thu, 26 Feb 2015 04:23:28 +0100 -Subject: server: Fall back to global key state when thread doesn't have a - queue. - ---- - server/queue.c | 25 +++++++++++++------------ - 1 file changed, 13 insertions(+), 12 deletions(-) - -diff --git a/server/queue.c b/server/queue.c -index 3a321cd..6cbf8e1 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -2783,27 +2783,28 @@ DECL_HANDLER(get_key_state) - struct desktop *desktop; - data_size_t size = min( 256, get_reply_max_size() ); - -- if (!req->tid) /* get global async key state */ -- { -- if (!(desktop = get_thread_desktop( current, 0 ))) return; -- if (req->key >= 0) -- { -- reply->state = desktop->keystate[req->key & 0xff]; -- desktop->keystate[req->key & 0xff] &= ~0x40; -- } -- set_reply_data( desktop->keystate, size ); -- release_object( desktop ); -- } -- else -+ if (req->tid) - { - if (!(thread = get_thread_from_id( req->tid ))) return; - if (thread->queue) - { - if (req->key >= 0) reply->state = thread->queue->input->keystate[req->key & 0xff]; - set_reply_data( thread->queue->input->keystate, size ); -+ release_object( thread ); -+ return; - } - release_object( thread ); - } -+ -+ /* get global async key state */ -+ if (!(desktop = get_thread_desktop( current, 0 ))) return; -+ if (req->key >= 0) -+ { -+ reply->state = desktop->keystate[req->key & 0xff]; -+ desktop->keystate[req->key & 0xff] &= ~0x40; -+ } -+ set_reply_data( desktop->keystate, size ); -+ release_object( desktop ); - } - - --- -2.3.0 - diff --git a/patches/server-Key_State/0001-server-Introduce-a-helper-function-to-update-the-thr.patch b/patches/server-Key_State/0001-server-Introduce-a-helper-function-to-update-the-thr.patch new file mode 100644 index 00000000..14ee8680 --- /dev/null +++ b/patches/server-Key_State/0001-server-Introduce-a-helper-function-to-update-the-thr.patch @@ -0,0 +1,88 @@ +From b575a8659eb9daa7af14c15f9f564a19e4b5dbd5 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Thu, 12 Mar 2015 00:44:25 +0100 +Subject: server: Introduce a helper function to update the thread_input key + state. + +--- + server/queue.c | 22 ++++++++++++++-------- + 1 file changed, 14 insertions(+), 8 deletions(-) + +diff --git a/server/queue.c b/server/queue.c +index 3a321cd..85c0786 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -1215,9 +1215,9 @@ static void set_input_key_state( unsigned char *keystate, unsigned char key, int + else keystate[key] &= ~0x80; + } + +-/* update the input key state for a keyboard message */ +-static void update_input_key_state( struct desktop *desktop, unsigned char *keystate, +- const struct message *msg ) ++/* update the key state for a keyboard message */ ++static void update_key_state( struct desktop *desktop, unsigned char *keystate, ++ const struct message *msg ) + { + unsigned char key; + int down = 0; +@@ -1279,6 +1279,12 @@ static void update_input_key_state( struct desktop *desktop, unsigned char *keys + } + } + ++/* update the thread input key state for a keyboard message */ ++static void update_input_key_state( struct thread_input *input, const struct message *msg ) ++{ ++ update_key_state( input->desktop, input->keystate, msg ); ++} ++ + /* release the hardware message currently being processed by the given thread */ + static void release_hardware_message( struct msg_queue *queue, unsigned int hw_id, + int remove ) +@@ -1309,7 +1315,7 @@ static void release_hardware_message( struct msg_queue *queue, unsigned int hw_i + } + if (clr_bit) clear_queue_bits( queue, clr_bit ); + +- update_input_key_state( input->desktop, input->keystate, msg ); ++ update_input_key_state( input, msg ); + list_remove( &msg->entry ); + free_message( msg ); + } +@@ -1430,7 +1436,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg + unsigned int msg_code; + struct hardware_msg_data *data = msg->data; + +- update_input_key_state( desktop, desktop->keystate, msg ); ++ update_key_state( desktop, desktop->keystate, msg ); + last_input_time = get_tick_count(); + if (msg->msg != WM_MOUSEMOVE) always_queue = 1; + +@@ -1473,7 +1479,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg + win = find_hardware_message_window( desktop, input, msg, &msg_code, &thread ); + if (!win || !thread) + { +- if (input) update_input_key_state( input->desktop, input->keystate, msg ); ++ if (input) update_input_key_state( input, msg ); + free_message( msg ); + return; + } +@@ -1911,7 +1917,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user + if (!win || !win_thread) + { + /* no window at all, remove it */ +- update_input_key_state( input->desktop, input->keystate, msg ); ++ update_input_key_state( input, msg ); + list_remove( &msg->entry ); + free_message( msg ); + continue; +@@ -1927,7 +1933,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user + else + { + /* for another thread input, drop it */ +- update_input_key_state( input->desktop, input->keystate, msg ); ++ update_input_key_state( input, msg ); + list_remove( &msg->entry ); + free_message( msg ); + } +-- +2.3.1 + diff --git a/patches/server-Key_State/0002-server-Implement-locking-and-synchronization-of-keys.patch b/patches/server-Key_State/0002-server-Implement-locking-and-synchronization-of-keys.patch new file mode 100644 index 00000000..c9adbc64 --- /dev/null +++ b/patches/server-Key_State/0002-server-Implement-locking-and-synchronization-of-keys.patch @@ -0,0 +1,144 @@ +From 230ab0ec85f3f175396876907fed42ef285d0f64 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Thu, 12 Mar 2015 02:56:21 +0100 +Subject: server: Implement locking and synchronization of keystate buffer. + +--- + server/queue.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 55 insertions(+), 1 deletion(-) + +diff --git a/server/queue.c b/server/queue.c +index 85c0786..426f626 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -111,6 +111,7 @@ struct thread_input + user_handle_t cursor; /* current cursor */ + int cursor_count; /* cursor show count */ + struct list msg_list; /* list of hardware messages */ ++ int lock_count; /* lock counter for keystate */ + unsigned char keystate[256]; /* state of each key */ + }; + +@@ -122,6 +123,7 @@ struct msg_queue + unsigned int wake_mask; /* wakeup mask */ + unsigned int changed_bits; /* changed wakeup bits */ + unsigned int changed_mask; /* changed wakeup mask */ ++ int keystate_locked; /* keystate is locked */ + int paint_count; /* pending paint messages count */ + int hotkey_count; /* pending hotkey messages count */ + int quit_message; /* is there a pending quit message? */ +@@ -250,6 +252,7 @@ static struct thread_input *create_thread_input( struct thread *thread ) + input->cursor = 0; + input->cursor_count = 0; + list_init( &input->msg_list ); ++ input->lock_count = 0; + set_caret_window( input, 0 ); + memset( input->keystate, 0, sizeof(input->keystate) ); + +@@ -282,6 +285,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ + queue->wake_mask = 0; + queue->changed_bits = 0; + queue->changed_mask = 0; ++ queue->keystate_locked = 0; + queue->paint_count = 0; + queue->hotkey_count = 0; + queue->quit_message = 0; +@@ -970,6 +974,7 @@ static void msg_queue_destroy( struct object *obj ) + free( timer ); + } + if (queue->timeout) remove_timeout_user( queue->timeout ); ++ if (queue->keystate_locked) queue->input->lock_count--; + queue->input->cursor_count -= queue->cursor_count; + release_object( queue->input ); + if (queue->hooks) release_object( queue->hooks ); +@@ -1279,9 +1284,22 @@ static void update_key_state( struct desktop *desktop, unsigned char *keystate, + } + } + ++/* synchronizes the thread input key state with the desktop */ ++static void synchronize_input_key_state( struct thread_input *input ) ++{ ++ if (!input->lock_count) ++ { ++ unsigned char *keystate = input->keystate; ++ unsigned int i; ++ for (i = 0; i < 256; i++) ++ keystate[i] = input->desktop->keystate[i] & ~0x40; ++ } ++} ++ + /* update the thread input key state for a keyboard message */ + static void update_input_key_state( struct thread_input *input, const struct message *msg ) + { ++ synchronize_input_key_state( input ); + update_key_state( input->desktop, input->keystate, msg ); + } + +@@ -1492,6 +1510,15 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg + else + { + msg->unique_id = 0; /* will be set once we return it to the app */ ++ ++ /* lock the keystate on the first hardware message */ ++ if (!thread->queue->keystate_locked) ++ { ++ synchronize_input_key_state( input ); ++ input->lock_count++; ++ thread->queue->keystate_locked = 1; ++ } ++ + list_add_tail( &input->msg_list, &msg->entry ); + set_queue_bits( thread->queue, get_hardware_msg_bit(msg) ); + } +@@ -2363,6 +2390,13 @@ DECL_HANDLER(get_message) + queue->last_get_msg = current_time; + if (!filter) filter = QS_ALLINPUT; + ++ /* no longer lock the keystate if we have processed all input */ ++ if (queue->keystate_locked && !(queue->wake_bits & QS_ALLINPUT)) ++ { ++ queue->input->lock_count--; ++ queue->keystate_locked = 0; ++ } ++ + /* first check for sent messages */ + if ((ptr = list_head( &queue->msg_list[SEND_MESSAGE] ))) + { +@@ -2802,13 +2836,33 @@ DECL_HANDLER(get_key_state) + } + else + { ++ unsigned char *keystate; + if (!(thread = get_thread_from_id( req->tid ))) return; + if (thread->queue) + { +- if (req->key >= 0) reply->state = thread->queue->input->keystate[req->key & 0xff]; ++ if (req->key >= 0) ++ { ++ /* synchronize with desktop keystate, but _only_ if req->key is given */ ++ synchronize_input_key_state( thread->queue->input ); ++ reply->state = thread->queue->input->keystate[req->key & 0xff]; ++ } + set_reply_data( thread->queue->input->keystate, size ); ++ release_object( thread ); ++ return; + } + release_object( thread ); ++ ++ /* fallback to desktop keystate */ ++ if (!(desktop = get_thread_desktop( current, 0 ))) return; ++ if (req->key >= 0) ++ reply->state = desktop->keystate[req->key & 0xff] & ~0x40; ++ if ((keystate = set_reply_data_size( size ))) ++ { ++ unsigned int i; ++ for (i = 0; i < size; i++) ++ keystate[i] = desktop->keystate[i] & ~0x40; ++ } ++ release_object( desktop ); + } + } + +-- +2.3.1 + diff --git a/patches/server-Key_State/definition b/patches/server-Key_State/definition index c014bbd5..acb81cf6 100644 --- a/patches/server-Key_State/definition +++ b/patches/server-Key_State/definition @@ -1 +1,3 @@ Fixes: [27238] Fallback to global key state for threads without a queue +Fixes: [31899] Implement locking and synchronization of key states +Fixes: [35907] Fix caps lock state issues with multiple processes