From: Twaik Yont <9674930+twaik@users.noreply.github.com> Move native window registration from the APC/unixlib callback path to the direct JNI surface_changed callback. Keep WM_ANDROID_REFRESH posted from process_events() after updating the native window state. Add a temporary serialization lock around ioctl dispatch and native window registration to keep intermediate migration commits bisectable while moving this code away from the old APC execution path. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/android.h | 2 - dlls/wineandroid.drv/device.c | 95 ++++++++++++++++++---------------- dlls/wineandroid.drv/dllmain.c | 8 --- dlls/wineandroid.drv/init.c | 3 -- dlls/wineandroid.drv/unixlib.h | 11 ---- dlls/wineandroid.drv/window.c | 3 +- 6 files changed, 51 insertions(+), 71 deletions(-) diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h index 8cec766f1eb..f87c561d2e2 100644 --- a/dlls/wineandroid.drv/android.h +++ b/dlls/wineandroid.drv/android.h @@ -105,8 +105,6 @@ extern BOOL has_client_surface( HWND hwnd ); extern NTSTATUS android_dispatch_ioctl( void *arg ); extern NTSTATUS android_java_init( void *arg ); extern NTSTATUS android_java_uninit( void *arg ); -extern NTSTATUS android_register_window( void *arg ); -extern PNTAPCFUNC register_window_callback; extern UINT64 start_device_callback; extern unsigned int screen_width; diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index a19fd0074e1..544b63a21da 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -109,6 +109,8 @@ static JNIEnv *jni_env; static HWND capture_window; static HWND desktop_window; +static pthread_mutex_t dispatch_ioctl_lock = PTHREAD_MUTEX_INITIALIZER; // Temporary lock for bisect-safe serialization of dispatch-related state during the APC-to-JNI registration migration. + #define ANDROIDCONTROLTYPE ((ULONG)'A') #define ANDROID_IOCTL(n) CTL_CODE(ANDROIDCONTROLTYPE, n, METHOD_BUFFERED, FILE_READ_ACCESS) @@ -395,6 +397,7 @@ static void insert_buffer_lru( struct native_win_data *win, int index ) win->buffer_lru[0] = index; } +/* Called from JNI surface_changed() on the Java thread */ static int register_buffer( struct native_win_data *win, struct AHardwareBuffer *buffer, int *is_new ) { unsigned int i; @@ -481,41 +484,36 @@ static struct native_win_data *create_native_win_data( HWND hwnd, BOOL opengl ) return data; } -NTSTATUS android_register_window( void *arg ) +/* register a native window received from the Java side for use in ioctls */ +void register_native_window( HWND hwnd, struct ANativeWindow *win, BOOL opengl ) { - struct register_window_params *params = arg; - HWND hwnd = (HWND)params->arg1; - struct ANativeWindow *win = (struct ANativeWindow *)params->arg2; - BOOL opengl = params->arg3; - struct native_win_data *data = get_native_win_data( hwnd, opengl ); + struct native_win_data *data = NULL; + + pthread_mutex_lock(&dispatch_ioctl_lock); + data = get_native_win_data( hwnd, opengl ); - if (!win) return 0; /* do nothing and hold on to the window until we get a new surface */ + if (!win) { + pthread_mutex_unlock(&dispatch_ioctl_lock); + return; /* do nothing and hold on to the window until we get a new surface */ + } if (!data || data->parent == win) { pANativeWindow_release( win ); - if (data) NtUserPostMessage( hwnd, WM_ANDROID_REFRESH, opengl, 0 ); _TRACE( "%p -> %p win %p (unchanged)\n", hwnd, data, win ); - return 0; + pthread_mutex_unlock(&dispatch_ioctl_lock); + return; } release_native_window( data ); data->parent = win; data->generation++; - wrap_java_call(); if (data->api) win->perform( win, NATIVE_WINDOW_API_CONNECT, data->api ); win->perform( win, NATIVE_WINDOW_SET_BUFFERS_FORMAT, data->buffer_format ); win->setSwapInterval( win, data->swap_interval ); - unwrap_java_call(); - NtUserPostMessage( hwnd, WM_ANDROID_REFRESH, opengl, 0 ); _TRACE( "%p -> %p win %p\n", hwnd, data, win ); - return 0; -} - -/* register a native window received from the Java side for use in ioctls */ -void register_native_window( HWND hwnd, struct ANativeWindow *win, BOOL opengl ) -{ - NtQueueApcThread( thread, register_window_callback, (ULONG_PTR)hwnd, (ULONG_PTR)win, opengl ); + pthread_mutex_unlock(&dispatch_ioctl_lock); + return; } #define LOAD_FUNCPTR(lib, func) do { \ @@ -636,7 +634,7 @@ static void create_desktop_view(void) unwrap_java_call(); } -static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; @@ -658,7 +656,7 @@ static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, U return STATUS_SUCCESS; } -static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; @@ -680,7 +678,7 @@ static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, return STATUS_SUCCESS; } -static NTSTATUS windowPosChanged_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS windowPosChanged_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; @@ -704,7 +702,7 @@ static NTSTATUS windowPosChanged_ioctl( void *data, DWORD in_size, DWORD out_siz return STATUS_SUCCESS; } -static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ANativeWindow *parent; struct ioctl_android_dequeueBuffer *res = data; @@ -803,7 +801,7 @@ static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, return STATUS_SUCCESS; } -static NTSTATUS cancelBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS cancelBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_cancelBuffer *res = data; struct ANativeWindow *parent; @@ -826,7 +824,7 @@ static NTSTATUS cancelBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, U return android_error_to_status( ret ); } -static NTSTATUS queueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS queueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_queueBuffer *res = data; struct ANativeWindow *parent; @@ -849,7 +847,7 @@ static NTSTATUS queueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, UL return android_error_to_status( ret ); } -static NTSTATUS query_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS query_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_query *res = data; struct ANativeWindow *parent; @@ -869,7 +867,7 @@ static NTSTATUS query_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PT return android_error_to_status( ret ); } -static NTSTATUS perform_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS perform_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_perform *res = data; struct ANativeWindow *parent; @@ -956,7 +954,7 @@ static NTSTATUS perform_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_ return android_error_to_status( ret ); } -static NTSTATUS setSwapInterval_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS setSwapInterval_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_set_swap_interval *res = data; struct ANativeWindow *parent; @@ -975,7 +973,7 @@ static NTSTATUS setSwapInterval_ioctl( void *data, DWORD in_size, DWORD out_size return android_error_to_status( ret ); } -static NTSTATUS setWindowParent_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS setWindowParent_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; @@ -996,7 +994,7 @@ static NTSTATUS setWindowParent_ioctl( void *data, DWORD in_size, DWORD out_size return STATUS_SUCCESS; } -static NTSTATUS setCapture_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS setCapture_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_set_capture *res = data; @@ -1010,7 +1008,7 @@ static NTSTATUS setCapture_ioctl( void *data, DWORD in_size, DWORD out_size, ULO return STATUS_SUCCESS; } -static NTSTATUS setCursor_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS setCursor_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; @@ -1048,7 +1046,7 @@ static NTSTATUS setCursor_ioctl( void *data, DWORD in_size, DWORD out_size, ULON return STATUS_SUCCESS; } -typedef NTSTATUS (*ioctl_func)( void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ); +typedef NTSTATUS (*ioctl_func)( void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ); static const ioctl_func ioctl_funcs[] = { createWindow_ioctl, /* IOCTL_CREATE_WINDOW */ @@ -1076,13 +1074,16 @@ NTSTATUS android_dispatch_ioctl( void *arg ) struct ioctl_header *header = irp->AssociatedIrp.SystemBuffer; DWORD in_size = irpsp->Parameters.DeviceIoControl.InputBufferLength; ioctl_func func = ioctl_funcs[code]; + int reply_fd = -1; if (in_size >= sizeof(*header)) { irp->IoStatus.Information = 0; + pthread_mutex_lock(&dispatch_ioctl_lock); irp->IoStatus.Status = func( irp->AssociatedIrp.SystemBuffer, in_size, irpsp->Parameters.DeviceIoControl.OutputBufferLength, - &irp->IoStatus.Information ); + &irp->IoStatus.Information, &reply_fd ); + pthread_mutex_unlock(&dispatch_ioctl_lock); } else irp->IoStatus.Status = STATUS_INVALID_PARAMETER; } @@ -1130,7 +1131,7 @@ void start_android_device(void) /* Client-side ioctl support */ -static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size ) +static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size, int *recv_fd ) { static const WCHAR deviceW[] = { '\\','D','e','v','i','c','e','\\','W','i','n','e','A','n','d','r','o','i','d', 0 }; static HANDLE device; @@ -1153,6 +1154,8 @@ static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void if (InterlockedCompareExchangePointer( &device, file, NULL )) NtClose( file ); } + if (recv_fd) *recv_fd = -1; + status = NtDeviceIoControlFile( device, NULL, NULL, NULL, &iosb, ANDROID_IOCTL(code), in, in_size, out, out_size ? *out_size : 0 ); if (status == STATUS_FILE_DELETED) @@ -1190,7 +1193,7 @@ static int dequeueBuffer( struct ANativeWindow *window, struct ANativeWindowBuff res.buffer_id = -1; res.generation = 0; - ret = android_ioctl( IOCTL_DEQUEUE_BUFFER, &res, size, &res, &size ); + ret = android_ioctl( IOCTL_DEQUEUE_BUFFER, &res, size, &res, &size, NULL ); if (ret) return ret; if (size < sizeof(res)) return -EINVAL; @@ -1246,7 +1249,7 @@ static int cancelBuffer( struct ANativeWindow *window, struct ANativeWindowBuffe cancel.hdr.hwnd = HandleToLong( win->hwnd ); cancel.hdr.opengl = win->opengl; wait_fence_and_close( fence ); - return android_ioctl( IOCTL_CANCEL_BUFFER, &cancel, sizeof(cancel), NULL, NULL ); + return android_ioctl( IOCTL_CANCEL_BUFFER, &cancel, sizeof(cancel), NULL, NULL, NULL ); } static int queueBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer, int fence ) @@ -1265,7 +1268,7 @@ static int queueBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer queue.hdr.hwnd = HandleToLong( win->hwnd ); queue.hdr.opengl = win->opengl; wait_fence_and_close( fence ); - return android_ioctl( IOCTL_QUEUE_BUFFER, &queue, sizeof(queue), NULL, NULL ); + return android_ioctl( IOCTL_QUEUE_BUFFER, &queue, sizeof(queue), NULL, NULL, NULL ); } static int dequeueBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer **buffer ) @@ -1300,7 +1303,7 @@ static int setSwapInterval( struct ANativeWindow *window, int interval ) swap.hdr.hwnd = HandleToLong( win->hwnd ); swap.hdr.opengl = win->opengl; swap.interval = interval; - return android_ioctl( IOCTL_SET_SWAP_INT, &swap, sizeof(swap), NULL, NULL ); + return android_ioctl( IOCTL_SET_SWAP_INT, &swap, sizeof(swap), NULL, NULL, NULL ); } static int query( const ANativeWindow *window, int what, int *value ) @@ -1313,7 +1316,7 @@ static int query( const ANativeWindow *window, int what, int *value ) query.hdr.hwnd = HandleToLong( win->hwnd ); query.hdr.opengl = win->opengl; query.what = what; - ret = android_ioctl( IOCTL_QUERY, &query, sizeof(query), &query, &size ); + ret = android_ioctl( IOCTL_QUERY, &query, sizeof(query), &query, &size, NULL ); TRACE( "hwnd %p what %d got %d -> %p\n", win->hwnd, what, query.value, value ); if (!ret) *value = query.value; return ret; @@ -1455,7 +1458,7 @@ static int perform( ANativeWindow *window, int operation, ... ) break; } va_end( args ); - return android_ioctl( IOCTL_PERFORM, &perf, sizeof(perf), NULL, NULL ); + return android_ioctl( IOCTL_PERFORM, &perf, sizeof(perf), NULL, NULL, NULL ); } struct ANativeWindow *create_ioctl_window( HWND hwnd, BOOL opengl ) @@ -1488,7 +1491,7 @@ struct ANativeWindow *create_ioctl_window( HWND hwnd, BOOL opengl ) req.hdr.opengl = win->opengl; req.parent = get_ioctl_win_parent( NtUserGetAncestor( hwnd, GA_PARENT )); req.is_desktop = hwnd == desktop_window; - android_ioctl( IOCTL_CREATE_WINDOW, &req, sizeof(req), NULL, NULL ); + android_ioctl( IOCTL_CREATE_WINDOW, &req, sizeof(req), NULL, NULL, NULL ); return &win->win; } @@ -1521,7 +1524,7 @@ void destroy_ioctl_window( HWND hwnd, BOOL opengl ) req.hdr.hwnd = HandleToLong( hwnd ); req.hdr.opengl = opengl; - android_ioctl( IOCTL_DESTROY_WINDOW, &req, sizeof(req), NULL, NULL ); + android_ioctl( IOCTL_DESTROY_WINDOW, &req, sizeof(req), NULL, NULL, NULL ); } int ioctl_window_pos_changed( HWND hwnd, const struct window_rects *rects, @@ -1538,7 +1541,7 @@ int ioctl_window_pos_changed( HWND hwnd, const struct window_rects *rects, req.flags = flags; req.after = HandleToLong( after ); req.owner = HandleToLong( owner ); - return android_ioctl( IOCTL_WINDOW_POS_CHANGED, &req, sizeof(req), NULL, NULL ); + return android_ioctl( IOCTL_WINDOW_POS_CHANGED, &req, sizeof(req), NULL, NULL, NULL ); } int ioctl_set_window_parent( HWND hwnd, HWND parent ) @@ -1548,7 +1551,7 @@ int ioctl_set_window_parent( HWND hwnd, HWND parent ) req.hdr.hwnd = HandleToLong( hwnd ); req.hdr.opengl = FALSE; req.parent = get_ioctl_win_parent( parent ); - return android_ioctl( IOCTL_SET_WINDOW_PARENT, &req, sizeof(req), NULL, NULL ); + return android_ioctl( IOCTL_SET_WINDOW_PARENT, &req, sizeof(req), NULL, NULL, NULL ); } int ioctl_set_capture( HWND hwnd ) @@ -1557,7 +1560,7 @@ int ioctl_set_capture( HWND hwnd ) req.hdr.hwnd = HandleToLong( hwnd ); req.hdr.opengl = FALSE; - return android_ioctl( IOCTL_SET_CAPTURE, &req, sizeof(req), NULL, NULL ); + return android_ioctl( IOCTL_SET_CAPTURE, &req, sizeof(req), NULL, NULL, NULL ); } int ioctl_set_cursor( int id, int width, int height, @@ -1576,7 +1579,7 @@ int ioctl_set_cursor( int id, int width, int height, req->hotspotx = hotspotx; req->hotspoty = hotspoty; memcpy( req->bits, bits, width * height * sizeof(req->bits[0]) ); - ret = android_ioctl( IOCTL_SET_CURSOR, req, size, NULL, NULL ); + ret = android_ioctl( IOCTL_SET_CURSOR, req, size, NULL, NULL, NULL ); free( req ); return ret; } diff --git a/dlls/wineandroid.drv/dllmain.c b/dlls/wineandroid.drv/dllmain.c index 7f6d04e83df..d1775c4f4e4 100644 --- a/dlls/wineandroid.drv/dllmain.c +++ b/dlls/wineandroid.drv/dllmain.c @@ -90,13 +90,6 @@ static NTSTATUS WINAPI android_start_device(void *param, ULONG size) } -static void CALLBACK register_window_callback( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 ) -{ - struct register_window_params params = { .arg1 = arg1, .arg2 = arg2, .arg3 = arg3 }; - ANDROID_CALL( register_window, ¶ms ); -} - - /*********************************************************************** * dll initialisation routine */ @@ -109,7 +102,6 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) DisableThreadLibraryCalls( inst ); if (__wine_init_unix_call()) return FALSE; - params.register_window_callback = register_window_callback; params.start_device_callback = (UINT_PTR)android_start_device; return !ANDROID_CALL( init, ¶ms ); } diff --git a/dlls/wineandroid.drv/init.c b/dlls/wineandroid.drv/init.c index e8cb360d032..f4faaca2216 100644 --- a/dlls/wineandroid.drv/init.c +++ b/dlls/wineandroid.drv/init.c @@ -48,7 +48,6 @@ static const unsigned int screen_bpp = 32; /* we don't support other modes */ static RECT monitor_rc_work; static int device_init_done; -PNTAPCFUNC register_window_callback; UINT64 start_device_callback; typedef struct @@ -394,7 +393,6 @@ static HRESULT android_init( void *arg ) pthread_mutex_init( &win_data_mutex, &attr ); pthread_mutexattr_destroy( &attr ); - register_window_callback = params->register_window_callback; start_device_callback = params->start_device_callback; if ((java_vm = *p_java_vm)) /* running under Java */ @@ -423,7 +421,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = android_init, android_java_init, android_java_uninit, - android_register_window, }; diff --git a/dlls/wineandroid.drv/unixlib.h b/dlls/wineandroid.drv/unixlib.h index 39a4df58283..bc15911ebd9 100644 --- a/dlls/wineandroid.drv/unixlib.h +++ b/dlls/wineandroid.drv/unixlib.h @@ -25,7 +25,6 @@ enum android_funcs unix_init, unix_java_init, unix_java_uninit, - unix_register_window, unix_funcs_count }; @@ -34,15 +33,5 @@ enum android_funcs /* android_init params */ struct init_params { - PNTAPCFUNC register_window_callback; UINT64 start_device_callback; }; - - -/* android_register_window params */ -struct register_window_params -{ - UINT_PTR arg1; - UINT_PTR arg2; - UINT_PTR arg3; -}; diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index 97eb3004ba8..3c6a32a08a7 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -251,6 +251,7 @@ void surface_changed( JNIEnv *env, jobject obj, jint win, jobject surface, jbool data.surface.height = height; p__android_log_print( ANDROID_LOG_INFO, "wine", "surface_changed: %p %s %ux%u", data.surface.hwnd, client ? "client" : "whole", width, height ); + register_native_window( data.surface.hwnd, data.surface.window, data.surface.client ); } data.type = SURFACE_CHANGED; send_event( &data ); @@ -456,7 +457,7 @@ static int process_events( DWORD mask ) event->data.surface.window, event->data.surface.client ? "client" : "whole", event->data.surface.width, event->data.surface.height ); - register_native_window( event->data.surface.hwnd, event->data.surface.window, event->data.surface.client ); + NtUserPostMessage( event->data.surface.hwnd, WM_ANDROID_REFRESH, event->data.surface.client, 0 ); break; case MOTION_EVENT: -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569