diff --git a/0003-pending-mrs-and-backports/7016-winex11-drv-Use-NtUserReleaseDC-with-hdc-in-X11DRV-vulkan-surface-presented-/0001-winex11-drv-Use-NtUserReleaseDC-with-hdc.patch b/0003-pending-mrs-and-backports/7016-winex11-drv-Use-NtUserReleaseDC-with-hdc-in-X11DRV-vulkan-surface-presented-/0001-winex11-drv-Use-NtUserReleaseDC-with-hdc.patch new file mode 100644 index 0000000..87efc3d --- /dev/null +++ b/0003-pending-mrs-and-backports/7016-winex11-drv-Use-NtUserReleaseDC-with-hdc-in-X11DRV-vulkan-surface-presented-/0001-winex11-drv-Use-NtUserReleaseDC-with-hdc.patch @@ -0,0 +1,39 @@ +From 6a2af9fc9415a13e82155d96eea3a9440d593fcd Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Fri, 13 Dec 2024 19:28:43 -0600 +Subject: [PATCH] winex11.drv: Use NtUserReleaseDC() with hdc. + +--- + dlls/winex11.drv/init.c | 2 +- + dlls/winex11.drv/vulkan.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c +index ddb8101a2f7..fca673fb825 100644 +--- a/dlls/winex11.drv/init.c ++++ b/dlls/winex11.drv/init.c +@@ -215,7 +215,7 @@ static BOOL needs_client_window_clipping( HWND hwnd ) + if (ret == SIMPLEREGION && EqualRect( &rect, &client )) ret = 0; + NtGdiDeleteObjectApp( region ); + } +- NtGdiDeleteObjectApp( hdc ); ++ NtUserReleaseDC( hwnd, hdc ); + + return ret > 0; + } +diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c +index 12f51fdcefd..855dddba440 100644 +--- a/dlls/winex11.drv/vulkan.c ++++ b/dlls/winex11.drv/vulkan.c +@@ -246,7 +246,7 @@ static void X11DRV_vulkan_surface_presented( HWND hwnd, void *private, VkResult + surface->hdc_src, 0, 0, surface->rect.right, surface->rect.bottom, SRCCOPY, 0 ); + + if (region) NtGdiDeleteObjectApp( region ); +- if (hdc) NtGdiDeleteObjectApp( hdc ); ++ if (hdc) NtUserReleaseDC( hwnd, hdc ); + } + + static VkBool32 X11DRV_vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice phys_dev, +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/7018-Revert-wined3d-Use-bindless-textures-for-GLSL-shaders-if-possible-/0001-Revert-wined3d-Use-bindless-textures-for-GLSL-shaders-if-possible-.patch b/0003-pending-mrs-and-backports/7018-Revert-wined3d-Use-bindless-textures-for-GLSL-shaders-if-possible-/0001-Revert-wined3d-Use-bindless-textures-for-GLSL-shaders-if-possible-.patch new file mode 100644 index 0000000..c0957c0 --- /dev/null +++ b/0003-pending-mrs-and-backports/7018-Revert-wined3d-Use-bindless-textures-for-GLSL-shaders-if-possible-/0001-Revert-wined3d-Use-bindless-textures-for-GLSL-shaders-if-possible-.patch @@ -0,0 +1,529 @@ +From 77e8366287bac3c607bbc08c6684187d0fa802eb Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura +Date: Sat, 14 Dec 2024 12:35:38 -0600 +Subject: [PATCH] Revert "wined3d: Use bindless textures for GLSL shaders if + possible." + +This reverts commit f6a1844dbed91b441ad69e7b15b5be242d063e87. + +The use of bindless textures results in several bugs. Some appear to be our +bugs; at least some of these would require us to attempt to keep textures +nonresident when not used, and others have not yet been debugged. Some appear to +be driver bugs or at least exacerbations of existing bugs that are not really +fixable. + +At the same time, separate samplers are a d3d10-level feature, and any +d3d10-level GPU should be capable of supporting Vulkan, which does not use +combined samplers. The Vulkan renderer does not suffer from the problem that the +GL renderer does in this case. + +Put another way, any application that is helped by the original commit should +also be helped by the Vulkan renderer, and if the application in question is +capable of running on a given GPU in the first place then the GPU should in +practice support Vulkan. + +The original commit fixed a clear and definite bug, and thus this revert +reintroduces regressions in some applications, while fixing regressions in +others. The long-term fix for these regressions is to finish the Vulkan renderer +and default to it where possible. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56474 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56523 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56605 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56627 +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57409 +--- + dlls/d3d11/tests/d3d11.c | 4 +-- + dlls/wined3d/adapter_gl.c | 15 -------- + dlls/wined3d/context_gl.c | 38 ++------------------- + dlls/wined3d/device.c | 24 ------------- + dlls/wined3d/glsl_shader.c | 70 +------------------------------------- + dlls/wined3d/texture.c | 20 ++++------- + dlls/wined3d/view.c | 39 --------------------- + dlls/wined3d/wined3d_gl.h | 22 ------------ + 8 files changed, 12 insertions(+), 220 deletions(-) + +diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c +index 6d9ad491716..9c5b35faafa 100644 +--- a/dlls/d3d11/tests/d3d11.c ++++ b/dlls/d3d11/tests/d3d11.c +@@ -36183,7 +36183,7 @@ static void test_high_resource_count(void) + ID3D11DeviceContext_PSSetSamplers(context, 0, 2, samplers); + draw_quad(&test_context); + +- check_texture_vec4(rt, &expect, 0); ++ todo_wine_if (!damavand) check_texture_vec4(rt, &expect, 0); + + /* Discard the data in one of the buffers and draw again. */ + +@@ -36195,7 +36195,7 @@ static void test_high_resource_count(void) + ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)buffers[1], 0); + draw_quad(&test_context); + +- check_texture_vec4(rt, &expect2, 0); ++ todo_wine_if (!damavand) check_texture_vec4(rt, &expect2, 0); + + ID3D11Texture2D_Release(rt); + ID3D11RenderTargetView_Release(rtv); +diff --git a/dlls/wined3d/adapter_gl.c b/dlls/wined3d/adapter_gl.c +index c2803379347..1bbafc7957e 100644 +--- a/dlls/wined3d/adapter_gl.c ++++ b/dlls/wined3d/adapter_gl.c +@@ -57,7 +57,6 @@ static const struct wined3d_extension_map gl_extension_map[] = + + /* ARB */ + {"GL_ARB_base_instance", ARB_BASE_INSTANCE }, +- {"GL_ARB_bindless_texture", ARB_BINDLESS_TEXTURE }, + {"GL_ARB_blend_func_extended", ARB_BLEND_FUNC_EXTENDED }, + {"GL_ARB_buffer_storage", ARB_BUFFER_STORAGE }, + {"GL_ARB_clear_buffer_object", ARB_CLEAR_BUFFER_OBJECT }, +@@ -2048,12 +2047,6 @@ static void load_gl_funcs(struct wined3d_gl_info *gl_info) + /* GL_ARB_base_instance */ + USE_GL_FUNC(glDrawArraysInstancedBaseInstance) + USE_GL_FUNC(glDrawElementsInstancedBaseVertexBaseInstance) +- /* GL_ARB_bindless_texture */ +- USE_GL_FUNC(glGetTextureHandleARB) +- USE_GL_FUNC(glGetTextureSamplerHandleARB) +- USE_GL_FUNC(glIsTextureHandleResidentARB) +- USE_GL_FUNC(glMakeTextureHandleResidentARB) +- USE_GL_FUNC(glUniformHandleui64ARB) + /* GL_ARB_blend_func_extended */ + USE_GL_FUNC(glBindFragDataLocationIndexed) + USE_GL_FUNC(glGetFragDataIndex) +@@ -3540,14 +3533,6 @@ static BOOL wined3d_adapter_init_gl_caps(struct wined3d_adapter_gl *adapter_gl, + /* GL_ARB_half_float_vertex is a subset of GL_NV_half_float. */ + gl_info->supported[ARB_HALF_FLOAT_VERTEX] = TRUE; + } +- if (wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL) +- { +- /* ARB_bindless_texture does not let us use EXT_texture_sRGB_decode. +- * We could use ARB_texture_view, but the main reason to use bindless +- * textures is to avoid GL_MAX_TEXTURE_IMAGE_UNITS, so there's not much +- * point. */ +- gl_info->supported[ARB_BINDLESS_TEXTURE] = FALSE; +- } + if (gl_info->supported[ARB_FRAMEBUFFER_SRGB] && !gl_info->supported[EXT_TEXTURE_SRGB_DECODE]) + { + /* Current wined3d sRGB infrastructure requires EXT_texture_sRGB_decode +diff --git a/dlls/wined3d/context_gl.c b/dlls/wined3d/context_gl.c +index 46bb3f9f365..e150e2bdec6 100644 +--- a/dlls/wined3d/context_gl.c ++++ b/dlls/wined3d/context_gl.c +@@ -2552,37 +2552,6 @@ void wined3d_context_gl_bind_texture(struct wined3d_context_gl *context_gl, GLen + checkGLcall("bind texture"); + } + +-GLuint64 wined3d_device_gl_get_dummy_bindless_handle(const struct wined3d_device_gl *device_gl, +- enum wined3d_shader_resource_type type) +-{ +- switch (type) +- { +- case WINED3D_SHADER_RESOURCE_BUFFER: +- return device_gl->dummy_textures.bindless.tex_buffer; +- case WINED3D_SHADER_RESOURCE_TEXTURE_1D: +- return device_gl->dummy_textures.bindless.tex_1d; +- case WINED3D_SHADER_RESOURCE_TEXTURE_2D: +- return device_gl->dummy_textures.bindless.tex_2d; +- case WINED3D_SHADER_RESOURCE_TEXTURE_3D: +- return device_gl->dummy_textures.bindless.tex_3d; +- case WINED3D_SHADER_RESOURCE_TEXTURE_CUBE: +- return device_gl->dummy_textures.bindless.tex_cube; +- case WINED3D_SHADER_RESOURCE_TEXTURE_1DARRAY: +- return device_gl->dummy_textures.bindless.tex_1d_array; +- case WINED3D_SHADER_RESOURCE_TEXTURE_2DARRAY: +- return device_gl->dummy_textures.bindless.tex_2d_array; +- case WINED3D_SHADER_RESOURCE_TEXTURE_CUBEARRAY: +- return device_gl->dummy_textures.bindless.tex_cube_array; +- case WINED3D_SHADER_RESOURCE_TEXTURE_2DMS: +- return device_gl->dummy_textures.bindless.tex_2d_ms; +- case WINED3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY: +- return device_gl->dummy_textures.bindless.tex_2d_ms_array; +- default: +- FIXME("Unhandled resource type %#x.\n", type); +- return 0; +- } +-} +- + static void wined3d_context_gl_poll_fences(struct wined3d_context_gl *context_gl) + { + struct wined3d_device_gl *device_gl = wined3d_device_gl(context_gl->c.device); +@@ -3803,9 +3772,6 @@ static void wined3d_context_gl_bind_shader_resources(struct wined3d_context_gl * + return; + } + +- if (gl_info->supported[ARB_BINDLESS_TEXTURE]) +- return; +- + tex_unit_map = wined3d_context_gl_get_tex_unit_mapping(context_gl, + &shader->reg_maps.shader_version, &base, &count); + +@@ -4167,6 +4133,7 @@ static BOOL context_apply_draw_state(struct wined3d_context *context, + { + for (i = 0; i < WINED3D_SHADER_TYPE_GRAPHICS_COUNT; ++i) + wined3d_context_gl_bind_shader_resources(context_gl, state, i); ++ context->update_shader_resource_bindings = 0; + if (gl_info->limits.combined_samplers == gl_info->limits.graphics_samplers) + context->update_compute_shader_resource_bindings = 1; + } +@@ -4185,7 +4152,6 @@ static BOOL context_apply_draw_state(struct wined3d_context *context, + device->shader_backend->shader_apply_draw_state(device->shader_priv, context, state); + context->shader_update_mask &= 1u << WINED3D_SHADER_TYPE_COMPUTE; + context->constant_update_mask = 0; +- context->update_shader_resource_bindings = 0; + + context->last_was_blit = FALSE; + context->last_was_ffp_blit = FALSE; +@@ -4222,6 +4188,7 @@ static void wined3d_context_gl_apply_compute_state(struct wined3d_context_gl *co + if (context_gl->c.update_compute_shader_resource_bindings) + { + wined3d_context_gl_bind_shader_resources(context_gl, state, WINED3D_SHADER_TYPE_COMPUTE); ++ context_gl->c.update_compute_shader_resource_bindings = 0; + if (gl_info->limits.combined_samplers == gl_info->limits.graphics_samplers) + context_gl->c.update_shader_resource_bindings = 1; + } +@@ -4248,7 +4215,6 @@ static void wined3d_context_gl_apply_compute_state(struct wined3d_context_gl *co + context_gl->c.last_was_blit = FALSE; + context_gl->c.last_was_ffp_blit = FALSE; + context_gl->c.shader_update_mask &= ~(1u << WINED3D_SHADER_TYPE_COMPUTE); +- context_gl->c.update_compute_shader_resource_bindings = 0; + } + + void wined3d_context_gl_end_transform_feedback(struct wined3d_context_gl *context_gl) +diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c +index 7e24de8afb3..503b377662a 100644 +--- a/dlls/wined3d/device.c ++++ b/dlls/wined3d/device.c +@@ -568,18 +568,6 @@ out: + if (hbm) DeleteObject(hbm); + } + +-static GLuint64 create_dummy_bindless_handle(const struct wined3d_gl_info *gl_info, GLuint texture) +-{ +- GLuint64 handle; +- +- if (!texture || !gl_info->supported[ARB_BINDLESS_TEXTURE]) +- return 0; +- +- handle = GL_EXTCALL(glGetTextureHandleARB(texture)); +- GL_EXTCALL(glMakeTextureHandleResidentARB(handle)); +- return handle; +-} +- + /* Context activation is done by the caller. */ + static void wined3d_device_gl_create_dummy_textures(struct wined3d_device_gl *device_gl, + struct wined3d_context_gl *context_gl) +@@ -701,18 +689,6 @@ static void wined3d_device_gl_create_dummy_textures(struct wined3d_device_gl *de + } + } + +- textures->bindless.tex_1d = create_dummy_bindless_handle(gl_info, textures->tex_1d); +- textures->bindless.tex_2d = create_dummy_bindless_handle(gl_info, textures->tex_2d); +- textures->bindless.tex_rect = create_dummy_bindless_handle(gl_info, textures->tex_rect); +- textures->bindless.tex_3d = create_dummy_bindless_handle(gl_info, textures->tex_3d); +- textures->bindless.tex_cube = create_dummy_bindless_handle(gl_info, textures->tex_cube); +- textures->bindless.tex_cube_array = create_dummy_bindless_handle(gl_info, textures->tex_cube_array); +- textures->bindless.tex_1d_array = create_dummy_bindless_handle(gl_info, textures->tex_1d_array); +- textures->bindless.tex_2d_array = create_dummy_bindless_handle(gl_info, textures->tex_2d_array); +- textures->bindless.tex_buffer = create_dummy_bindless_handle(gl_info, textures->tex_buffer); +- textures->bindless.tex_2d_ms = create_dummy_bindless_handle(gl_info, textures->tex_2d_ms); +- textures->bindless.tex_2d_ms_array = create_dummy_bindless_handle(gl_info, textures->tex_2d_ms_array); +- + checkGLcall("create dummy textures"); + + wined3d_context_gl_bind_dummy_textures(context_gl); +diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c +index 61b53da540a..5856aae5447 100644 +--- a/dlls/wined3d/glsl_shader.c ++++ b/dlls/wined3d/glsl_shader.c +@@ -2611,9 +2611,7 @@ static void shader_generate_glsl_declarations(const struct wined3d_context_gl *c + break; + } + +- if (gl_info->supported[ARB_BINDLESS_TEXTURE]) +- shader_addline(buffer, "layout(bindless_sampler) "); +- else if (shader_glsl_use_layout_binding_qualifier(gl_info)) ++ if (shader_glsl_use_layout_binding_qualifier(gl_info)) + shader_glsl_append_sampler_binding_qualifier(buffer, &context_gl->c, version, entry->bind_idx); + shader_addline(buffer, "uniform %s%s %s_sampler%u;\n", + sampler_type_prefix, sampler_type, prefix, entry->bind_idx); +@@ -7710,8 +7708,6 @@ static void shader_glsl_generate_colour_key_test(struct wined3d_string_buffer *b + static void shader_glsl_enable_extensions(struct wined3d_string_buffer *buffer, + const struct wined3d_gl_info *gl_info) + { +- if (gl_info->supported[ARB_BINDLESS_TEXTURE]) +- shader_addline(buffer, "#extension GL_ARB_bindless_texture : enable\n"); + if (gl_info->supported[ARB_CULL_DISTANCE]) + shader_addline(buffer, "#extension GL_ARB_cull_distance : enable\n"); + if (gl_info->supported[ARB_GPU_SHADER5]) +@@ -9814,7 +9810,6 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct shader_glsl_priv * + } + if (sampler_type) + { +- /* We don't use bindless samplers for FFP shaders. */ + if (shader_glsl_use_layout_binding_qualifier(gl_info)) + shader_glsl_append_sampler_binding_qualifier(buffer, &context_gl->c, NULL, stage); + shader_addline(buffer, "uniform sampler%s ps_sampler%u;\n", sampler_type, stage); +@@ -10884,60 +10879,6 @@ static void shader_glsl_update_graphics_program(struct shader_glsl_priv *priv, + context_gl->c.shader_update_mask |= (1u << WINED3D_SHADER_TYPE_COMPUTE); + } + +-static void shader_glsl_load_bindless_samplers(struct shader_glsl_priv *priv, struct wined3d_context_gl *context_gl, +- const struct wined3d_state *state, enum wined3d_shader_type shader_type) +-{ +- const struct wined3d_device_gl *device_gl = wined3d_device_gl(context_gl->c.device); +- const struct glsl_context_data *ctx_data = context_gl->c.shader_backend_data; +- const struct wined3d_shader *shader = state->shader[shader_type]; +- const struct wined3d_gl_info *gl_info = context_gl->gl_info; +- const char *prefix = shader_glsl_get_prefix(shader_type); +- struct wined3d_string_buffer *sampler_name; +- +- /* Note that we don't use bindless samplers for FFP shaders. */ +- if (!shader) +- return; +- +- sampler_name = string_buffer_get(&priv->string_buffers); +- +- for (unsigned int i = 0; i < shader->reg_maps.sampler_map.count; ++i) +- { +- const struct wined3d_shader_sampler_map_entry *entry = &shader->reg_maps.sampler_map.entries[i]; +- struct wined3d_shader_resource_view *view; +- struct wined3d_sampler *sampler; +- GLuint64 handle; +- GLint name_loc; +- +- /* No need to bother with the texture unit map; we're binding directly to uniforms. */ +- +- string_buffer_sprintf(sampler_name, "%s_sampler%u", prefix, entry->bind_idx); +- name_loc = GL_EXTCALL(glGetUniformLocation(ctx_data->glsl_program->id, sampler_name->buffer)); +- if (name_loc == -1) +- continue; +- +- if ((view = state->shader_resource_view[shader_type][entry->resource_idx])) +- { +- if (entry->sampler_idx == WINED3D_SAMPLER_DEFAULT) +- sampler = device_gl->d.default_sampler; +- else if (!(sampler = state->sampler[shader_type][entry->sampler_idx])) +- sampler = device_gl->d.null_sampler; +- +- handle = wined3d_shader_resource_view_gl_get_bindless_handle( +- wined3d_shader_resource_view_gl(view), wined3d_sampler_gl(sampler), context_gl); +- } +- else +- { +- WARN("No resource view bound at index %u, %u.\n", shader_type, entry->resource_idx); +- handle = wined3d_device_gl_get_dummy_bindless_handle(device_gl, +- shader->reg_maps.resource_info[entry->resource_idx].type); +- } +- GL_EXTCALL(glUniformHandleui64ARB(name_loc, handle)); +- checkGLcall("glUniformHandleui64ARB"); +- } +- +- string_buffer_release(&priv->string_buffers, sampler_name); +-} +- + static void shader_glsl_apply_draw_state(void *shader_priv, struct wined3d_context *context, + const struct wined3d_state *state) + { +@@ -10949,12 +10890,6 @@ static void shader_glsl_apply_draw_state(void *shader_priv, struct wined3d_conte + + if (context->constant_update_mask) + shader_glsl_load_constants(priv, context, state); +- +- if (context->update_shader_resource_bindings && context_gl->gl_info->supported[ARB_BINDLESS_TEXTURE]) +- { +- for (unsigned int type = 0; type < WINED3D_SHADER_TYPE_GRAPHICS_COUNT; ++type) +- shader_glsl_load_bindless_samplers(priv, context_gl, state, type); +- } + } + + static void shader_glsl_update_compute_program(struct shader_glsl_priv *priv, +@@ -10991,9 +10926,6 @@ static void shader_glsl_apply_compute_state(void *shader_priv, struct wined3d_co + + if (context_gl->c.shader_update_mask & (1u << WINED3D_SHADER_TYPE_COMPUTE)) + shader_glsl_update_compute_program(priv, context_gl, state); +- +- if (context->update_compute_shader_resource_bindings && context_gl->gl_info->supported[ARB_BINDLESS_TEXTURE]) +- shader_glsl_load_bindless_samplers(priv, context_gl, state, WINED3D_SHADER_TYPE_COMPUTE); + } + + /* "context" is not necessarily the currently active context. */ +diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c +index 27fedf4db67..5061f0033fd 100644 +--- a/dlls/wined3d/texture.c ++++ b/dlls/wined3d/texture.c +@@ -1285,8 +1285,8 @@ void wined3d_gl_texture_swizzle_from_color_fixup(GLint swizzle[4], struct color_ + } + + /* Context activation is done by the caller. */ +-GLuint wined3d_texture_gl_prepare_gl_texture(struct wined3d_texture_gl *texture_gl, +- struct wined3d_context_gl *context_gl, BOOL srgb) ++void wined3d_texture_gl_bind(struct wined3d_texture_gl *texture_gl, ++ struct wined3d_context_gl *context_gl, BOOL srgb) + { + const struct wined3d_format *format = texture_gl->t.resource.format; + const struct wined3d_gl_info *gl_info = context_gl->gl_info; +@@ -1309,7 +1309,10 @@ GLuint wined3d_texture_gl_prepare_gl_texture(struct wined3d_texture_gl *texture_ + target = texture_gl->target; + + if (gl_tex->name) +- return gl_tex->name; ++ { ++ wined3d_context_gl_bind_texture(context_gl, target, gl_tex->name); ++ return; ++ } + + gl_info->gl_ops.gl.p_glGenTextures(1, &gl_tex->name); + checkGLcall("glGenTextures"); +@@ -1318,7 +1321,7 @@ GLuint wined3d_texture_gl_prepare_gl_texture(struct wined3d_texture_gl *texture_ + if (!gl_tex->name) + { + ERR("Failed to generate a texture name.\n"); +- return 0; ++ return; + } + + /* Initialise the state of the texture object to the OpenGL defaults, not +@@ -1396,8 +1399,6 @@ GLuint wined3d_texture_gl_prepare_gl_texture(struct wined3d_texture_gl *texture_ + gl_info->gl_ops.gl.p_glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle); + checkGLcall("set format swizzle"); + } +- +- return gl_tex->name; + } + + /* Context activation is done by the caller. */ +@@ -1412,13 +1413,6 @@ void wined3d_texture_gl_bind_and_dirtify(struct wined3d_texture_gl *texture_gl, + wined3d_texture_gl_bind(texture_gl, context_gl, srgb); + } + +-void wined3d_texture_gl_bind(struct wined3d_texture_gl *texture_gl, +- struct wined3d_context_gl *context_gl, BOOL srgb) +-{ +- wined3d_context_gl_bind_texture(context_gl, texture_gl->target, +- wined3d_texture_gl_prepare_gl_texture(texture_gl, context_gl, srgb)); +-} +- + /* Context activation is done by the caller (state handler). */ + /* This function relies on the correct texture being bound and loaded. */ + void wined3d_texture_gl_apply_sampler_desc(struct wined3d_texture_gl *texture_gl, +diff --git a/dlls/wined3d/view.c b/dlls/wined3d/view.c +index 91b88c2037d..c72e5044d04 100644 +--- a/dlls/wined3d/view.c ++++ b/dlls/wined3d/view.c +@@ -270,14 +270,6 @@ static void create_buffer_texture(struct wined3d_gl_view *view, struct wined3d_c + { + gl_info->gl_ops.gl.p_glGenTextures(1, &view->name); + } +- else if (gl_info->supported[ARB_BINDLESS_TEXTURE]) +- { +- /* If we already bound this view to a shader, we acquired a handle to +- * it, and it's now immutable. This means we can't bind a new buffer +- * storage to it, so recreate the texture. */ +- gl_info->gl_ops.gl.p_glDeleteTextures(1, &view->name); +- gl_info->gl_ops.gl.p_glGenTextures(1, &view->name); +- } + + wined3d_context_gl_bind_texture(context_gl, GL_TEXTURE_BUFFER, view->name); + if (gl_info->supported[ARB_TEXTURE_BUFFER_RANGE]) +@@ -1317,37 +1309,6 @@ static void shader_resource_view_gl_bind_and_dirtify(struct wined3d_shader_resou + wined3d_context_gl_bind_texture(context_gl, view_gl->gl_view.target, view_gl->gl_view.name); + } + +-GLuint64 wined3d_shader_resource_view_gl_get_bindless_handle(struct wined3d_shader_resource_view_gl *view_gl, +- struct wined3d_sampler_gl *sampler_gl, struct wined3d_context_gl *context_gl) +-{ +- const struct wined3d_gl_info *gl_info = context_gl->gl_info; +- GLuint64 handle; +- GLuint name; +- +- if (view_gl->gl_view.name) +- { +- name = view_gl->gl_view.name; +- } +- else if (view_gl->v.resource->type == WINED3D_RTYPE_BUFFER) +- { +- FIXME("Buffer shader resources not supported.\n"); +- return 0; +- } +- else +- { +- struct wined3d_texture_gl *texture_gl = wined3d_texture_gl(wined3d_texture_from_resource(view_gl->v.resource)); +- name = wined3d_texture_gl_prepare_gl_texture(texture_gl, context_gl, FALSE); +- } +- +- handle = GL_EXTCALL(glGetTextureSamplerHandleARB(name, sampler_gl->name)); +- checkGLcall("glGetTextureSamplerHandleARB"); +- /* It is an error to make a handle resident if it is already resident. */ +- if (!GL_EXTCALL(glIsTextureHandleResidentARB(handle))) +- GL_EXTCALL(glMakeTextureHandleResidentARB(handle)); +- checkGLcall("glMakeTextureHandleResidentARB"); +- return handle; +-} +- + void wined3d_shader_resource_view_gl_generate_mipmap(struct wined3d_shader_resource_view_gl *view_gl, + struct wined3d_context_gl *context_gl) + { +diff --git a/dlls/wined3d/wined3d_gl.h b/dlls/wined3d/wined3d_gl.h +index 039f652adb9..24d7ebf663b 100644 +--- a/dlls/wined3d/wined3d_gl.h ++++ b/dlls/wined3d/wined3d_gl.h +@@ -51,7 +51,6 @@ enum wined3d_gl_extension + APPLE_YCBCR_422, + /* ARB */ + ARB_BASE_INSTANCE, +- ARB_BINDLESS_TEXTURE, + ARB_BLEND_FUNC_EXTENDED, + ARB_BUFFER_STORAGE, + ARB_CLEAR_BUFFER_OBJECT, +@@ -841,21 +840,6 @@ struct wined3d_dummy_textures + GLuint tex_buffer; + GLuint tex_2d_ms; + GLuint tex_2d_ms_array; +- +- struct +- { +- GLuint64 tex_1d; +- GLuint64 tex_2d; +- GLuint64 tex_rect; +- GLuint64 tex_3d; +- GLuint64 tex_cube; +- GLuint64 tex_cube_array; +- GLuint64 tex_1d_array; +- GLuint64 tex_2d_array; +- GLuint64 tex_buffer; +- GLuint64 tex_2d_ms; +- GLuint64 tex_2d_ms_array; +- } bindless; + }; + + struct wined3d_device_gl +@@ -919,8 +903,6 @@ bool wined3d_device_gl_create_bo(struct wined3d_device_gl *device_gl, + void wined3d_device_gl_create_primary_opengl_context_cs(void *object); + void wined3d_device_gl_delete_opengl_contexts_cs(void *object); + HDC wined3d_device_gl_get_backup_dc(struct wined3d_device_gl *device_gl); +-GLuint64 wined3d_device_gl_get_dummy_bindless_handle(const struct wined3d_device_gl *device_gl, +- enum wined3d_shader_resource_type type); + GLbitfield wined3d_device_gl_get_memory_type_flags(unsigned int memory_type_idx); + + GLbitfield wined3d_resource_gl_map_flags(const struct wined3d_bo_gl *bo, DWORD d3d_flags); +@@ -1037,8 +1019,6 @@ void wined3d_texture_gl_bind_and_dirtify(struct wined3d_texture_gl *texture_gl, + HRESULT wined3d_texture_gl_init(struct wined3d_texture_gl *texture_gl, struct wined3d_device *device, + const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count, + uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops); +-GLuint wined3d_texture_gl_prepare_gl_texture(struct wined3d_texture_gl *texture_gl, +- struct wined3d_context_gl *context_gl, BOOL srgb); + void wined3d_texture_gl_prepare_texture(struct wined3d_texture_gl *texture_gl, + struct wined3d_context_gl *context_gl, BOOL srgb); + void wined3d_texture_gl_set_compatible_renderbuffer(struct wined3d_texture_gl *texture_gl, +@@ -1113,8 +1093,6 @@ void wined3d_shader_resource_view_gl_bind(struct wined3d_shader_resource_view_gl + struct wined3d_sampler_gl *sampler_gl, struct wined3d_context_gl *context_gl); + void wined3d_shader_resource_view_gl_generate_mipmap(struct wined3d_shader_resource_view_gl *srv_gl, + struct wined3d_context_gl *context_gl); +-GLuint64 wined3d_shader_resource_view_gl_get_bindless_handle(struct wined3d_shader_resource_view_gl *view_gl, +- struct wined3d_sampler_gl *sampler_gl, struct wined3d_context_gl *context_gl); + HRESULT wined3d_shader_resource_view_gl_init(struct wined3d_shader_resource_view_gl *view_gl, + const struct wined3d_view_desc *desc, struct wined3d_resource *resource, + void *parent, const struct wined3d_parent_ops *parent_ops); +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/7021-wined3d-Add-nop-state-entries-for-states-now-invalidated-on-the-client-side/0001-wined3d-Add-nop-state-entries-for-states-now-invalidated-on-the-client-side.patch b/0003-pending-mrs-and-backports/7021-wined3d-Add-nop-state-entries-for-states-now-invalidated-on-the-client-side/0001-wined3d-Add-nop-state-entries-for-states-now-invalidated-on-the-client-side.patch new file mode 100644 index 0000000..5f20e90 --- /dev/null +++ b/0003-pending-mrs-and-backports/7021-wined3d-Add-nop-state-entries-for-states-now-invalidated-on-the-client-side/0001-wined3d-Add-nop-state-entries-for-states-now-invalidated-on-the-client-side.patch @@ -0,0 +1,168 @@ +From ba2851966b4f2045f2da7bb354d5a60483b15609 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura +Date: Sat, 14 Dec 2024 17:18:07 -0600 +Subject: [PATCH] wined3d: Add nop state entries for states now invalidated on + the client side. + +9313c14c63a9b941b66ea367b72f0f928e39c68b and following commits moved invalidation to the client side of the CS, and removed the state table entries since nothing needed to be done. +However, in order to avoid errors, the state table still validates that all states have a representative, and thus complains at the missing representatives for all of these states. +Avoid this by adding state_nop entries, as is done in some other places. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57207 +--- + dlls/wined3d/ffp_gl.c | 11 +++-- + dlls/wined3d/glsl_shader.c | 92 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 99 insertions(+), 4 deletions(-) + +diff --git a/dlls/wined3d/ffp_gl.c b/dlls/wined3d/ffp_gl.c +index 20f9828d0a2..9012ba2215e 100644 +--- a/dlls/wined3d/ffp_gl.c ++++ b/dlls/wined3d/ffp_gl.c +@@ -1653,10 +1653,13 @@ static void validate_state_table(struct wined3d_state_entry *state_table) + { 11, 14}, + { 16, 23}, + { 27, 27}, +- { 29, 33}, +- { 39, 135}, +- {137, 139}, +- {141, 151}, ++ { 30, 33}, ++ { 39, 40}, ++ { 42, 47}, ++ { 49, 135}, ++ {138, 139}, ++ {144, 144}, ++ {149, 150}, + {153, 153}, + {157, 160}, + {162, 165}, +diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c +index 61b53da540a..b94ba5ac373 100644 +--- a/dlls/wined3d/glsl_shader.c ++++ b/dlls/wined3d/glsl_shader.c +@@ -12005,9 +12005,20 @@ static const struct wined3d_state_entry_template glsl_vertex_pipe_vp_states[] = + /* Viewport */ + {STATE_VIEWPORT, {STATE_VIEWPORT, glsl_vertex_pipe_viewport}, WINED3D_GL_EXT_NONE }, + /* Fog */ ++ {STATE_RENDER(WINED3D_RS_AMBIENTMATERIALSOURCE), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_RENDER(WINED3D_RS_COLORVERTEX), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_RENDER(WINED3D_RS_DIFFUSEMATERIALSOURCE), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_RENDER(WINED3D_RS_EMISSIVEMATERIALSOURCE), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, + {STATE_RENDER(WINED3D_RS_FOGENABLE), {STATE_RENDER(WINED3D_RS_FOGENABLE), state_nop }, WINED3D_GL_EXT_NONE }, + {STATE_RENDER(WINED3D_RS_FOGTABLEMODE), {STATE_RENDER(WINED3D_RS_FOGTABLEMODE), glsl_vertex_pipe_shader}, WINED3D_GL_EXT_NONE }, + {STATE_RENDER(WINED3D_RS_FOGVERTEXMODE), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_RENDER(WINED3D_RS_LIGHTING), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_RENDER(WINED3D_RS_LOCALVIEWER), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_RENDER(WINED3D_RS_NORMALIZENORMALS), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_RENDER(WINED3D_RS_RANGEFOGENABLE), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_RENDER(WINED3D_RS_SPECULARENABLE), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_RENDER(WINED3D_RS_SPECULARMATERIALSOURCE), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_RENDER(WINED3D_RS_VERTEXBLEND), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, + {STATE_RENDER(WINED3D_RS_CLIPPING), {STATE_RENDER(WINED3D_RS_CLIPPING), state_clipping }, WINED3D_GL_EXT_NONE }, + {STATE_RENDER(WINED3D_RS_CLIPPLANEENABLE), {STATE_RENDER(WINED3D_RS_CLIPPING), NULL }, WINED3D_GL_EXT_NONE }, + {STATE_RENDER(WINED3D_RS_POINTSIZE), {STATE_RENDER(WINED3D_RS_POINTSIZE_MIN), NULL }, WINED3D_GL_EXT_NONE }, +@@ -12018,6 +12029,14 @@ static const struct wined3d_state_entry_template glsl_vertex_pipe_vp_states[] = + {STATE_RENDER(WINED3D_RS_POINTSIZE_MAX), {STATE_RENDER(WINED3D_RS_POINTSIZE_MIN), NULL }, WINED3D_GL_EXT_NONE }, + {STATE_RENDER(WINED3D_RS_SHADEMODE), {STATE_RENDER(WINED3D_RS_SHADEMODE), glsl_vertex_pipe_shademode}, WINED3D_GLSL_130 }, + {STATE_RENDER(WINED3D_RS_SHADEMODE), {STATE_RENDER(WINED3D_RS_SHADEMODE), glsl_vertex_pipe_nop }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(0, WINED3D_TSS_TEXCOORD_INDEX), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(1, WINED3D_TSS_TEXCOORD_INDEX), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(2, WINED3D_TSS_TEXCOORD_INDEX), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(3, WINED3D_TSS_TEXCOORD_INDEX), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(4, WINED3D_TSS_TEXCOORD_INDEX), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(5, WINED3D_TSS_TEXCOORD_INDEX), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(6, WINED3D_TSS_TEXCOORD_INDEX), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(7, WINED3D_TSS_TEXCOORD_INDEX), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, + {0 /* Terminate */, {0, NULL }, WINED3D_GL_EXT_NONE }, + }; + +@@ -12267,6 +12286,7 @@ static const struct wined3d_state_entry_template glsl_fragment_pipe_state_templa + {STATE_RENDER(WINED3D_RS_ALPHAREF), {STATE_RENDER(WINED3D_RS_ALPHAREF), glsl_fragment_pipe_core_alpha_test_ref }, WINED3D_GL_EXT_NONE }, + {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE), {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE), glsl_fragment_pipe_alpha_test }, WINED3D_GL_LEGACY_CONTEXT}, + {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE), {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE), glsl_fragment_pipe_core_alpha_test }, WINED3D_GL_EXT_NONE }, ++ {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), state_nop }, WINED3D_GL_EXT_NONE }, + {STATE_RENDER(WINED3D_RS_FOGENABLE), {STATE_RENDER(WINED3D_RS_FOGENABLE), glsl_fragment_pipe_fog }, WINED3D_GL_EXT_NONE }, + {STATE_RENDER(WINED3D_RS_FOGTABLEMODE), {STATE_RENDER(WINED3D_RS_FOGTABLEMODE), glsl_fragment_pipe_fog }, WINED3D_GL_EXT_NONE }, + {STATE_RENDER(WINED3D_RS_FOGVERTEXMODE), {STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE }, +@@ -12278,6 +12298,78 @@ static const struct wined3d_state_entry_template glsl_fragment_pipe_state_templa + {STATE_RENDER(WINED3D_RS_FOGDENSITY), {STATE_RENDER(WINED3D_RS_FOGDENSITY), glsl_fragment_pipe_fogparams }, WINED3D_GL_EXT_NONE }, + {STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE), {STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE), glsl_fragment_pipe_shader }, ARB_POINT_SPRITE }, + {STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE), {STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE), glsl_fragment_pipe_shader }, WINED3D_GL_VERSION_2_0}, ++ {STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_ARG0), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(1, WINED3D_TSS_ALPHA_ARG0), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(2, WINED3D_TSS_ALPHA_ARG0), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(3, WINED3D_TSS_ALPHA_ARG0), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(4, WINED3D_TSS_ALPHA_ARG0), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(5, WINED3D_TSS_ALPHA_ARG0), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(6, WINED3D_TSS_ALPHA_ARG0), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_ARG0), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_ARG1), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(1, WINED3D_TSS_ALPHA_ARG1), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(2, WINED3D_TSS_ALPHA_ARG1), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(3, WINED3D_TSS_ALPHA_ARG1), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(4, WINED3D_TSS_ALPHA_ARG1), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(5, WINED3D_TSS_ALPHA_ARG1), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(6, WINED3D_TSS_ALPHA_ARG1), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_ARG1), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_ARG2), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(1, WINED3D_TSS_ALPHA_ARG2), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(2, WINED3D_TSS_ALPHA_ARG2), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(3, WINED3D_TSS_ALPHA_ARG2), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(4, WINED3D_TSS_ALPHA_ARG2), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(5, WINED3D_TSS_ALPHA_ARG2), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(6, WINED3D_TSS_ALPHA_ARG2), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_ARG2), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_OP), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(1, WINED3D_TSS_ALPHA_OP), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(2, WINED3D_TSS_ALPHA_OP), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(3, WINED3D_TSS_ALPHA_OP), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(4, WINED3D_TSS_ALPHA_OP), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(5, WINED3D_TSS_ALPHA_OP), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(6, WINED3D_TSS_ALPHA_OP), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_OP), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_ARG0), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(1, WINED3D_TSS_COLOR_ARG0), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(2, WINED3D_TSS_COLOR_ARG0), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(3, WINED3D_TSS_COLOR_ARG0), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(4, WINED3D_TSS_COLOR_ARG0), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(5, WINED3D_TSS_COLOR_ARG0), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(6, WINED3D_TSS_COLOR_ARG0), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(7, WINED3D_TSS_COLOR_ARG0), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_ARG1), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(1, WINED3D_TSS_COLOR_ARG1), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(2, WINED3D_TSS_COLOR_ARG1), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(3, WINED3D_TSS_COLOR_ARG1), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(4, WINED3D_TSS_COLOR_ARG1), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(5, WINED3D_TSS_COLOR_ARG1), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(6, WINED3D_TSS_COLOR_ARG1), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(7, WINED3D_TSS_COLOR_ARG1), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_ARG2), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(1, WINED3D_TSS_COLOR_ARG2), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(2, WINED3D_TSS_COLOR_ARG2), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(3, WINED3D_TSS_COLOR_ARG2), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(4, WINED3D_TSS_COLOR_ARG2), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(5, WINED3D_TSS_COLOR_ARG2), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(6, WINED3D_TSS_COLOR_ARG2), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(7, WINED3D_TSS_COLOR_ARG2), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(1, WINED3D_TSS_COLOR_OP), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(2, WINED3D_TSS_COLOR_OP), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(3, WINED3D_TSS_COLOR_OP), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(4, WINED3D_TSS_COLOR_OP), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(5, WINED3D_TSS_COLOR_OP), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(6, WINED3D_TSS_COLOR_OP), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(7, WINED3D_TSS_COLOR_OP), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(0, WINED3D_TSS_RESULT_ARG), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(1, WINED3D_TSS_RESULT_ARG), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(2, WINED3D_TSS_RESULT_ARG), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(3, WINED3D_TSS_RESULT_ARG), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(4, WINED3D_TSS_RESULT_ARG), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(5, WINED3D_TSS_RESULT_ARG), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(6, WINED3D_TSS_RESULT_ARG), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, ++ {STATE_TEXTURESTAGE(7, WINED3D_TSS_RESULT_ARG), {STATE_RENDER(WINED3D_RS_COLORKEYENABLE), NULL }, WINED3D_GL_EXT_NONE }, + {STATE_TEXTURESTAGE(0,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(0, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_fragment_pipe_tex_transform }, WINED3D_GL_EXT_NONE }, + {STATE_TEXTURESTAGE(1,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(1, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_fragment_pipe_tex_transform }, WINED3D_GL_EXT_NONE }, + {STATE_TEXTURESTAGE(2,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(2, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), glsl_fragment_pipe_tex_transform }, WINED3D_GL_EXT_NONE }, +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/7022-configure-Add-usr-lib64-pkgconfig-to-the-32-bit-search-path/0001-configure-Add-usr-lib64-pkgconfig-to-the-32-bit-search-path.patch b/0003-pending-mrs-and-backports/7022-configure-Add-usr-lib64-pkgconfig-to-the-32-bit-search-path/0001-configure-Add-usr-lib64-pkgconfig-to-the-32-bit-search-path.patch new file mode 100644 index 0000000..7407b87 --- /dev/null +++ b/0003-pending-mrs-and-backports/7022-configure-Add-usr-lib64-pkgconfig-to-the-32-bit-search-path/0001-configure-Add-usr-lib64-pkgconfig-to-the-32-bit-search-path.patch @@ -0,0 +1,30 @@ +From 93260362ecc1daac2c5a621ecc4e651fac787c5a Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura +Date: Sat, 14 Dec 2024 19:00:44 -0600 +Subject: [PATCH] configure: Add /usr/lib64/pkgconfig to the 32-bit search + path. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53953 +--- + configure.ac | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index 6596f653fb1..1d6a2b55b4a 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -129,7 +129,10 @@ case $host in + host_cpu="i386" + notice_platform="32-bit " + TARGETFLAGS="$TARGETFLAGS -m32" +- PKG_CONFIG_LIBDIR=${PKG_CONFIG_LIBDIR:-/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib32/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig} ++ dnl Search 64-bit directories, even though it's explicitly the wrong architecture. ++ dnl Most headers end up being identical anyway, and this allows users to not need ++ dnl to go out of their way to install the right headers. ++ PKG_CONFIG_LIBDIR=${PKG_CONFIG_LIBDIR:-/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib32/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig:/usr/lib64/pkgconfig} + export PKG_CONFIG_LIBDIR + else + CC="$CC -m64" +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/7026-win32u-Always-update-the-surface-region-when-the-surface-changes/0001-win32u-Always-update-the-surface-region-when-the-surface-changes.patch b/0003-pending-mrs-and-backports/7026-win32u-Always-update-the-surface-region-when-the-surface-changes/0001-win32u-Always-update-the-surface-region-when-the-surface-changes.patch new file mode 100644 index 0000000..5b9a370 --- /dev/null +++ b/0003-pending-mrs-and-backports/7026-win32u-Always-update-the-surface-region-when-the-surface-changes/0001-win32u-Always-update-the-surface-region-when-the-surface-changes.patch @@ -0,0 +1,40 @@ +From d5f8bedec11d7d72e8312bc1302aad943f0bd054 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Mon, 16 Dec 2024 11:19:14 +0100 +Subject: [PATCH] win32u: Always update the surface region when the surface + changes. + +Instead of reapplying the old shape, which not only includes the window +shape but also the old clipping and visible areas that can change +independently. + +Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57551 +--- + dlls/win32u/window.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c +index 4855555d926..d8974501adb 100644 +--- a/dlls/win32u/window.c ++++ b/dlls/win32u/window.c +@@ -2066,7 +2066,7 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru + old_surface = win->surface; + if (old_surface != new_surface) + { +- if (old_surface && new_surface) window_surface_set_shape( new_surface, old_surface->shape_region ); ++ needs_update = TRUE; /* force refreshing the window surface shape */ + swp_flags |= SWP_FRAMECHANGED; /* force refreshing non-client area */ + } + +@@ -2112,7 +2112,7 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru + win->rects = *new_rects; + if ((win->surface = new_surface)) window_surface_add_ref( win->surface ); + surface_win = wine_server_ptr_handle( reply->surface_win ); +- needs_update = reply->needs_update; ++ if (!needs_update) needs_update = reply->needs_update; + if (get_window_long( win->parent, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL) + { + RECT client = {0}; +-- +GitLab + diff --git a/0007-proton-esync-fsync/0262-fsync-Don-t-spin-on-zero-timeouts-and-fix-try_wait_s.patch b/0007-proton-esync-fsync/0262-fsync-Don-t-spin-on-zero-timeouts-and-fix-try_wait_s.patch new file mode 100644 index 0000000..cc837d8 --- /dev/null +++ b/0007-proton-esync-fsync/0262-fsync-Don-t-spin-on-zero-timeouts-and-fix-try_wait_s.patch @@ -0,0 +1,128 @@ +From a0642db0c5a57d93c66193a14a8eb4da28f84359 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Mon, 16 Dec 2024 00:43:14 -0800 +Subject: [PATCH] fsync: Don't spin on zero timeouts, and fix + try_wait_semaphore logic. + +--- + dlls/ntdll/unix/fsync.c | 28 +++++++++++++--------------- + 1 file changed, 13 insertions(+), 15 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 9831fa4e8ee..307f891eb9d 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -880,7 +880,7 @@ static inline NTSTATUS try_wait_value( volatile int *addr, int expected_val, + } + + static inline BOOL try_reacquire_mutex( struct mutex *mutex, int current_tid, +- int *observed_tid ) ++ int *observed_tid, BOOL zero_timeout ) + { + int tid = *observed_tid; + +@@ -900,7 +900,7 @@ static inline BOOL try_reacquire_mutex( struct mutex *mutex, int current_tid, + mutex->count = 1; + return TRUE; + } +- if (try_wait_value( &mutex->tid, tid, &tid, MUTEX_MON_TIMEOUT ) == STATUS_SUCCESS) ++ if (!zero_timeout && try_wait_value( &mutex->tid, tid, &tid, MUTEX_MON_TIMEOUT ) == STATUS_SUCCESS) + { + *observed_tid = tid; + return TRUE; +@@ -908,26 +908,23 @@ static inline BOOL try_reacquire_mutex( struct mutex *mutex, int current_tid, + return FALSE; /* fall back to futex */ + } + +-static inline BOOL try_acquire_semaphore( struct semaphore *semaphore ) ++static inline BOOL try_acquire_semaphore( struct semaphore *semaphore, BOOL zero_timeout ) + { + int count, new_count; + + new_count = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST ); +- while ((count = new_count) > 0) ++ while ((count = new_count)) + { + if ((new_count = __sync_val_compare_and_swap( &semaphore->count, + count, count - 1 )) == count) + { + return TRUE; + } +- +- if (!new_count && +- try_wait_value( &semaphore->count, 0, &new_count, SEM_MON_TIMEOUT ) == STATUS_SUCCESS) ++ if (!zero_timeout && ++ try_wait_value( &semaphore->count, new_count, &new_count, SEM_MON_TIMEOUT ) == STATUS_SUCCESS) + { + continue; + } +- +- break; + } + return FALSE; + } +@@ -941,7 +938,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + + struct futex_waitv futexes[MAXIMUM_WAIT_OBJECTS + 1]; + struct fsync objs[MAXIMUM_WAIT_OBJECTS]; +- BOOL msgwait = FALSE, waited = FALSE; ++ BOOL msgwait = FALSE, waited = FALSE, zero_timeout = FALSE; + int has_fsync = 0, has_server = 0; + clockid_t clock_id = 0; + struct timespec64 end; +@@ -969,6 +966,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + } + + get_wait_end_time( &timeout, &end, &clock_id ); ++ zero_timeout = timeout && !timeout->QuadPart; + + for (i = 0; i < count; i++) + { +@@ -1050,7 +1048,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + { + struct semaphore *semaphore = obj->shm; + +- if (try_acquire_semaphore( semaphore )) ++ if (try_acquire_semaphore( semaphore, zero_timeout )) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + return i; +@@ -1072,7 +1070,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + } + + tid = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ); +- if (try_reacquire_mutex( mutex, current_tid, &tid )) ++ if (try_reacquire_mutex( mutex, current_tid, &tid, zero_timeout )) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + return (tid == ~0) ? STATUS_ABANDONED_WAIT_0 + i : i; +@@ -1093,7 +1091,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + return i; + } + +- if (try_wait_value( &event->signaled, 0, &signaled, AUTO_MON_TIMEOUT ) == STATUS_SUCCESS && ++ if (!zero_timeout && try_wait_value( &event->signaled, 0, &signaled, AUTO_MON_TIMEOUT ) == STATUS_SUCCESS && + __sync_val_compare_and_swap( &event->signaled, 1, 0 )) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); +@@ -1116,7 +1114,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + return i; + } + +- if (try_wait_value( &event->signaled, 0, &signaled, MANUAL_MON_TIMEOUT ) == STATUS_SUCCESS && ++ if (!zero_timeout && try_wait_value( &event->signaled, 0, &signaled, MANUAL_MON_TIMEOUT ) == STATUS_SUCCESS && + signaled) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); +@@ -1146,7 +1144,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + + /* Looks like everything is contended, so wait. */ + +- if (timeout && !timeout->QuadPart) ++ if (zero_timeout) + { + /* Unlike esync, we already know that we've timed out, so we + * can avoid a syscall. */ +-- +2.47.1 + diff --git a/0009-windowing-system-integration/0001-misc/0000-Revert-winex11-Sync-gl-drawable-outside-of-the-win_data-mut.patch b/0009-windowing-system-integration/0001-misc/0000-Revert-winex11-Sync-gl-drawable-outside-of-the-win_data-mut.patch new file mode 100644 index 0000000..06652b5 --- /dev/null +++ b/0009-windowing-system-integration/0001-misc/0000-Revert-winex11-Sync-gl-drawable-outside-of-the-win_data-mut.patch @@ -0,0 +1,46 @@ +From 54d82ed4d5483f7569871219acc485b3cb5a224e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Sat, 14 Dec 2024 13:15:42 +0100 +Subject: [PATCH] winex11: Sync gl drawable outside of the win_data mutex. + +Some thread might be destroying a window, calling destroy_client_window +from release_gl_drawable, holding the GL context mutex and trying to +enter the win_data mutex. + +At the same time, another thread might be moving its window, calling +sync_gl_drawable from X11DRV_WindowPosChanged, holding the win_data +mutex and trying to enter the GL context mutex. + +The deadlock was present before already, although less frequently +triggered as sync_gl_drawable was done conditionally if the client +window has been moved. + +This triggers now more frequently in the dxgi:dxgi tests. +--- + dlls/winex11.drv/window.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git b/dlls/winex11.drv/window.c a/dlls/winex11.drv/window.c +index bf415f19cb9..d109d6a744e 100644 +--- b/dlls/winex11.drv/window.c ++++ a/dlls/winex11.drv/window.c +@@ -2932,8 +2932,6 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UIN + struct window_rects old_rects; + BOOL was_fullscreen; + +- sync_gl_drawable( hwnd, FALSE ); +- + if (!(data = get_win_data( hwnd ))) return; + + old_style = new_style & ~(WS_VISIBLE | WS_MINIMIZE | WS_MAXIMIZE); +@@ -2952,6 +2950,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UIN + XFlush( gdi_display ); /* make sure painting is done before we move the window */ + + sync_client_position( data, &old_rects ); ++ sync_gl_drawable( hwnd, FALSE ); + + if (!data->whole_window) + { +-- +2.47.1 + diff --git a/0013-server-optimization/0001-misc/0756-ntdll-HACK-Delay-resuming-thread-after-suspending-se.patch b/0013-server-optimization/0001-misc/0756-ntdll-HACK-Delay-resuming-thread-after-suspending-se.patch deleted file mode 100644 index 3e04c7c..0000000 --- a/0013-server-optimization/0001-misc/0756-ntdll-HACK-Delay-resuming-thread-after-suspending-se.patch +++ /dev/null @@ -1,60 +0,0 @@ -From a65aa9c07be77d44fdc3392ef11a4b581128485e Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Thu, 10 Mar 2022 17:58:41 +0300 -Subject: [PATCH 0756/2346] ntdll: HACK: Delay resuming thread after suspending - self. - -CW-Bug-Id: #20270 - -Fixes a random hang on exit in Little Nightmares 2. ---- - dlls/ntdll/unix/thread.c | 5 ++++- - server/thread.c | 6 +++++- - 2 files changed, 9 insertions(+), 2 deletions(-) - -diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c -index e7c6c5f560a..64cad6e7c0e 100644 ---- a/dlls/ntdll/unix/thread.c -+++ b/dlls/ntdll/unix/thread.c -@@ -1613,6 +1613,7 @@ NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access, - */ - NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *count ) - { -+ BOOL self = FALSE; - unsigned int ret; - - SERVER_START_REQ( suspend_thread ) -@@ -1620,10 +1621,12 @@ NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *count ) - req->handle = wine_server_obj_handle( handle ); - if (!(ret = wine_server_call( req ))) - { -- if (count) *count = reply->count; -+ self = reply->count & 0x80000000; -+ if (count) *count = reply->count & 0x7fffffff; - } - } - SERVER_END_REQ; -+ if (self) usleep( 0 ); - return ret; - } - -diff --git a/server/thread.c b/server/thread.c -index 8c8d8b868da..a6039b35d9d 100644 ---- a/server/thread.c -+++ b/server/thread.c -@@ -912,7 +912,11 @@ int suspend_thread( struct thread *thread ) - int old_count = thread->suspend; - if (thread->suspend < MAXIMUM_SUSPEND_COUNT) - { -- if (!(thread->process->suspend + thread->suspend++)) stop_thread( thread ); -+ if (!(thread->process->suspend + thread->suspend++)) -+ { -+ stop_thread( thread ); -+ if (thread == current) return old_count | 0x80000000; -+ } - } - else set_error( STATUS_SUSPEND_COUNT_EXCEEDED ); - return old_count; --- -2.47.0 - diff --git a/0013-server-optimization/0001-misc/1209-ntdll-Wait-for-thread-suspension-in-NtSuspendThread.patch b/0013-server-optimization/0001-misc/1209-ntdll-Wait-for-thread-suspension-in-NtSuspendThread.patch deleted file mode 100644 index b53f202..0000000 --- a/0013-server-optimization/0001-misc/1209-ntdll-Wait-for-thread-suspension-in-NtSuspendThread.patch +++ /dev/null @@ -1,124 +0,0 @@ -From bfa83480970ff96bb4e4c6290f1b45745ff5d757 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 13 Mar 2024 18:44:31 -0600 -Subject: [PATCH 1209/2346] ntdll: Wait for thread suspension in - NtSuspendThread(). - -CW-Bug-Id: #23552 ---- - dlls/ntdll/unix/thread.c | 26 ++++++++++++++++++++++---- - server/protocol.def | 6 ++++-- - server/thread.c | 28 ++++++++++++++++++++++++---- - 3 files changed, 50 insertions(+), 10 deletions(-) - -diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c -index 64cad6e7c0e..c69d3de3e15 100644 ---- a/dlls/ntdll/unix/thread.c -+++ b/dlls/ntdll/unix/thread.c -@@ -1611,22 +1611,40 @@ NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access, - /****************************************************************************** - * NtSuspendThread (NTDLL.@) - */ --NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *count ) -+NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *ret_count ) - { - BOOL self = FALSE; -- unsigned int ret; -+ unsigned int ret, count = 0; -+ HANDLE wait_handle = NULL; - - SERVER_START_REQ( suspend_thread ) - { - req->handle = wine_server_obj_handle( handle ); -- if (!(ret = wine_server_call( req ))) -+ if (!(ret = wine_server_call( req )) || ret == STATUS_PENDING) - { - self = reply->count & 0x80000000; -- if (count) *count = reply->count & 0x7fffffff; -+ count = reply->count & 0x7fffffff;; -+ wait_handle = wine_server_ptr_handle( reply->wait_handle ); - } - } - SERVER_END_REQ; -+ - if (self) usleep( 0 ); -+ -+ if (ret == STATUS_PENDING && wait_handle) -+ { -+ NtWaitForSingleObject( wait_handle, FALSE, NULL ); -+ -+ SERVER_START_REQ( suspend_thread ) -+ { -+ req->handle = wine_server_obj_handle( handle ); -+ req->waited_handle = wine_server_obj_handle( wait_handle ); -+ ret = wine_server_call( req ); -+ } -+ SERVER_END_REQ; -+ } -+ -+ if (!ret && ret_count) *ret_count = count; - return ret; - } - -diff --git a/server/protocol.def b/server/protocol.def -index ee75ae5e566..d6926784fe5 100644 ---- a/server/protocol.def -+++ b/server/protocol.def -@@ -1183,9 +1183,11 @@ typedef volatile struct input_shared_memory input_shm_t; - - /* Suspend a thread */ - @REQ(suspend_thread) -- obj_handle_t handle; /* thread handle */ -+ obj_handle_t handle; /* thread handle */ -+ obj_handle_t waited_handle; /* handle waited on */ - @REPLY -- int count; /* new suspend count */ -+ int count; /* new suspend count */ -+ obj_handle_t wait_handle; /* handle to wait on */ - @END - - -diff --git a/server/thread.c b/server/thread.c -index a6039b35d9d..e54e83c178a 100644 ---- a/server/thread.c -+++ b/server/thread.c -@@ -1815,12 +1815,32 @@ DECL_HANDLER(suspend_thread) - { - struct thread *thread; - -- if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME ))) -+ if (req->waited_handle) - { -- if (thread->state == TERMINATED) set_error( STATUS_ACCESS_DENIED ); -- else reply->count = suspend_thread( thread ); -- release_object( thread ); -+ struct context *context; -+ -+ if (!(context = (struct context *)get_handle_obj( current->process, req->waited_handle, -+ 0, &context_ops ))) -+ return; -+ close_handle( current->process, req->waited_handle ); /* avoid extra server call */ -+ set_error( context->status ); -+ release_object( context ); -+ return; - } -+ -+ if (!(thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME ))) return; -+ -+ if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED ); -+ else -+ { -+ reply->count = suspend_thread( thread ); -+ if (!get_error() && thread != current && thread->context && thread->context->status == STATUS_PENDING) -+ { -+ set_error( STATUS_PENDING ); -+ reply->wait_handle = alloc_handle( current->process, thread->context, SYNCHRONIZE, 0 ); -+ } -+ } -+ release_object( thread ); - } - - /* resume a thread */ --- -2.47.0 - diff --git a/0013-server-optimization/0001-misc/ps0050-oleaut32-CoMsgWaitForMultipleHandles-message-pump.patch b/0013-server-optimization/0001-misc/ps0050-oleaut32-CoMsgWaitForMultipleHandles-message-pump.patch deleted file mode 100644 index 13b89e4..0000000 --- a/0013-server-optimization/0001-misc/ps0050-oleaut32-CoMsgWaitForMultipleHandles-message-pump.patch +++ /dev/null @@ -1,509 +0,0 @@ -From: Kevin Puetz -Subject: [PATCH] oleaut32: CoMsgWaitForMultipleHandles message pump. -Message-Id: <20201124231833.11578-1-PuetzKevinA@JohnDeere.com> -Date: Tue, 24 Nov 2020 17:18:32 -0600 - -Check for completion (handles/APC) before pumping any messages, and -again after each message is dispatched, returning as soon as the wait -condition is satisfied. This matches windows behavior and obsoletes -the previous "100 message" workaround for WM_PAINT. - -Only report timeout before/during sleep, not while actively working. -The previous code had a narrow race (particularly for timeout=0): -if GetTickCount incremented between start_time and the loop body -it could WAIT_TIMEOUT even if the handles were already signaled. -No test; I couldn't think of a way to provoke this consistently. - -NOTE: this means CoWaitForMultipleHandles does not time out while -there are still queued messages, and will livelock (and never time out) -if dispatching of messages continuously posts additional messages. -It will exit (successfully) if the handles eventually become signaled. -The latter is the only case tested, since I don't know how to write -a successful test for "this will livelock and hang the process". -But windows does do the same. - -Notify IMessageFilter::MessagePending only for messages that wake -CoWait from MsgWait (sleeping on an empty queue), but not for -messages already posted before it sleeps. - -Add tests for IMessageFilter::MessagePending -> PENDINGMSG_CANCELCALL -One of these is todo_wine, as was the existing MessageFilter test. -The bug is the same: windows does not call MessagePending for DDE/RPC -messages, but wine (still) does. I'm not sure what the right structure -is to fix this, but it's a separate (and preexisting) issue. ---- - dlls/combase/combase.c | 173 +++++++++++++++++++------------------ - dlls/ole32/tests/compobj.c | 164 +++++++++++++++++++++++++++++++++++ - 2 files changed, 253 insertions(+), 84 deletions(-) - -diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c -index 11111111111..11111111111 100644 ---- a/dlls/combase/combase.c -+++ b/dlls/combase/combase.c -@@ -2050,12 +2050,13 @@ static BOOL com_peek_message(struct apartment *apt, MSG *msg) - HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle_count, HANDLE *handles, - DWORD *index) - { -- BOOL check_apc = !!(flags & COWAIT_ALERTABLE), message_loop; -+ BOOL message_loop; - struct { BOOL post; UINT code; } quit = { .post = FALSE }; - DWORD start_time, wait_flags = 0; - struct tlsdata *tlsdata; - struct apartment *apt; - HRESULT hr; -+ DWORD res; - - TRACE("%#lx, %#lx, %lu, %p, %p\n", flags, timeout, handle_count, handles, index); - -@@ -2084,113 +2085,117 @@ HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle - - start_time = GetTickCount(); - -- while (TRUE) -+ if (message_loop) - { -- DWORD now = GetTickCount(), res; -- -- if (now - start_time > timeout) -+ while (TRUE) - { -- hr = RPC_S_CALLPENDING; -- break; -- } -+ MSG msg; - -- if (message_loop) -- { - TRACE("waiting for rpc completion or window message\n"); - -- res = WAIT_TIMEOUT; -+ res = WaitForMultipleObjectsEx(handle_count, handles, -+ !!(flags & COWAIT_WAITALL), 0, !!(flags & COWAIT_ALERTABLE)); - -- if (check_apc) -+ if (res != WAIT_TIMEOUT) - { -- res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL), 0, TRUE); -- check_apc = FALSE; -+ break; - } - -- if (res == WAIT_TIMEOUT) -- res = MsgWaitForMultipleObjectsEx(handle_count, handles, -- timeout == INFINITE ? INFINITE : start_time + timeout - now, -- QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags); -- -- if (res == WAIT_OBJECT_0 + handle_count) /* messages available */ -+ if (!apt->win) - { -- int msg_count = 0; -- MSG msg; -- -- /* call message filter */ -+ /* If window is NULL on apartment, peek at messages so that it will not trigger -+ * MsgWaitForMultipleObjects next time. */ -+ PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD); -+ } - -- if (apt->filter) -+ if (com_peek_message(apt, &msg)) -+ { -+ if (msg.message == WM_QUIT) - { -- PENDINGTYPE pendingtype = tlsdata->pending_call_count_server ? PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL; -- DWORD be_handled = IMessageFilter_MessagePending(apt->filter, 0 /* FIXME */, now - start_time, pendingtype); -- -- TRACE("IMessageFilter_MessagePending returned %ld\n", be_handled); -- -- switch (be_handled) -- { -- case PENDINGMSG_CANCELCALL: -- WARN("call canceled\n"); -- hr = RPC_E_CALL_CANCELED; -- break; -- case PENDINGMSG_WAITNOPROCESS: -- case PENDINGMSG_WAITDEFPROCESS: -- default: -- /* FIXME: MSDN is very vague about the difference -- * between WAITNOPROCESS and WAITDEFPROCESS - there -- * appears to be none, so it is possibly a left-over -- * from the 16-bit world. */ -- break; -- } -+ TRACE("Received WM_QUIT message\n"); -+ quit.post = TRUE; -+ quit.code = msg.wParam; - } -- -- if (!apt->win) -+ else - { -- /* If window is NULL on apartment, peek at messages so that it will not trigger -- * MsgWaitForMultipleObjects next time. */ -- PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD); -+ TRACE("Received message whilst waiting for RPC: 0x%04x\n", msg.message); -+ TranslateMessage(&msg); -+ DispatchMessageW(&msg); -+ } -+ } -+ else -+ { -+ DWORD now = GetTickCount(); -+ if (now - start_time > timeout) -+ { -+ /* res really is WAIT_TIMEOUT (not just from the dwMilliseconds=0 polling of handles) */ -+ break; - } - -- /* Some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever, -- * so after processing 100 messages we go back to checking the wait handles */ -- while (msg_count++ < 100 && com_peek_message(apt, &msg)) -+ /* not done, no messages pending, sleep for the remaining time (or until something happens) */ -+ res = MsgWaitForMultipleObjectsEx(handle_count, handles, -+ timeout == INFINITE ? INFINITE : start_time + timeout - now, -+ QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags); -+ -+ if (res == WAIT_OBJECT_0 + handle_count) /* messages available */ - { -- if (msg.message == WM_QUIT) -- { -- TRACE("Received WM_QUIT message\n"); -- quit.post = TRUE; -- quit.code = msg.wParam; -- } -- else -+ /* call message filter */ -+ -+ if (apt->filter) - { -- TRACE("Received message whilst waiting for RPC: 0x%04x\n", msg.message); -- TranslateMessage(&msg); -- DispatchMessageW(&msg); -+ PENDINGTYPE pendingtype = tlsdata->pending_call_count_server ? PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL; -+ DWORD be_handled = IMessageFilter_MessagePending(apt->filter, 0 /* FIXME */, now - start_time, pendingtype); -+ -+ TRACE("IMessageFilter_MessagePending returned %d\n", be_handled); -+ -+ switch (be_handled) -+ { -+ case PENDINGMSG_CANCELCALL: -+ WARN("call canceled\n"); -+ hr = RPC_E_CALL_CANCELED; -+ goto done; -+ break; -+ case PENDINGMSG_WAITNOPROCESS: -+ case PENDINGMSG_WAITDEFPROCESS: -+ default: -+ /* FIXME: MSDN is very vague about the difference -+ * between WAITNOPROCESS and WAITDEFPROCESS - there -+ * appears to be none, so it is possibly a left-over -+ * from the 16-bit world. */ -+ break; -+ } - } - } -- continue; -+ else -+ { -+ break; -+ } - } - } -- else -- { -- TRACE("Waiting for rpc completion\n"); -+ } -+ else -+ { -+ TRACE("Waiting for rpc completion\n"); - -- res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL), -- (timeout == INFINITE) ? INFINITE : start_time + timeout - now, !!(flags & COWAIT_ALERTABLE)); -- } -+ res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL), -+ timeout, !!(flags & COWAIT_ALERTABLE)); -+ } - -- switch (res) -- { -- case WAIT_TIMEOUT: -- hr = RPC_S_CALLPENDING; -- break; -- case WAIT_FAILED: -- hr = HRESULT_FROM_WIN32(GetLastError()); -- break; -- default: -- *index = res; -- break; -- } -+ switch (res) -+ { -+ case WAIT_TIMEOUT: -+ hr = RPC_S_CALLPENDING; -+ break; -+ case WAIT_FAILED: -+ hr = HRESULT_FROM_WIN32(GetLastError()); -+ break; -+ default: -+ hr = S_OK; -+ *index = res; - break; - } -+ -+done: - if (quit.post) PostQuitMessage(quit.code); - - TRACE("-- %#lx\n", hr); -diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c -index 11111111111..11111111111 100644 ---- a/dlls/ole32/tests/compobj.c -+++ b/dlls/ole32/tests/compobj.c -@@ -975,6 +975,16 @@ static DWORD WINAPI MessageFilter_MessagePending( - return PENDINGMSG_WAITNOPROCESS; - } - -+static DWORD WINAPI MessageFilter_MessagePending_cancel( -+ IMessageFilter *iface, -+ HTASK threadIDCallee, -+ DWORD dwTickCount, -+ DWORD dwPendingType) -+{ -+ trace("MessagePending(cancel)\n"); -+ return PENDINGMSG_CANCELCALL; -+} -+ - static const IMessageFilterVtbl MessageFilter_Vtbl = - { - MessageFilter_QueryInterface, -@@ -987,6 +997,18 @@ static const IMessageFilterVtbl MessageFilter_Vtbl = - - static IMessageFilter MessageFilter = { &MessageFilter_Vtbl }; - -+static const IMessageFilterVtbl MessageFilter_Vtbl_cancel = -+{ -+ MessageFilter_QueryInterface, -+ MessageFilter_AddRef, -+ MessageFilter_Release, -+ MessageFilter_HandleInComingCall, -+ MessageFilter_RetryRejectedCall, -+ MessageFilter_MessagePending_cancel -+}; -+ -+static IMessageFilter MessageFilter_cancel = { &MessageFilter_Vtbl_cancel }; -+ - static void test_CoRegisterMessageFilter(void) - { - HRESULT hr; -@@ -2611,6 +2633,22 @@ static DWORD CALLBACK post_message_thread(LPVOID arg) - return 0; - } - -+static DWORD CALLBACK post_input_later_thread(LPVOID arg) -+{ -+ HWND hWnd = arg; -+ Sleep(50); -+ PostMessageA(hWnd, WM_CHAR, VK_ESCAPE, 0); -+ return 0; -+} -+ -+static DWORD CALLBACK post_dde_later_thread(LPVOID arg) -+{ -+ HWND hWnd = arg; -+ Sleep(50); -+ PostMessageA(hWnd, WM_DDE_FIRST, 0, 0); -+ return 0; -+} -+ - static const char cls_name[] = "cowait_test_class"; - - static UINT cowait_msgs[100], cowait_msgs_first, cowait_msgs_last; -@@ -2668,6 +2706,18 @@ static LRESULT CALLBACK cowait_window_proc(HWND hwnd, UINT msg, WPARAM wparam, L - cowait_msgs[cowait_msgs_last++] = msg; - if(msg == WM_DDE_FIRST) - return 6; -+ if(msg == WM_DDE_EXECUTE && lparam) -+ { -+ const char* command = (const char *)GlobalLock((HGLOBAL)lparam); -+ if(strcmp(command,"[apc]") == 0) -+ QueueUserAPC(apc_test_proc, GetCurrentThread(), 0); -+ else if(strcmp(command,"[postmessage]") == 0) -+ PostMessageA(hwnd,msg,wparam,lparam); /* post the same message again (trigges livelock) */ -+ else if(strcmp(command,"[semaphore]") == 0) -+ ReleaseSemaphore(GetPropA(hwnd,"semaphore"), 1, NULL); -+ GlobalUnlock((HGLOBAL)lparam); -+ return 0; -+ } - return DefWindowProcA(hwnd, msg, wparam, lparam); - } - -@@ -2749,6 +2799,27 @@ static DWORD CALLBACK test_CoWaitForMultipleHandles_thread(LPVOID arg) - success = PeekMessageA(&msg, NULL, uMSG, uMSG, PM_REMOVE); - ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n"); - -+ hr = CoRegisterMessageFilter(&MessageFilter_cancel, NULL); -+ ok(hr == S_OK, "CoRegisterMessageFilter failed: %08x\n", hr); -+ -+ /* a message which arrives during the wait calls IMessageFilter::PendingMessage, -+ * which can cancel the wait (without pumping the message) */ -+ thread = CreateThread(NULL, 0, post_input_later_thread, hWnd, 0, &tid); -+ hr = CoWaitForMultipleHandles(0, 200, 2, handles, &index); -+ ok(hr == RPC_E_CALL_CANCELED, "expected RPC_E_CALL_CANCELED, got 0x%08x\n", hr); -+ success = PeekMessageA(&msg, hWnd, WM_CHAR, WM_CHAR, PM_REMOVE); -+ ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n"); -+ CloseHandle(thread); -+ -+ /* DDE/RPC messages shouldn't go to IMessageFilter::PendingMessage */ -+ thread = CreateThread(NULL, 0, post_dde_later_thread, hWnd, 0, &tid); -+ hr = CoWaitForMultipleHandles(0, 200, 2, handles, &index); -+ todo_wine ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr); -+ CloseHandle(thread); -+ -+ hr = CoRegisterMessageFilter(NULL, NULL); -+ ok(hr == S_OK, "CoRegisterMessageFilter failed: %08x\n", hr); -+ - DestroyWindow(hWnd); - CoUninitialize(); - -@@ -2788,6 +2859,15 @@ static DWORD CALLBACK test_CoWaitForMultipleHandles_thread(LPVOID arg) - return 0; - } - -+static HGLOBAL globalalloc_string(const char *s) { -+ UINT len = strlen(s); -+ HGLOBAL ret = GlobalAlloc(GMEM_FIXED,len+1); -+ void *ptr = GlobalLock(ret); -+ strcpy(ptr,s); -+ GlobalUnlock(ret); -+ return ret; -+} -+ - static void test_CoWaitForMultipleHandles(void) - { - HANDLE handles[2], thread; -@@ -2797,6 +2877,10 @@ static void test_CoWaitForMultipleHandles(void) - HRESULT hr; - HWND hWnd; - MSG msg; -+ HGLOBAL execute_apc = globalalloc_string("[apc]"); -+ HGLOBAL execute_postmessage = globalalloc_string("[postmessage]"); -+ HGLOBAL execute_semaphore = globalalloc_string("[semaphore]"); -+ DWORD start_time; - - hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); - ok(hr == S_OK, "CoInitializeEx failed with error 0x%08lx\n", hr); -@@ -2819,6 +2903,8 @@ static void test_CoWaitForMultipleHandles(void) - handles[1] = CreateSemaphoreA(NULL, 1, 1, NULL); - ok(handles[1] != 0, "CreateSemaphoreA failed %lu\n", GetLastError()); - -+ SetPropA(hWnd,"semaphore",handles[0]); -+ - /* test without flags */ - - PostMessageA(hWnd, WM_DDE_FIRST, 0, 0); -@@ -2867,6 +2953,31 @@ static void test_CoWaitForMultipleHandles(void) - success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE); - ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n"); - -+ /* test CoWaitForMultipleHandles stops pumping messages as soon as its handles are signaled */ -+ index = 0xdeadbeef; -+ PostMessageA(hWnd, WM_DDE_EXECUTE, 0, (LPARAM)execute_semaphore); -+ PostMessageA(hWnd, WM_DDE_FIRST, 0, 0); -+ hr = CoWaitForMultipleHandles(0, 50, 1, handles, &index); -+ ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr); -+ ok(index == 0, "expected index 0, got %u\n", index); -+ cowait_msgs_expect_queued(hWnd,WM_DDE_FIRST); /* WM_DDE_EXECUTE already pumped*/ -+ success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE); -+ ok(!success, "CoWaitForMultipleHandles didn't pump enough messages\n"); -+ -+ /* test CoWaitForMultipleHandles will keep pumping even beyond timeout if the queue -+ * still has messages (e.g. pumping messages just posts more mesages), -+ * but will still exit if the handles handles become signaled */ -+ index = 0xdeadbeef; -+ PostMessageA(hWnd, WM_DDE_EXECUTE, 0, (LPARAM)execute_postmessage); -+ start_time = GetTickCount(); -+ thread = CreateThread(NULL, 0, release_semaphore_thread, handles[0], 0, &tid); -+ hr = CoWaitForMultipleHandles(0, 50, 1, handles, &index); -+ ok(GetTickCount() - start_time >= 200, "CoWaitForMultipleHandles exited too soon\n"); -+ ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr); -+ cowait_msgs_expect_queued(hWnd,WM_DDE_EXECUTE); /* each pumped execute_postmessage added one more back */ -+ success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE); -+ ok(!success, "CoWaitForMultipleHandles didn't pump enough messages\n"); -+ - /* test PostMessageA/SendMessageA from a different thread */ - - index = 0xdeadbeef; -@@ -2914,6 +3025,45 @@ static void test_CoWaitForMultipleHandles(void) - success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE); - ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n"); - -+ ReleaseSemaphore(handles[0], 1, NULL); -+ -+ /* COWAIT_ALL will get time out even if the handles became signaled while it waits -+ * in MsgWaitForMultipleObjects(...,MWIO_WAITALL), as it demands a posted message too */ -+ index = 0xdeadbeef; -+ thread = CreateThread(NULL, 0, release_semaphore_thread, handles[1], 0, &tid); -+ hr = CoWaitForMultipleHandles(COWAIT_WAITALL, 500, 2, handles, &index); -+ ok(hr == RPC_S_CALLPENDING, "expected RPC_S_CALLPENDING, got 0x%08x\n", hr); -+ /* but will succeed (without any further wait time) if the handles are avilable right away -+ * i.e. that it checks the handles first before calling MsgWaitForMultipleObjects */ -+ hr = CoWaitForMultipleHandles(COWAIT_WAITALL, 0, 2, handles, &index); -+ ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr); -+ ok(index == 0, "expected index 0, got %u\n", index); -+ -+ ReleaseSemaphore(handles[1], 1, NULL); -+ -+ /* COWAIT_ALL will pump message which are already in the queue, -+ * (but no longer QS_ALLPOSTMESSAGE), before blocking in MsgWaitForMultipleObjectsEx */ -+ index = 0xdeadbeef; -+ PostMessageA(hWnd, WM_DDE_EXECUTE, 0, (LPARAM)execute_semaphore); -+ PeekMessageA(&msg, hWnd, 0, 0, PM_NOREMOVE); // clear QS_ALLPOSTMESSAGE -+ hr = CoWaitForMultipleHandles(COWAIT_WAITALL, 50, 1, handles, &index); -+ ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr); -+ ok(index == 0, "expected index 0, got %u\n", index); -+ success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE); -+ ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n"); -+ -+ ReleaseSemaphore(handles[1], 1, NULL); -+ -+ /* test early completion (rather than blocking in MsgWaitForMultipleObjectsEx again) -+ * if pumping a message results in all handles becoming signaled) */ -+ index = 0xdeadbeef; -+ PostMessageA(hWnd, WM_DDE_EXECUTE, 0, (LPARAM)execute_semaphore); -+ hr = CoWaitForMultipleHandles(COWAIT_WAITALL, 50, 2, handles, &index); -+ ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr); -+ ok(index == 0, "expected index 0, got %u\n", index); -+ success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE); -+ ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n"); -+ - ReleaseSemaphore(handles[0], 1, NULL); - ReleaseSemaphore(handles[1], 1, NULL); - -@@ -2953,6 +3103,16 @@ static void test_CoWaitForMultipleHandles(void) - success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE); - ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n"); - -+ index = 0xdeadbeef; -+ PostMessageA(hWnd, WM_DDE_EXECUTE, 0, (LPARAM)execute_apc); -+ PostMessageA(hWnd, WM_DDE_FIRST, 0, 0); -+ hr = CoWaitForMultipleHandles(COWAIT_ALERTABLE, 50, 1, handles, &index); -+ ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr); -+ ok(index == WAIT_IO_COMPLETION, "expected index WAIT_IO_COMPLETION, got %u\n", index); -+ cowait_msgs_expect_queued(hWnd,WM_DDE_FIRST); /* WM_DDE_EXECUTE already pumped*/ -+ success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE); -+ ok(!success, "CoWaitForMultipleHandles didn't pump enough messages\n"); -+ - /* test with COWAIT_INPUTAVAILABLE (semaphores are still locked) */ - - index = 0xdeadbeef; -@@ -3165,6 +3325,10 @@ static void test_CoWaitForMultipleHandles(void) - - CoUninitialize(); - -+ RemovePropA(hWnd,"semaphore"); -+ GlobalFree(execute_apc); -+ GlobalFree(execute_postmessage); -+ GlobalFree(execute_semaphore); - CloseHandle(handles[0]); - CloseHandle(handles[1]); - DestroyWindow(hWnd); - diff --git a/0013-server-optimization/0002-threaded-server/ps0435-p0001-server-ntdll-Create-shared-memory-for-every.patch b/0013-server-optimization/0002-threaded-server/ps0435-p0001-server-ntdll-Create-shared-memory-for-every.patch new file mode 100644 index 0000000..7871d36 --- /dev/null +++ b/0013-server-optimization/0002-threaded-server/ps0435-p0001-server-ntdll-Create-shared-memory-for-every.patch @@ -0,0 +1,388 @@ +From 0ad5a65f071a1e759b852eb82da66ec1e18cc72b Mon Sep 17 00:00:00 2001 +From: Torge Matthies +Date: Sun, 31 Jul 2022 15:09:23 +0200 +Subject: [PATCH 1/8] server,ntdll: Create shared memory for every thread. + +--- + dlls/ntdll/unix/server.c | 65 +++++++++++++++++++++++++++++++++- + dlls/ntdll/unix/unix_private.h | 17 +++++++++ + dlls/ntdll/unix/virtual.c | 4 +++ + server/file.h | 4 +++ + server/mapping.c | 16 +++++++++ + server/protocol.def | 4 +++ + server/thread.c | 27 ++++++++++++++ + server/thread.h | 17 +++++++++ + 8 files changed, 153 insertions(+), 1 deletion(-) + +diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c +index 11111111111..11111111111 100644 +--- a/dlls/ntdll/unix/server.c ++++ b/dlls/ntdll/unix/server.c +@@ -1662,6 +1662,13 @@ size_t server_init_process(void) + struct sigaction sig_act; + size_t info_size; + DWORD pid, tid; ++ sigset_t sigset; ++#ifdef __linux__ ++ int has_request_shm = 0; ++ obj_handle_t fd_handle; ++ int request_shm_fd = -1; ++ void *request_shm = MAP_FAILED; ++#endif + + server_pid = -1; + if (env_socket) +@@ -1724,6 +1731,7 @@ size_t server_init_process(void) + + reply_pipe = init_thread_pipe(); + ++ server_enter_uninterrupted_section( &fd_cache_mutex, &sigset ); + SERVER_START_REQ( init_first_thread ) + { + req->unix_pid = getpid(); +@@ -1738,9 +1746,18 @@ size_t server_init_process(void) + peb->SessionId = reply->session_id; + info_size = reply->info_size; + server_start_time = reply->server_start; ++#ifdef __linux__ ++ has_request_shm = reply->has_request_shm; ++ if (has_request_shm) ++ { ++ request_shm_fd = receive_fd( &fd_handle ); ++ assert( fd_handle == tid ); ++ } ++#endif + supported_machines_count = wine_server_reply_size( reply ) / sizeof(*supported_machines); + } + SERVER_END_REQ; ++ server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); + close( reply_pipe ); + + if (ret) server_protocol_error( "init_first_thread failed with status %x\n", ret ); +@@ -1771,9 +1788,25 @@ size_t server_init_process(void) + set_thread_id( NtCurrentTeb(), pid, tid ); + + for (i = 0; i < supported_machines_count; i++) +- if (supported_machines[i] == current_machine) return info_size; ++ if (supported_machines[i] == current_machine) ++ goto map_request_shm; + + fatal_error( "wineserver doesn't support the %04x architecture\n", current_machine ); ++ ++map_request_shm: ++#ifdef __linux__ ++ if (!has_request_shm) return info_size; ++ ++ request_shm = mmap( NULL, REQUEST_SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, request_shm_fd, 0 ); ++ if (request_shm != MAP_FAILED) ++ { ++ ntdll_get_thread_data()->request_shm_fd = request_shm_fd; ++ ntdll_get_thread_data()->request_shm = request_shm; ++ } ++ else ++ close( request_shm_fd ); ++#endif ++ return info_size; + } + + +@@ -1834,10 +1867,18 @@ void server_init_thread( void *entry_point, BOOL *suspend ) + { + void *teb; + int reply_pipe = init_thread_pipe(); ++ sigset_t sigset; ++#ifdef __linux__ ++ int has_request_shm = 0; ++ obj_handle_t fd_handle; ++ int request_shm_fd = -1; ++ void *request_shm; ++#endif + + /* always send the native TEB */ + if (!(teb = NtCurrentTeb64())) teb = NtCurrentTeb(); + ++ server_enter_uninterrupted_section( &fd_cache_mutex, &sigset ); + SERVER_START_REQ( init_thread ) + { + req->unix_tid = get_unix_tid(); +@@ -1847,9 +1888,31 @@ void server_init_thread( void *entry_point, BOOL *suspend ) + req->wait_fd = ntdll_get_thread_data()->wait_fd[1]; + wine_server_call( req ); + *suspend = reply->suspend; ++#ifdef __linux__ ++ has_request_shm = reply->has_request_shm; ++ if (has_request_shm) ++ { ++ request_shm_fd = receive_fd( &fd_handle ); ++ assert( fd_handle == GetCurrentThreadId() ); ++ } ++#endif + } + SERVER_END_REQ; ++ server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); + close( reply_pipe ); ++ ++#ifdef __linux__ ++ if (!has_request_shm) return; ++ ++ request_shm = mmap( NULL, REQUEST_SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, request_shm_fd, 0 ); ++ if (request_shm != MAP_FAILED) ++ { ++ ntdll_get_thread_data()->request_shm_fd = request_shm_fd; ++ ntdll_get_thread_data()->request_shm = request_shm; ++ } ++ else ++ close( request_shm_fd ); ++#endif + } + + +diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h +index 11111111111..11111111111 100644 +--- a/dlls/ntdll/unix/unix_private.h ++++ b/dlls/ntdll/unix/unix_private.h +@@ -81,6 +81,19 @@ static inline BOOL is_old_wow64(void) + return !is_win64 && wow_peb; + } + ++#ifdef __linux__ ++struct request_shm ++{ ++ int futex; /* signaling futex */ ++ int pad; ++ union ++ { ++ union generic_request req; /* request structure */ ++ union generic_reply reply; /* reply structure */ ++ } u; ++}; ++#endif ++ + /* thread private data, stored in NtCurrentTeb()->GdiTebBatch */ + struct ntdll_thread_data + { +@@ -91,6 +104,10 @@ struct ntdll_thread_data + int request_fd; /* fd for sending server requests */ + int reply_fd; /* fd for receiving server replies */ + int wait_fd[2]; /* fd for sleeping server requests */ ++#ifdef __linux__ ++ int request_shm_fd; /* request shared memory fd */ ++ volatile struct request_shm *request_shm; /* shared memory for sending and receiving server requests/replies */ ++#endif + BOOL allow_writes; /* ThreadAllowWrites flags */ + pthread_t pthread_id; /* pthread thread id */ + struct list entry; /* entry in TEB list */ +diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c +index 11111111111..11111111111 100644 +--- a/dlls/ntdll/unix/virtual.c ++++ b/dlls/ntdll/unix/virtual.c +@@ -3704,6 +3704,10 @@ static TEB *init_teb( void *ptr, BOOL is_wow ) + thread_data->reply_fd = -1; + thread_data->wait_fd[0] = -1; + thread_data->wait_fd[1] = -1; ++#ifdef __linux__ ++ thread_data->request_shm_fd = -1; ++ thread_data->request_shm = NULL; ++#endif + list_add_head( &teb_list, &thread_data->entry ); + return teb; + } +diff --git a/server/file.h b/server/file.h +index 11111111111..11111111111 100644 +--- a/server/file.h ++++ b/server/file.h +@@ -30,6 +30,7 @@ struct mapping; + struct async_queue; + struct completion; + struct reserve; ++struct request_shm; + + /* server-side representation of I/O status block */ + struct iosb +@@ -214,6 +215,10 @@ assert( __seq == __obj->seq ); \ + __WINE_ATOMIC_STORE_RELEASE( &__obj->seq, &__end ); \ + } while(0) + ++#ifdef __linux__ ++extern int create_request_shm( int *fd, struct request_shm **ptr ); ++#endif ++ + /* device functions */ + + extern struct object *create_named_pipe_device( struct object *root, const struct unicode_str *name, +diff --git a/server/mapping.c b/server/mapping.c +index 11111111111..11111111111 100644 +--- a/server/mapping.c ++++ b/server/mapping.c +@@ -1309,6 +1309,22 @@ struct object *create_shared_mapping( struct object *root, const struct unicode_ + return &mapping->obj; + } + ++#ifdef __linux__ ++int create_request_shm( int *fd, struct request_shm **ptr ) ++{ ++ if ((*fd = create_temp_file( REQUEST_SHM_SIZE )) == -1) return 0; ++ ++ *ptr = mmap( NULL, REQUEST_SHM_SIZE, PROT_WRITE, MAP_SHARED, *fd, 0 ); ++ if (*ptr == MAP_FAILED) ++ { ++ *ptr = NULL; ++ set_error( STATUS_NO_MEMORY ); ++ return 0; ++ } ++ return 1; ++} ++#endif ++ + /* create a file mapping */ + DECL_HANDLER(create_mapping) + { +diff --git a/server/protocol.def b/server/protocol.def +index 11111111111..11111111111 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -46,6 +46,8 @@ typedef unsigned __int64 client_ptr_t; + typedef unsigned __int64 affinity_t; + typedef client_ptr_t mod_handle_t; + ++#define REQUEST_SHM_SIZE (1 * 1024 * 1024) ++ + struct request_header + { + int req; /* request code */ +@@ -1056,6 +1058,7 @@ struct directory_entry + timeout_t server_start; /* server start time */ + unsigned int session_id; /* process session id */ + data_size_t info_size; /* total size of startup info */ ++ int has_request_shm; /* is request shared memory supported? */ + VARARG(machines,ushorts); /* array of supported machines */ + @END + +@@ -1069,6 +1072,7 @@ struct directory_entry + client_ptr_t entry; /* entry point (in thread address space) */ + @REPLY + int suspend; /* is thread suspended? */ ++ int has_request_shm; /* is request shared memory supported? */ + @END + + +diff --git a/server/thread.c b/server/thread.c +index 11111111111..11111111111 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -374,6 +375,10 @@ static inline void init_thread_structure( struct thread *thread ) + thread->request_fd = NULL; + thread->reply_fd = NULL; + thread->wait_fd = NULL; ++#ifdef __linux__ ++ thread->request_shm_fd = -1; ++ thread->request_shm = NULL; ++#endif + thread->state = RUNNING; + thread->exit_code = 0; + thread->priority = 0; +@@ -585,6 +590,14 @@ struct thread *create_thread( int fd, struct process *process, const struct secu + } + } + ++#ifdef __linux__ ++ if (!create_request_shm( &thread->request_shm_fd, (struct request_shm**)&thread->request_shm )) ++ { ++ release_object( thread ); ++ return NULL; ++ } ++#endif ++ + if (do_esync()) + { + thread->esync_fd = esync_create_fd( 0, 0 ); +@@ -652,6 +665,10 @@ static void cleanup_thread( struct thread *thread ) + if (thread->request_fd) release_object( thread->request_fd ); + if (thread->reply_fd) release_object( thread->reply_fd ); + if (thread->wait_fd) release_object( thread->wait_fd ); ++#ifdef __linux__ ++ if (thread->request_shm_fd != -1) close( thread->request_shm_fd ); ++ if (thread->request_shm) munmap( (void*)thread->request_shm, REQUEST_SHM_SIZE ); ++#endif + cleanup_clipboard_thread(thread); + destroy_thread_windows( thread ); + free_msg_queue( thread ); +@@ -675,6 +692,10 @@ static void cleanup_thread( struct thread *thread ) + thread->request_fd = NULL; + thread->reply_fd = NULL; + thread->wait_fd = NULL; ++#ifdef __linux__ ++ thread->request_shm_fd = -1; ++ thread->request_shm = NULL; ++#endif + thread->desktop = 0; + thread->desc = NULL; + thread->desc_len = 0; +@@ -1997,8 +2018,11 @@ DECL_HANDLER(init_first_thread) + reply->session_id = process->session_id; + reply->info_size = get_process_startup_info_size( process ); + reply->server_start = server_start_time; ++ reply->has_request_shm = current->request_shm_fd != -1; + set_reply_data( supported_machines, + min( supported_machines_count * sizeof(unsigned short), get_reply_max_size() )); ++ if (reply->has_request_shm) ++ send_client_fd( current->process, current->request_shm_fd, reply->tid ); + } + + /* initialize a new thread */ +@@ -2025,6 +2049,9 @@ DECL_HANDLER(init_thread) + set_thread_affinity( current, current->affinity ); + + reply->suspend = (current->suspend || current->process->suspend || current->context != NULL); ++ reply->has_request_shm = current->request_shm_fd != -1; ++ if (reply->has_request_shm) ++ send_client_fd( current->process, current->request_shm_fd, get_thread_id( current ) ); + } + + /* terminate a thread */ +diff --git a/server/thread.h b/server/thread.h +index 11111111111..11111111111 100644 +--- a/server/thread.h ++++ b/server/thread.h +@@ -46,6 +46,19 @@ struct inflight_fd + }; + #define MAX_INFLIGHT_FDS 16 /* max number of fds in flight per thread */ + ++#ifdef __linux__ ++struct request_shm ++{ ++ int futex; /* signaling futex */ ++ int pad; ++ union ++ { ++ union generic_request req; /* request structure */ ++ union generic_reply reply; /* reply structure */ ++ } u; ++}; ++#endif ++ + struct thread + { + struct object obj; /* object header */ +@@ -77,6 +90,10 @@ struct thread + struct fd *request_fd; /* fd for receiving client requests */ + struct fd *reply_fd; /* fd to send a reply to a client */ + struct fd *wait_fd; /* fd to use to wake a sleeping client */ ++#ifdef __linux__ ++ int request_shm_fd; /* request shared memory fd */ ++ volatile struct request_shm *request_shm; /* shared memory for receiving and sending client requests/replies */ ++#endif + enum run_state state; /* running state */ + int exit_code; /* thread exit code */ + int unix_pid; /* Unix pid of client */ +-- +0.0.0 + diff --git a/0013-server-optimization/0002-threaded-server/ps0435-p0002-server-ntdll-Send-and-receive-server-request.patch b/0013-server-optimization/0002-threaded-server/ps0435-p0002-server-ntdll-Send-and-receive-server-request.patch new file mode 100644 index 0000000..64c299d --- /dev/null +++ b/0013-server-optimization/0002-threaded-server/ps0435-p0002-server-ntdll-Send-and-receive-server-request.patch @@ -0,0 +1,768 @@ +From bdb5a922391cb54fc7db0b7ef5aad9f25c3f714b Mon Sep 17 00:00:00 2001 +From: Torge Matthies +Date: Sun, 7 Aug 2022 21:19:26 +0200 +Subject: [PATCH 2/8] server,ntdll: Send and receive server requests through + shared memory. + +--- + dlls/ntdll/unix/server.c | 92 ++++++++++++++++++++++++++++++++ + server/Makefile.in | 2 +- + server/fd.c | 81 ++++++++++++++++++++++++++++ + server/file.h | 5 ++ + server/request.c | 98 ++++++++++++++++++++++++++++++++++ + server/request.h | 1 + + server/thread.c | 111 ++++++++++++++++++++++++++++++++++++++- + server/thread.h | 1 + + 8 files changed, 388 insertions(+), 3 deletions(-) + +diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c +index 11111111111..11111111111 100644 +--- a/dlls/ntdll/unix/server.c ++++ b/dlls/ntdll/unix/server.c +@@ -196,6 +196,78 @@ static DECLSPEC_NORETURN void server_protocol_perror( const char *err ) + } + + ++#ifdef __linux__ ++ ++#define FUTEX_WAIT 0 ++#define FUTEX_WAKE 1 ++ ++/*********************************************************************** ++ * send_request_shm ++ * ++ * Send a request to the server using shared memory. ++ */ ++static unsigned int send_request_shm( const struct __server_request_info *req ) ++{ ++ volatile struct request_shm *request_shm = ntdll_get_thread_data()->request_shm; ++ unsigned int i; ++ ++ memcpy( (void*)&request_shm->u.req, &req->u.req, sizeof(req->u.req) ); ++ if (req->u.req.request_header.request_size) ++ { ++ char *ptr = (char*)(request_shm + 1); ++ for (i = 0; i < req->data_count; i++) ++ { ++ memcpy( ptr, req->data[i].ptr, req->data[i].size ); ++ ptr += req->data[i].size; ++ } ++ } ++ ++ while (InterlockedCompareExchange( (void*)&request_shm->futex, 1, 0 ) != 0) ++ YieldProcessor(); ++ syscall( __NR_futex, &request_shm->futex, FUTEX_WAKE, 1, NULL, NULL, 0 ); ++ return STATUS_SUCCESS; ++} ++ ++ ++static void read_reply_data( void *buffer, size_t size ); ++ ++/*********************************************************************** ++ * wait_reply_shm ++ * ++ * Wait for a reply from the server using shared memory. ++ */ ++static inline unsigned int wait_reply_shm( struct __server_request_info *req ) ++{ ++ volatile struct request_shm *request_shm = ntdll_get_thread_data()->request_shm; ++ char *data_ptr = (char*)(request_shm + 1) + req->u.req.request_header.request_size; ++ unsigned int copy_limit = (char*)request_shm + REQUEST_SHM_SIZE - data_ptr; ++ int val; ++ ++ while ((val = request_shm->futex) != 0) ++ { ++ if (val == -1) ++ abort_thread(0); ++ syscall( __NR_futex, &request_shm->futex, FUTEX_WAIT, val, NULL, NULL, 0 ); ++ } ++ ++ memcpy( &req->u.reply, (void*)&request_shm->u.reply, sizeof(req->u.reply) ); ++ if (req->u.reply.reply_header.reply_size) ++ { ++ if (req->u.reply.reply_header.reply_size > copy_limit) ++ { ++ memcpy( req->reply_data, data_ptr, copy_limit ); ++ read_reply_data( (char*)req->reply_data + copy_limit, ++ req->u.reply.reply_header.reply_size - copy_limit ); ++ } ++ else ++ memcpy( req->reply_data, data_ptr, req->u.reply.reply_header.reply_size ); ++ } ++ return req->u.reply.reply_header.error; ++} ++ ++#endif /* defined(__linux__) */ ++ ++ + /*********************************************************************** + * send_request + * +@@ -302,6 +374,20 @@ static inline unsigned int wait_reply( struct __server_request_info *req ) + } + + ++#ifdef __linux__ ++ ++unsigned int server_call_unlocked_shm( void *req_ptr ) ++{ ++ struct __server_request_info * const req = req_ptr; ++ unsigned int ret; ++ ++ if ((ret = send_request_shm( req ))) return ret; ++ return wait_reply_shm( req ); ++} ++ ++#endif ++ ++ + /*********************************************************************** + * server_call_unlocked + */ +@@ -310,6 +396,12 @@ unsigned int server_call_unlocked( void *req_ptr ) + struct __server_request_info * const req = req_ptr; + unsigned int ret; + ++#ifdef __linux__ ++ if (ntdll_get_thread_data()->request_shm && ++ sizeof(req->u.req) + req->u.req.request_header.request_size < REQUEST_SHM_SIZE) ++ return server_call_unlocked_shm( req_ptr ); ++#endif ++ + if ((ret = send_request( req ))) return ret; + return wait_reply( req ); + } +diff --git a/server/Makefile.in b/server/Makefile.in +index 11111111111..11111111111 100644 +--- a/server/Makefile.in ++++ b/server/Makefile.in +@@ -52,7 +52,7 @@ SOURCES = \ + wineserver.man.in \ + winstation.c + +-UNIX_LIBS = $(LDEXECFLAGS) $(RT_LIBS) $(INOTIFY_LIBS) $(PROCSTAT_LIBS) ++UNIX_LIBS = $(LDEXECFLAGS) $(RT_LIBS) $(INOTIFY_LIBS) $(PROCSTAT_LIBS) $(PTHREAD_LIBS) + + unicode_EXTRADEFS = -DNLSDIR="\"${nlsdir}\"" -DBIN_TO_NLSDIR=\"`${MAKEDEP} -R ${bindir} ${nlsdir}`\" + +diff --git a/server/fd.c b/server/fd.c +index 11111111111..11111111111 100644 +--- a/server/fd.c ++++ b/server/fd.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -160,6 +161,7 @@ struct fd + unsigned int signaled :1; /* is the fd signaled? */ + unsigned int fs_locks :1; /* can we use filesystem locks for this fd? */ + int poll_index; /* index of fd in poll array */ ++ int poll_generation; /* generation that this fd was added to the poll array in */ + struct async_queue read_q; /* async readers of this fd */ + struct async_queue write_q; /* async writers of this fd */ + struct async_queue wait_q; /* other async waiters of this fd */ +@@ -470,6 +472,10 @@ static void set_user_shared_data_time(void) + user_shared_data->QpcBias = qpc_bias; + } + ++pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER; ++int poll_exit_pipe[2]; ++struct fd *poll_exit_fd; ++ + void set_current_time(void) + { + static const timeout_t ticks_1601_to_1970 = (timeout_t)86400 * (369 * 365 + 89) * TICKS_PER_SEC; +@@ -565,6 +571,7 @@ static int nb_users; /* count of array entries actually i + static int active_users; /* current number of active users */ + static int allocated_users; /* count of allocated entries in the array */ + static struct fd **freelist; /* list of free entries in the array */ ++unsigned long poll_generation; /* current poll array generation */ + + static int get_next_timeout(void); + +@@ -643,20 +650,27 @@ static inline void main_loop_epoll(void) + + if (epoll_fd == -1) return; + ++ pthread_mutex_lock( &global_lock ); + while (active_users) + { ++ unsigned long generation; ++ + timeout = get_next_timeout(); + + if (!active_users) break; /* last user removed by a timeout */ + if (epoll_fd == -1) break; /* an error occurred with epoll */ + ++ generation = poll_generation; ++ pthread_mutex_unlock( &global_lock ); + ret = epoll_wait( epoll_fd, events, ARRAY_SIZE( events ), timeout ); ++ pthread_mutex_lock( &global_lock ); + set_current_time(); + + /* put the events into the pollfd array first, like poll does */ + for (i = 0; i < ret; i++) + { + int user = events[i].data.u32; ++ if (user >= nb_users || pollfd[user].fd == -1 || poll_users[user]->poll_generation > generation) continue; + pollfd[user].revents = events[i].events; + } + +@@ -664,9 +678,11 @@ static inline void main_loop_epoll(void) + for (i = 0; i < ret; i++) + { + int user = events[i].data.u32; ++ if (user >= nb_users || pollfd[user].fd == -1 || poll_users[user]->poll_generation > generation) continue; + if (pollfd[user].revents) fd_poll_event( poll_users[user], pollfd[user].revents ); + } + } ++ pthread_mutex_unlock( &global_lock ); + } + + #elif defined(HAVE_KQUEUE) +@@ -737,13 +753,18 @@ static inline void main_loop_epoll(void) + + if (kqueue_fd == -1) return; + ++ pthread_mutex_lock( &global_lock ); + while (active_users) + { ++ unsigned long generation; ++ + timeout = get_next_timeout(); + + if (!active_users) break; /* last user removed by a timeout */ + if (kqueue_fd == -1) break; /* an error occurred with kqueue */ + ++ generation = poll_generation; ++ pthread_mutex_unlock( &global_lock ); + if (timeout != -1) + { + struct timespec ts; +@@ -753,6 +774,7 @@ static inline void main_loop_epoll(void) + ret = kevent( kqueue_fd, NULL, 0, events, ARRAY_SIZE( events ), &ts ); + } + else ret = kevent( kqueue_fd, NULL, 0, events, ARRAY_SIZE( events ), NULL ); ++ pthread_mutex_lock( &global_lock ); + + set_current_time(); + +@@ -760,11 +782,13 @@ static inline void main_loop_epoll(void) + for (i = 0; i < ret; i++) + { + long user = (long)events[i].udata; ++ if (user >= nb_users || pollfd[user].fd == -1 || poll_users[user]->poll_generation > generation) continue; + pollfd[user].revents = 0; + } + for (i = 0; i < ret; i++) + { + long user = (long)events[i].udata; ++ if (user >= nb_users || pollfd[user].fd == -1 || poll_users[user]->poll_generation > generation) continue; + if (events[i].filter == EVFILT_READ) pollfd[user].revents |= POLLIN; + else if (events[i].filter == EVFILT_WRITE) pollfd[user].revents |= POLLOUT; + if (events[i].flags & EV_EOF) pollfd[user].revents |= POLLHUP; +@@ -775,10 +799,12 @@ static inline void main_loop_epoll(void) + for (i = 0; i < ret; i++) + { + long user = (long)events[i].udata; ++ if (user >= nb_users || pollfd[user].fd == -1 || poll_users[user]->poll_generation > generation) continue; + if (pollfd[user].revents) fd_poll_event( poll_users[user], pollfd[user].revents ); + pollfd[user].revents = 0; + } + } ++ pthread_mutex_unlock( &global_lock ); + } + + #elif defined(USE_EVENT_PORTS) +@@ -839,14 +865,19 @@ static inline void main_loop_epoll(void) + + if (port_fd == -1) return; + ++ pthread_mutex_lock( &global_lock ); + while (active_users) + { ++ unsigned long generation; ++ + timeout = get_next_timeout(); + nget = 1; + + if (!active_users) break; /* last user removed by a timeout */ + if (port_fd == -1) break; /* an error occurred with event completion */ + ++ generation = poll_generation; ++ pthread_mutex_unlock( &global_lock ); + if (timeout != -1) + { + struct timespec ts; +@@ -856,6 +887,7 @@ static inline void main_loop_epoll(void) + ret = port_getn( port_fd, events, ARRAY_SIZE( events ), &nget, &ts ); + } + else ret = port_getn( port_fd, events, ARRAY_SIZE( events ), &nget, NULL ); ++ pthread_mutex_lock( &global_lock ); + + if (ret == -1) break; /* an error occurred with event completion */ + +@@ -865,6 +897,7 @@ static inline void main_loop_epoll(void) + for (i = 0; i < nget; i++) + { + long user = (long)events[i].portev_user; ++ if (user >= nb_users || pollfd[user].fd == -1 || poll_users[user]->poll_generation > generation) continue; + pollfd[user].revents = events[i].portev_events; + } + +@@ -872,6 +905,7 @@ static inline void main_loop_epoll(void) + for (i = 0; i < nget; i++) + { + long user = (long)events[i].portev_user; ++ if (user >= nb_users || pollfd[user].fd == -1 || poll_users[user]->poll_generation > generation) continue; + if (pollfd[user].revents) fd_poll_event( poll_users[user], pollfd[user].revents ); + /* if we are still interested, reassociate the fd */ + if (pollfd[user].fd != -1) { +@@ -879,6 +913,7 @@ static inline void main_loop_epoll(void) + } + } + } ++ pthread_mutex_unlock( &global_lock ); + } + + #else /* HAVE_KQUEUE */ +@@ -927,6 +962,7 @@ static int add_poll_user( struct fd *fd ) + pollfd[ret].events = 0; + pollfd[ret].revents = 0; + poll_users[ret] = fd; ++ fd->poll_generation = ++poll_generation; + active_users++; + return ret; + } +@@ -1012,30 +1048,66 @@ static int get_next_timeout(void) + return ret; + } + ++static void poll_exit_poll_event( struct fd *fd, int event ) ++{ ++ char dummy; ++ read( fd->unix_fd, &dummy, sizeof(dummy) ); ++} ++ ++static const struct fd_ops poll_exit_fd_ops = ++{ ++ NULL, /* get_poll_events */ ++ poll_exit_poll_event, /* poll_event */ ++ NULL, /* flush */ ++ NULL, /* get_fd_type */ ++ NULL, /* ioctl */ ++ NULL, /* queue_async */ ++ NULL /* reselect_async */ ++}; ++ ++static int create_poll_exit_fd( void ) ++{ ++ if (pipe( poll_exit_pipe )) return 0; ++ poll_exit_fd = create_anonymous_fd( &poll_exit_fd_ops, poll_exit_pipe[0], NULL, 0 ); ++ if (!poll_exit_fd) return 0; ++ set_fd_events( poll_exit_fd, POLLIN ); ++ return 1; ++} ++ ++ + /* server main poll() loop */ + void main_loop(void) + { + int i, ret, timeout; + ++ if (!create_poll_exit_fd()) return; ++ + set_current_time(); + server_start_time = current_time; + + main_loop_epoll(); + /* fall through to normal poll loop */ + ++ pthread_mutex_lock( &global_lock ); + while (active_users) + { ++ unsigned long generation; ++ + timeout = get_next_timeout(); + + if (!active_users) break; /* last user removed by a timeout */ + ++ generation = poll_generation; ++ pthread_mutex_unlock( &global_lock ); + ret = poll( pollfd, nb_users, timeout ); ++ pthread_mutex_lock( &global_lock ); + set_current_time(); + + if (ret > 0) + { + for (i = 0; i < nb_users; i++) + { ++ if (pollfd[i].fd == -1 || poll_users[i]->poll_generation > generation) continue; + if (pollfd[i].revents) + { + fd_poll_event( poll_users[i], pollfd[i].revents ); +@@ -1044,6 +1116,14 @@ void main_loop(void) + } + } + } ++ pthread_mutex_unlock( &global_lock ); ++} ++ ++/* global lock must be held */ ++void force_exit_poll( void ) ++{ ++ static char zero; ++ write( poll_exit_pipe[1], &zero, sizeof(zero) ); + } + + +@@ -1768,6 +1848,8 @@ void set_fd_events( struct fd *fd, int events ) + int user = fd->poll_index; + assert( poll_users[user] == fd ); + ++ fd->poll_generation = ++poll_generation; ++ + set_fd_epoll_events( fd, user, events ); + + if (events == -1) /* stop waiting on this fd completely */ +diff --git a/server/file.h b/server/file.h +index 11111111111..11111111111 100644 +--- a/server/file.h ++++ b/server/file.h +@@ -21,6 +21,7 @@ + #ifndef __WINE_SERVER_FILE_H + #define __WINE_SERVER_FILE_H + ++#include + #include + #include + +@@ -80,6 +81,9 @@ struct fd_ops + + /* file descriptor functions */ + ++extern pthread_mutex_t global_lock; ++extern unsigned long poll_generation; ++ + extern struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *user, + unsigned int options ); + extern struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_name, +@@ -133,6 +137,7 @@ extern void no_fd_queue_async( struct fd *fd, struct async *async, int type, int + extern void default_fd_queue_async( struct fd *fd, struct async *async, int type, int count ); + extern void default_fd_reselect_async( struct fd *fd, struct async_queue *queue ); + extern void main_loop(void); ++extern void force_exit_poll(void); + extern void remove_process_locks( struct process *process ); + + static inline struct fd *get_obj_fd( struct object *obj ) { return obj->ops->get_fd( obj ); } +diff --git a/server/request.c b/server/request.c +index 11111111111..11111111111 100644 +--- a/server/request.c ++++ b/server/request.c +@@ -261,6 +261,104 @@ void write_reply( struct thread *thread ) + fatal_protocol_error( thread, "reply write: %s\n", strerror( errno )); + } + ++/* send a reply to the current thread */ ++void send_reply_shm( union generic_reply *reply, struct request_shm *request_shm, data_size_t req_data_size ) ++{ ++ char *data_ptr = (char*)(request_shm + 1) + req_data_size; ++ unsigned int copy_limit = (char*)request_shm + REQUEST_SHM_SIZE - data_ptr; ++ int ret; ++ ++ /* fixed data is already written */ ++ if (!current->reply_size) ++ return; ++ ++ if (current->reply_size <= copy_limit) ++ { ++ memcpy( data_ptr, current->reply_data, current->reply_size ); ++ if (current->reply_data != current->rep_data) free( current->reply_data ); ++ current->reply_data = NULL; ++ return; ++ } ++ ++ memcpy( data_ptr, current->reply_data, copy_limit ); ++ current->reply_towrite = current->reply_size - copy_limit; ++ ++ if ((ret = write( get_unix_fd( current->reply_fd ), ++ (char *)current->reply_data + current->reply_size - current->reply_towrite, ++ current->reply_towrite )) >= 0) ++ { ++ if (!(current->reply_towrite -= ret)) ++ { ++ if (current->reply_data != current->rep_data) free( current->reply_data ); ++ current->reply_data = NULL; ++ } ++ else ++ { ++ /* couldn't write it all, wait for POLLOUT */ ++ set_fd_events( current->reply_fd, POLLOUT ); ++ set_fd_events( current->request_fd, 0 ); ++ } ++ return; ++ } ++ if (errno == EPIPE) ++ kill_thread( current, 0 ); /* normal death */ ++ else if (errno != EWOULDBLOCK && (EWOULDBLOCK == EAGAIN || errno != EAGAIN)) ++ fatal_protocol_error( current, "reply write: %s\n", strerror( errno )); ++} ++ ++/* call a request handler using shared memory */ ++static void call_req_handler_shm( struct thread *thread, struct request_shm *request_shm ) ++{ ++ enum request req = thread->req.request_header.req; ++ data_size_t data_size = thread->req.request_header.request_size; ++ ++ current = thread; ++ current->reply_size = 0; ++ clear_error(); ++ memset( &request_shm->u.reply, 0, sizeof(request_shm->u.reply) ); ++ ++ if (debug_level) trace_request(); ++ ++ if (req < REQ_NB_REQUESTS) ++ req_handlers[req]( ¤t->req, &request_shm->u.reply ); ++ else ++ set_error( STATUS_NOT_IMPLEMENTED ); ++ ++ if (current) ++ { ++ if (current->reply_fd) ++ { ++ request_shm->u.reply.reply_header.error = current->error; ++ request_shm->u.reply.reply_header.reply_size = current->reply_size; ++ if (debug_level) trace_reply( req, &request_shm->u.reply ); ++ send_reply_shm( &request_shm->u.reply, request_shm, data_size ); ++ } ++ else ++ { ++ current->exit_code = 1; ++ kill_thread( current, 1 ); /* no way to continue without reply fd */ ++ } ++ } ++ current = NULL; ++} ++ ++/* read a request from a thread using shared memory */ ++void read_request_shm( struct thread *thread, struct request_shm *request_shm ) ++{ ++ void *orig_req_data = thread->req_data; ++ data_size_t data_size; ++ ++ memcpy( &thread->req, &request_shm->u.req, sizeof(thread->req) ); ++ data_size = thread->req.request_header.request_size; ++ if (data_size) ++ thread->req_data = request_shm + 1; ++ ++ call_req_handler_shm( thread, request_shm ); ++ ++ if (data_size) ++ thread->req_data = orig_req_data; ++} ++ + /* send a reply to the current thread */ + void send_reply( union generic_reply *reply ) + { +diff --git a/server/request.h b/server/request.h +index 11111111111..11111111111 100644 +--- a/server/request.h ++++ b/server/request.h +@@ -52,6 +52,7 @@ extern const struct object_attributes *get_req_object_attributes( const struct s + extern const void *get_req_data_after_objattr( const struct object_attributes *attr, data_size_t *len ); + extern int receive_fd( struct process *process ); + extern int send_client_fd( struct process *process, int fd, obj_handle_t handle ); ++extern void read_request_shm( struct thread *thread, struct request_shm *request_shm ); + extern void read_request( struct thread *thread ); + extern void write_reply( struct thread *thread ); + extern timeout_t monotonic_counter(void); +diff --git a/server/thread.c b/server/thread.c +index 11111111111..11111111111 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -44,6 +45,9 @@ + #ifdef HAVE_SYS_RESOURCE_H + #include + #endif ++#ifdef HAVE_SYS_SYSCALL_H ++#include ++#endif + + #include "ntstatus.h" + #define WIN32_NO_STATUS +@@ -378,6 +382,7 @@ static inline void init_thread_structure( struct thread *thread ) + #ifdef __linux__ + thread->request_shm_fd = -1; + thread->request_shm = NULL; ++ thread->request_shm_thread_running = 0; + #endif + thread->state = RUNNING; + thread->exit_code = 0; +@@ -446,6 +451,86 @@ static struct context *create_thread_context( struct thread *thread ) + } + + ++#ifdef __linux__ ++ ++static void handle_shm_request( struct thread *thread, struct request_shm *request_shm ) ++{ ++ set_current_time(); ++ read_request_shm( thread, request_shm ); ++} ++ ++ ++#define FUTEX_WAIT 0 ++#define FUTEX_WAKE 1 ++ ++static void *request_shm_thread(void *param) ++{ ++ struct thread *thread = param; ++ int request_shm_fd; ++ volatile struct request_shm *request_shm; ++ unsigned long generation = 0; ++ ++ pthread_mutex_lock( &global_lock ); ++ request_shm_fd = thread->request_shm_fd; ++ request_shm = thread->request_shm; ++ pthread_mutex_unlock( &global_lock ); ++ ++ for (;;) ++ { ++ int val; ++ ++ while ((val = request_shm->futex) != 1) ++ { ++ if (val == -1) ++ goto done; ++ else if (val != 0) ++ fatal_protocol_error( thread, "unknown futex state %d\n", val ); ++ syscall( __NR_futex, &request_shm->futex, FUTEX_WAIT, val, NULL, NULL, 0 ); ++ } ++ ++ pthread_mutex_lock( &global_lock ); ++ generation = poll_generation; ++ ++ val = request_shm->futex; ++ if (val != 1) ++ { ++ if (val != -1) ++ fatal_protocol_error( thread, "unknown futex state %d\n", val ); ++ goto done_locked; ++ } ++ ++ __asm__ __volatile__ ("" ::: "memory"); ++ handle_shm_request( thread, (struct request_shm *)request_shm ); ++ __asm__ __volatile__ ("" ::: "memory"); ++ ++ request_shm_fd = thread->request_shm_fd; ++ request_shm = thread->request_shm; ++ if (!request_shm_fd || !request_shm) ++ goto done_locked; ++ val = __sync_val_compare_and_swap( &request_shm->futex, 1, 0 ); ++ if (val != 1 && val != -1) ++ fatal_protocol_error( thread, "unknown futex state %d\n", val ); ++ pthread_mutex_unlock( &global_lock ); ++ syscall( __NR_futex, &request_shm->futex, FUTEX_WAKE, 1, NULL, NULL, 0 ); ++ if (poll_generation != generation) ++ force_exit_poll(); ++ } ++ ++done: ++ pthread_mutex_lock( &global_lock ); ++done_locked: ++ if (request_shm_fd != -1) close( request_shm_fd ); ++ if (request_shm) munmap( (void*)request_shm, REQUEST_SHM_SIZE ); ++ release_object( thread ); ++ pthread_mutex_unlock( &global_lock ); ++ if (poll_generation != generation) ++ force_exit_poll(); ++ return NULL; ++} ++ ++#endif /* defined(__linux__) */ ++ ++ + static struct context *create_thread_context( struct thread *thread ) + { + struct context *context; +@@ -504,6 +589,9 @@ struct thread *create_thread( int fd, struct process *process, const struct secu + struct desktop *desktop; + struct thread *thread; + int request_pipe[2]; ++#ifdef __linux__ ++ pthread_t pthread; ++#endif + + if (memory_barrier_obj) + grab_object( &memory_barrier_obj->obj ); +@@ -596,6 +684,16 @@ struct thread *create_thread( int fd, struct process *process, const struct secu + release_object( thread ); + return NULL; + } ++ ++ grab_object( thread ); ++ if (pthread_create( &pthread, NULL, request_shm_thread, thread )) ++ { ++ release_object( thread ); ++ release_object( thread ); ++ return NULL; ++ } ++ pthread_detach( pthread ); ++ thread->request_shm_thread_running = 1; + #endif + + if (do_fsync()) +@@ -666,8 +764,16 @@ static void cleanup_thread( struct thread *thread ) + if (thread->reply_fd) release_object( thread->reply_fd ); + if (thread->wait_fd) release_object( thread->wait_fd ); + #ifdef __linux__ +- if (thread->request_shm_fd != -1) close( thread->request_shm_fd ); +- if (thread->request_shm) munmap( (void*)thread->request_shm, REQUEST_SHM_SIZE ); ++ if (thread->request_shm) ++ { ++ __atomic_exchange_n( &thread->request_shm->futex, -1, __ATOMIC_SEQ_CST ); ++ syscall( __NR_futex, &thread->request_shm->futex, FUTEX_WAKE, 1, NULL, NULL, 0 ); ++ } ++ if (!thread->request_shm_thread_running) ++ { ++ if (thread->request_shm_fd != -1) close( thread->request_shm_fd ); ++ if (thread->request_shm) munmap( (void*)thread->request_shm, REQUEST_SHM_SIZE ); ++ } + #endif + cleanup_clipboard_thread(thread); + destroy_thread_windows( thread ); +@@ -695,6 +801,7 @@ static void cleanup_thread( struct thread *thread ) + #ifdef __linux__ + thread->request_shm_fd = -1; + thread->request_shm = NULL; ++ thread->request_shm_thread_running = 0; + #endif + thread->desktop = 0; + thread->desc = NULL; +diff --git a/server/thread.h b/server/thread.h +index 11111111111..11111111111 100644 +--- a/server/thread.h ++++ b/server/thread.h +@@ -93,6 +93,7 @@ struct thread + #ifdef __linux__ + int request_shm_fd; /* request shared memory fd */ + volatile struct request_shm *request_shm; /* shared memory for receiving and sending client requests/replies */ ++ int request_shm_thread_running; + #endif + enum run_state state; /* running state */ + int exit_code; /* thread exit code */ +-- +0.0.0 + diff --git a/0013-server-optimization/0002-threaded-server/ps0435-p0003-server-Write-reply-data-directly-to-shared-m.patch b/0013-server-optimization/0002-threaded-server/ps0435-p0003-server-Write-reply-data-directly-to-shared-m.patch new file mode 100644 index 0000000..a64e364 --- /dev/null +++ b/0013-server-optimization/0002-threaded-server/ps0435-p0003-server-Write-reply-data-directly-to-shared-m.patch @@ -0,0 +1,165 @@ +From 50a1e01f2af43c2e8600bd0b16406b19a1e38909 Mon Sep 17 00:00:00 2001 +From: Torge Matthies +Date: Sat, 6 Aug 2022 20:29:00 +0200 +Subject: [PATCH 3/8] server: Write reply data directly to shared memory if + possible. + +--- + server/request.c | 35 ++++++++++++++++++++++++----------- + server/thread.c | 28 ++++++++++++++++++++++++++-- + server/thread.h | 1 + + 3 files changed, 51 insertions(+), 13 deletions(-) + +diff --git a/server/request.c b/server/request.c +index 11111111111..11111111111 100644 +--- a/server/request.c ++++ b/server/request.c +@@ -162,10 +162,23 @@ void fatal_error( const char *err, ... ) + exit(1); + } + ++int reply_in_shm; ++ + /* allocate the reply data */ + void *set_reply_data_size( data_size_t size ) + { + assert( size <= get_reply_max_size() ); ++ if (current->request_shm && reply_in_shm) ++ { ++ char *data_ptr = (char*)(current->request_shm + 1) + current->req.request_header.request_size; ++ unsigned int size_limit = (char*)current->request_shm + REQUEST_SHM_SIZE - data_ptr; ++ if (size_limit >= size) ++ { ++ current->reply_data = data_ptr; ++ current->reply_size = size; ++ return current->reply_data; ++ } ++ } + if (size > current->rep_data_size) + { + if (current->rep_data) free(current->rep_data); +@@ -247,8 +260,7 @@ void write_reply( struct thread *thread ) + { + if (!(thread->reply_towrite -= ret)) + { +- if (thread->reply_data != thread->rep_data) free( thread->reply_data ); +- thread->reply_data = NULL; ++ cleanup_thread_reply_data( thread ); + /* sent everything, can go back to waiting for requests */ + set_fd_events( thread->request_fd, POLLIN ); + set_fd_events( thread->reply_fd, 0 ); +@@ -272,11 +284,14 @@ void send_reply_shm( union generic_reply *reply, struct request_shm *request_shm + if (!current->reply_size) + return; + ++ if ((char*)current->reply_data >= (char*)request_shm && ++ (char*)current->reply_data < (char*)request_shm + REQUEST_SHM_SIZE) ++ return; ++ + if (current->reply_size <= copy_limit) + { + memcpy( data_ptr, current->reply_data, current->reply_size ); +- if (current->reply_data != current->rep_data) free( current->reply_data ); +- current->reply_data = NULL; ++ cleanup_thread_reply_data( current ); + return; + } + +@@ -288,10 +303,7 @@ void send_reply_shm( union generic_reply *reply, struct request_shm *request_shm + current->reply_towrite )) >= 0) + { + if (!(current->reply_towrite -= ret)) +- { +- if (current->reply_data != current->rep_data) free( current->reply_data ); +- current->reply_data = NULL; +- } ++ cleanup_thread_reply_data( current ); + else + { + /* couldn't write it all, wait for POLLOUT */ +@@ -352,10 +364,12 @@ void read_request_shm( struct thread *thread, struct request_shm *request_shm ) + data_size = thread->req.request_header.request_size; + if (data_size) + thread->req_data = request_shm + 1; ++ reply_in_shm = 1; + + call_req_handler_shm( thread, request_shm ); + +- if (data_size) ++ reply_in_shm = 0; ++ if (data_size && thread->req_data == request_shm + 1) + thread->req_data = orig_req_data; + } + +@@ -382,8 +396,7 @@ void send_reply( union generic_reply *reply ) + return; + } + +- if (current->reply_data != current->rep_data) free( current->reply_data ); +- current->reply_data = NULL; ++ cleanup_thread_reply_data( current ); + return; + + error: +diff --git a/server/thread.c b/server/thread.c +index 11111111111..11111111111 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -742,6 +742,30 @@ static struct fast_sync *thread_get_fast_sync( struct object *obj ) + return thread->fast_sync; + } + ++void cleanup_thread_reply_data( struct thread *thread ) ++{ ++ if (thread->reply_data == thread->rep_data) ++ return; ++ ++ if (thread->request_shm && ++ (char*)thread->reply_data >= (char*)thread->request_shm && ++ (char*)thread->reply_data < (char*)thread->request_shm + REQUEST_SHM_SIZE) ++ return; ++ ++ free( thread->reply_data ); ++ thread->reply_data = NULL; ++} ++ ++void cleanup_thread_req_data( struct thread *thread ) ++{ ++ if (thread->request_shm && ++ (char*)thread->req_data >= (char*)thread->request_shm && ++ (char*)thread->req_data < (char*)thread->request_shm + REQUEST_SHM_SIZE) ++ return; ++ ++ free( thread->req_data ); ++} ++ + /* cleanup everything that is no longer needed by a dead thread */ + /* used by destroy_thread and kill_thread */ + static void cleanup_thread( struct thread *thread ) +@@ -757,9 +781,9 @@ static void cleanup_thread( struct thread *thread ) + } + clear_apc_queue( &thread->system_apc ); + clear_apc_queue( &thread->user_apc ); +- free( thread->req_data ); ++ cleanup_thread_req_data( thread ); + free( thread->rep_data ); +- if (thread->reply_data != thread->rep_data) free( thread->reply_data ); ++ cleanup_thread_reply_data( thread ); + if (thread->request_fd) release_object( thread->request_fd ); + if (thread->reply_fd) release_object( thread->reply_fd ); + if (thread->wait_fd) release_object( thread->wait_fd ); +diff --git a/server/thread.h b/server/thread.h +index 11111111111..11111111111 100644 +--- a/server/thread.h ++++ b/server/thread.h +@@ -132,6 +132,7 @@ extern struct thread *current; + + extern struct thread *create_thread( int fd, struct process *process, + const struct security_descriptor *sd ); ++extern void cleanup_thread_reply_data( struct thread *thread ); + extern struct thread *get_thread_from_id( thread_id_t id ); + extern struct thread *get_thread_from_handle( obj_handle_t handle, unsigned int access ); + extern struct thread *get_thread_from_tid( int tid ); +-- +0.0.0 + diff --git a/0013-server-optimization/0002-threaded-server/ps0435-p0004-HACK-ntdll-server-Spin-instead-of-wait-for-f.patch b/0013-server-optimization/0002-threaded-server/ps0435-p0004-HACK-ntdll-server-Spin-instead-of-wait-for-f.patch new file mode 100644 index 0000000..88b40b4 --- /dev/null +++ b/0013-server-optimization/0002-threaded-server/ps0435-p0004-HACK-ntdll-server-Spin-instead-of-wait-for-f.patch @@ -0,0 +1,40 @@ +From d658f3e6d8d379d428f60d3f7156f2a09e76db18 Mon Sep 17 00:00:00 2001 +From: Torge Matthies +Date: Mon, 8 Aug 2022 20:19:28 +0200 +Subject: [PATCH 4/8] HACK: ntdll,server: Spin instead of wait for futex + +--- + dlls/ntdll/unix/server.c | 3 ++- + server/thread.c | 2 +- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c +index 11111111111..11111111111 100644 +--- a/dlls/ntdll/unix/server.c ++++ b/dlls/ntdll/unix/server.c +@@ -247,7 +247,8 @@ static inline unsigned int wait_reply_shm( struct __server_request_info *req ) + { + if (val == -1) + abort_thread(0); +- syscall( __NR_futex, &request_shm->futex, FUTEX_WAIT, val, NULL, NULL, 0 ); ++ //syscall( __NR_futex, &request_shm->futex, FUTEX_WAIT, val, NULL, NULL, 0 ); ++ YieldProcessor(); + } + + memcpy( &req->u.reply, (void*)&request_shm->u.reply, sizeof(req->u.reply) ); +diff --git a/server/thread.c b/server/thread.c +index 11111111111..11111111111 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -511,7 +511,7 @@ static void *request_shm_thread(void *param) + if (val != 1 && val != -1) + fatal_protocol_error( thread, "unknown futex state %d\n", val ); + pthread_mutex_unlock( &global_lock ); +- syscall( __NR_futex, &request_shm->futex, FUTEX_WAKE, 1, NULL, NULL, 0 ); ++ //syscall( __NR_futex, &request_shm->futex, FUTEX_WAKE, 1, NULL, NULL, 0 ); + if (poll_generation != generation) + force_exit_poll(); + } +-- +0.0.0 + diff --git a/0013-server-optimization/0002-threaded-server/ps0435-p0005-HACK-server-Do-not-use-an-atomic-instruction.patch b/0013-server-optimization/0002-threaded-server/ps0435-p0005-HACK-server-Do-not-use-an-atomic-instruction.patch new file mode 100644 index 0000000..809bc25 --- /dev/null +++ b/0013-server-optimization/0002-threaded-server/ps0435-p0005-HACK-server-Do-not-use-an-atomic-instruction.patch @@ -0,0 +1,31 @@ +From 481c3131ad21fc62f45dc4b7c421926805d95285 Mon Sep 17 00:00:00 2001 +From: Torge Matthies +Date: Mon, 15 Aug 2022 21:03:25 +0200 +Subject: [PATCH 5/8] HACK: server: Do not use an atomic instruction to reset + futex. + +--- + server/thread.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/server/thread.c b/server/thread.c +index 11111111111..11111111111 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -507,8 +507,11 @@ static void *request_shm_thread(void *param) + request_shm = thread->request_shm; + if (!request_shm_fd || !request_shm) + goto done_locked; +- val = __sync_val_compare_and_swap( &request_shm->futex, 1, 0 ); +- if (val != 1 && val != -1) ++ __sync_synchronize(); ++ val = request_shm->futex; ++ if (val == 1) ++ request_shm->futex = 0; ++ else if (val != -1) + fatal_protocol_error( thread, "unknown futex state %d\n", val ); + pthread_mutex_unlock( &global_lock ); + //syscall( __NR_futex, &request_shm->futex, FUTEX_WAKE, 1, NULL, NULL, 0 ); +-- +0.0.0 + diff --git a/0013-server-optimization/0002-threaded-server/ps0435-p0006-HACK-server-Spin-on-the-request-futex-for-a-.patch b/0013-server-optimization/0002-threaded-server/ps0435-p0006-HACK-server-Spin-on-the-request-futex-for-a-.patch new file mode 100644 index 0000000..dfd1e3e --- /dev/null +++ b/0013-server-optimization/0002-threaded-server/ps0435-p0006-HACK-server-Spin-on-the-request-futex-for-a-.patch @@ -0,0 +1,47 @@ +From b7a8b42e4aa284288672c04ade38e5c50f918b52 Mon Sep 17 00:00:00 2001 +From: Torge Matthies +Date: Mon, 15 Aug 2022 21:04:27 +0200 +Subject: [PATCH 6/8] HACK: server: Spin on the request futex for a little bit + after completing a request. + +--- + server/thread.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/server/thread.c b/server/thread.c +index 11111111111..11111111111 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -478,14 +479,20 @@ static void *request_shm_thread(void *param) + for (;;) + { + int val; ++ int spincount = 2000; + ++ if ((val = request_shm->futex) != 1) ++ sched_yield(); + while ((val = request_shm->futex) != 1) + { + if (val == -1) + goto done; + else if (val != 0) + fatal_protocol_error( thread, "unknown futex state %d\n", val ); +- syscall( __NR_futex, &request_shm->futex, FUTEX_WAIT, val, NULL, NULL, 0 ); ++ if (spincount == 0) ++ syscall( __NR_futex, &request_shm->futex, FUTEX_WAIT, val, NULL, NULL, 0 ); ++ else ++ --spincount; + } + + pthread_mutex_lock( &global_lock ); +-- +0.0.0 + diff --git a/0013-server-optimization/0002-threaded-server/ps0435-p0007-STAGING-server-Propagate-main-thread-schedul.patch b/0013-server-optimization/0002-threaded-server/ps0435-p0007-STAGING-server-Propagate-main-thread-schedul.patch new file mode 100644 index 0000000..637c3a5 --- /dev/null +++ b/0013-server-optimization/0002-threaded-server/ps0435-p0007-STAGING-server-Propagate-main-thread-schedul.patch @@ -0,0 +1,36 @@ +From e59d96f59742a9074ae44576aa350764f50675dd Mon Sep 17 00:00:00 2001 +From: Torge Matthies +Date: Fri, 20 Jan 2023 18:31:18 +0100 +Subject: [PATCH 7/8] STAGING: server: Propagate main thread scheduling priority to + shm request threads. + +--- + server/thread.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/server/thread.c b/server/thread.c +index 11111111111..11111111111 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -601,6 +601,8 @@ struct thread *create_thread( int fd, struct process *process, const struct secu + int request_pipe[2]; + #ifdef __linux__ + pthread_t pthread; ++ int policy; ++ struct sched_param param; + #endif + + if (memory_barrier_obj) +@@ -702,6 +704,9 @@ struct thread *create_thread( int fd, struct process *process, const struct secu + release_object( thread ); + return NULL; + } ++ if (!pthread_getschedparam( pthread_self(), &policy, ¶m ) && (policy || param.sched_priority)) ++ if (pthread_setschedparam( pthread, policy | SCHED_RESET_ON_FORK, ¶m )) ++ pthread_setschedparam( pthread, policy, ¶m ); + pthread_detach( pthread ); + thread->request_shm_thread_running = 1; + #endif +-- +0.0.0 + diff --git a/0013-server-optimization/0002-threaded-server/ps0435-p0008-HACK-ntdll-Track-spin-timeout-counts-and-sto.patch b/0013-server-optimization/0002-threaded-server/ps0435-p0008-HACK-ntdll-Track-spin-timeout-counts-and-sto.patch new file mode 100644 index 0000000..2e5e5e8 --- /dev/null +++ b/0013-server-optimization/0002-threaded-server/ps0435-p0008-HACK-ntdll-Track-spin-timeout-counts-and-sto.patch @@ -0,0 +1,80 @@ +From 40145ff85b39d69a0a53a8534e2431d75b51a765 Mon Sep 17 00:00:00 2001 +From: Torge Matthies +Date: Sat, 24 Jun 2023 16:34:51 +0200 +Subject: [PATCH 8/8] HACK: ntdll: Track spin timeout counts and stop spinning + after a certain number of timeouts. + +--- + dlls/ntdll/unix/server.c | 27 +++++++++++++++++++++++++-- + server/thread.c | 2 +- + 2 files changed, 26 insertions(+), 3 deletions(-) + +diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c +index 11111111111..11111111111 100644 +--- a/dlls/ntdll/unix/server.c ++++ b/dlls/ntdll/unix/server.c +@@ -231,6 +231,9 @@ static unsigned int send_request_shm( const struct __server_request_info *req ) + + static void read_reply_data( void *buffer, size_t size ); + ++unsigned int request_spin_timeout_count[REQ_NB_REQUESTS]; ++unsigned int request_spin_success_count[REQ_NB_REQUESTS]; ++ + /*********************************************************************** + * wait_reply_shm + * +@@ -241,16 +244,36 @@ static inline unsigned int wait_reply_shm( struct __server_request_info *req ) + volatile struct request_shm *request_shm = ntdll_get_thread_data()->request_shm; + char *data_ptr = (char*)(request_shm + 1) + req->u.req.request_header.request_size; + unsigned int copy_limit = (char*)request_shm + REQUEST_SHM_SIZE - data_ptr; ++ enum request req_nr = req->u.req.request_header.req; ++ unsigned int spincount = 8000; + int val; + +- while ((val = request_shm->futex) != 0) ++ if ((request_spin_timeout_count[req_nr] * 64) > request_spin_success_count[req_nr] + 2048) ++ goto no_spin; ++ ++ while (spincount > 0 && (val = request_shm->futex) != 0) + { + if (val == -1) + abort_thread(0); +- //syscall( __NR_futex, &request_shm->futex, FUTEX_WAIT, val, NULL, NULL, 0 ); ++ spincount--; + YieldProcessor(); + } + ++ if (spincount) ++ InterlockedIncrement( &request_spin_success_count[req_nr] ); ++ else ++ { ++ InterlockedIncrement( &request_spin_timeout_count[req_nr] ); ++ ++ no_spin:; ++ while ((val = request_shm->futex) != 0) ++ { ++ if (val == -1) ++ abort_thread(0); ++ syscall( __NR_futex, &request_shm->futex, FUTEX_WAIT, val, NULL, NULL, 0 ); ++ } ++ } ++ + memcpy( &req->u.reply, (void*)&request_shm->u.reply, sizeof(req->u.reply) ); + if (req->u.reply.reply_header.reply_size) + { +diff --git a/server/thread.c b/server/thread.c +index 11111111111..11111111111 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -521,7 +521,7 @@ static void *request_shm_thread(void *param) + else if (val != -1) + fatal_protocol_error( thread, "unknown futex state %d\n", val ); + pthread_mutex_unlock( &global_lock ); +- //syscall( __NR_futex, &request_shm->futex, FUTEX_WAKE, 1, NULL, NULL, 0 ); ++ syscall( __NR_futex, &request_shm->futex, FUTEX_WAKE, 1, NULL, NULL, 0 ); + if (poll_generation != generation) + force_exit_poll(); + } +-- +0.0.0 + diff --git a/0013-server-optimization/0002-threaded-server/ps0435-p0009-HACK-ntdll-Use-mwaitx-if-available.patch b/0013-server-optimization/0002-threaded-server/ps0435-p0009-HACK-ntdll-Use-mwaitx-if-available.patch new file mode 100644 index 0000000..ab0f5ea --- /dev/null +++ b/0013-server-optimization/0002-threaded-server/ps0435-p0009-HACK-ntdll-Use-mwaitx-if-available.patch @@ -0,0 +1,118 @@ +From dfd4f6e375524b320e7bbb892b42bc22ab5fac0a Mon Sep 17 00:00:00 2001 +From: Torge Matthies +Date: Thu, 3 Aug 2023 22:10:18 +0200 +Subject: [PATCH 9/9] HACK: ntdll: Use mwaitx if available. + +--- + dlls/ntdll/unix/server.c | 88 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 88 insertions(+) + +diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c +index 11111111111..11111111111 100644 +--- a/dlls/ntdll/unix/server.c ++++ b/dlls/ntdll/unix/server.c +@@ -229,6 +229,84 @@ static unsigned int send_request_shm( const struct __server_request_info *req ) + } + + ++#if defined(__x86_64__) || defined(__i386__) ++ ++#if __GNUC__ > 8 || (__GNUC__ == 8 && __GNUC_MINOR__ >= 3) ++#define __asm_inline__ __inline__ ++#else ++#define __asm_inline__ ++#endif ++ ++static inline int mwaitx_supported(void) ++{ ++ static int supported; ++ if (!supported) ++ { ++ unsigned int eax, ecx; ++ __asm__ __volatile__ ( ++ "cpuid" ++ : "=a" (eax), "=c" (ecx) ++ : "a" (0x80000001U) ++ : "ebx", "edx" ++ ); ++ if (ecx & (1U << 29)) ++ supported = 3; ++ else ++ supported = 2; ++ } ++ return supported & 1; ++} ++ ++#define DEFINE_MWAITX(name, type) \ ++ void name(type *addr, type value, unsigned int timeout) \ ++ { \ ++ if (*addr != value) \ ++ return; \ ++ __asm__ __asm_inline__ __volatile__ ( \ ++ ".byte 0x0f,0x01,0xfa" /* monitorx */ \ ++ : "+m" (*(volatile type*)addr) \ ++ : "a" (addr), "c" (0x0U), "d" (0x0U) \ ++ ); \ ++ if (__builtin_expect(*addr != value, 0)) \ ++ return; \ ++ if (__builtin_constant_p(timeout) && timeout == 0) \ ++ { \ ++ __asm__ __volatile__ ( \ ++ ".byte 0x0f,0x01,0xfb" /* mwaitx */ \ ++ : "+m" (*(volatile type*)addr) \ ++ : "a" (0xF0U), "c" (0x0U) \ ++ ); \ ++ } \ ++ else \ ++ { \ ++ __asm__ __volatile__ ( \ ++ ".byte 0x0f,0x01,0xfb" /* mwaitx */ \ ++ : "+m" (*(volatile type*)addr) \ ++ : "a" (0xF0U), "b" (timeout), "c" (0x2U) \ ++ ); \ ++ } \ ++ } ++ ++#else ++ ++#define mwaitx_supported() 0 ++ ++#define DEFINE_MWAITX(name, type) \ ++ static inline void name(type *addr, type value, unsigned int timeout) {} ++ ++#endif ++ ++static inline DEFINE_MWAITX(mwaitxc, unsigned char) ++static inline DEFINE_MWAITX(mwaitxs, unsigned short) ++static inline DEFINE_MWAITX(mwaitx, unsigned int) ++static inline DEFINE_MWAITX(mwaitxl, unsigned long long) ++static inline DEFINE_MWAITX(mwaitxll, unsigned long long) ++#define mwaitx8(a,v) mwaitxc(a,v) ++#define mwaitx16(a,v) mwaitxs(a,v) ++#define mwaitx32(a,v) mwaitx(a,v) ++#define mwaitx64(a,v) mwaitxll(a,v) ++ ++ + static void read_reply_data( void *buffer, size_t size ); + + unsigned int request_spin_timeout_count[REQ_NB_REQUESTS]; +@@ -251,6 +329,16 @@ static inline unsigned int wait_reply_shm( struct __server_request_info *req ) + if ((request_spin_timeout_count[req_nr] * 64) > request_spin_success_count[req_nr] + 2048) + goto no_spin; + ++ if (mwaitx_supported()) ++ { ++ if ((val = request_shm->futex) != 0) ++ mwaitx(&request_shm->futex, val, 10000U); ++ if (request_shm->futex != 0) ++ spincount = 400; ++ else ++ spincount = 1; ++ } ++ + while (spincount > 0 && (val = request_shm->futex) != 0) + { + if (val == -1) +-- +0.0.0 + diff --git a/0013-server-optimization/0002-threaded-server/server-Set-a-proper-thread-description-for-each-requ.patch b/0013-server-optimization/0002-threaded-server/server-Set-a-proper-thread-description-for-each-requ.patch new file mode 100644 index 0000000..0c2d2a7 --- /dev/null +++ b/0013-server-optimization/0002-threaded-server/server-Set-a-proper-thread-description-for-each-requ.patch @@ -0,0 +1,213 @@ +From ae28b0be95145cd7fa3471c338a4cf5c1fd94932 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Thu, 19 Sep 2024 11:39:32 -0700 +Subject: [PATCH] server: Set each wineserver thread's description also when + thread->desc is set. + +--- + server/thread.c | 77 +++++++++++++++++++++++++++++++++++++++++++ + server/thread.h | 87 ++++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 163 insertions(+), 1 deletion(-) + +diff --git a/server/thread.c b/server/thread.c +index edd65ae3a68..de6b02a19d4 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -1077,6 +1077,79 @@ int set_thread_priority( struct thread* thread, int priority_class, int priority + return 0; /* ignore errors for now */ + } + ++#define MAX_THREAD_NAME_LENGTH 16 ++#define MAX_RETRIES 5 ++#define RETRY_DELAY_US 1000 ++ ++static void set_shm_thread_name(const WCHAR *desc, size_t desc_len) ++{ ++ if (!desc || desc_len == 0 || desc_len > 1024) ++ return; ++ ++ char converted_name[MAX_THREAD_NAME_LENGTH]; ++ int conversion_result = __utf8_wcstombs(converted_name, sizeof(converted_name) - 1, desc, desc_len); ++ ++ if (conversion_result != STATUS_SUCCESS && conversion_result != STATUS_BUFFER_TOO_SMALL) ++ return; ++ ++ converted_name[sizeof(converted_name) - 1] = '\0'; ++ ++ /* remove any partial UTF-8 character at the end */ ++ size_t i = strnlen(converted_name, sizeof(converted_name) - 1); ++ while (i > 0 && (converted_name[i - 1] & 0xC0) == 0x80) ++ i--; ++ converted_name[i] = '\0'; ++ ++ /* name empty after conversion */ ++ if (converted_name[0] == '\0') ++ return; ++ ++ pid_t tid = gettid(); ++ ++ if (tid == 0) { ++ if (debug_level) ++ fprintf(stderr, "failed to get thread ID for tid %d\n", tid); ++ return; ++ } ++ ++ char path[64]; ++ snprintf(path, sizeof(path), "/proc/self/task/%d/comm", tid); ++ ++ int retries = 0; ++ while (retries < MAX_RETRIES) ++ { ++ int fd = open(path, O_WRONLY); ++ if (fd != -1) ++ { ++ ssize_t written = write(fd, converted_name, strlen(converted_name)); ++ close(fd); ++ ++ if (written > 0) ++ { ++ if (debug_level) ++ fprintf(stderr, "successfully wrote '%s' to %s for tid %d\n", ++ converted_name, path, (unsigned long)tid); ++ return; ++ } ++ } ++ ++ if (errno != ENOENT) ++ { ++ if (debug_level) ++ fprintf(stderr, "failed to write '%s' to %s for tid %d: %s\n", ++ converted_name, path, tid, strerror(errno)); ++ return; ++ } ++ ++ usleep(RETRY_DELAY_US); ++ retries++; ++ } ++ ++ if (debug_level) ++ fprintf(stderr, "failed to write '%s' to %s for tid %d after %d retries\n", ++ converted_name, path, tid, MAX_RETRIES); ++} ++ + /* set all information about a thread */ + static void set_thread_info( struct thread *thread, + const struct set_thread_info_request *req ) +@@ -1114,6 +1187,9 @@ static void set_thread_info( struct thread *thread, + free( thread->desc ); + thread->desc = desc; + thread->desc_len = desc_len; ++#ifdef __linux__ ++ set_shm_thread_name(thread->desc, thread->desc_len); ++#endif + } + } + else +diff --git a/server/thread.h b/server/thread.h +index 21dfbba321f..7e57d3d2bbb 100644 +--- a/server/thread.h ++++ b/server/thread.h +@@ -22,7 +22,8 @@ + #define __WINE_SERVER_THREAD_H + + #include "object.h" +- ++#include "ntstatus.h" ++#define WIN32_NO_STATUS + /* thread structure */ + + struct process; +@@ -47,6 +48,90 @@ struct inflight_fd + #define MAX_INFLIGHT_FDS 16 /* max number of fds in flight per thread */ + + #ifdef __linux__ ++ ++#define HIGH_SURROGATE_START 0xd800 ++#define HIGH_SURROGATE_END 0xdbff ++#define LOW_SURROGATE_START 0xdc00 ++#define LOW_SURROGATE_END 0xdfff ++ ++#define IS_HIGH_SURROGATE(ch) ((ch) >= HIGH_SURROGATE_START && (ch) <= HIGH_SURROGATE_END) ++#define IS_LOW_SURROGATE(ch) ((ch) >= LOW_SURROGATE_START && (ch) <= LOW_SURROGATE_END) ++#define IS_SURROGATE_PAIR(high,low) (IS_HIGH_SURROGATE(high) && IS_LOW_SURROGATE(low)) ++ ++/* copied from dlls/ntdll/locale_private.h */ ++static inline int __get_utf16( const WCHAR *src, unsigned int srclen, unsigned int *ch ) ++{ ++ if (IS_HIGH_SURROGATE( src[0] )) ++ { ++ if (srclen <= 1) return 0; ++ if (!IS_LOW_SURROGATE( src[1] )) return 0; ++ *ch = 0x10000 + ((src[0] & 0x3ff) << 10) + (src[1] & 0x3ff); ++ return 2; ++ } ++ if (IS_LOW_SURROGATE( src[0] )) return 0; ++ *ch = src[0]; ++ return 1; ++} ++ ++/* copied from dlls/ntdll/locale_private.h */ ++static inline NTSTATUS __utf8_wcstombs( char *dst, unsigned int dstlen, const WCHAR *src, unsigned int srclen ) ++{ ++ char *end; ++ unsigned int val; ++ NTSTATUS status = 0; ++ ++ for (end = dst + dstlen; srclen; srclen--, src++) ++ { ++ WCHAR ch = *src; ++ ++ if (ch < 0x80) /* 0x00-0x7f: 1 byte */ ++ { ++ if (dst > end - 1) break; ++ *dst++ = ch; ++ continue; ++ } ++ if (ch < 0x800) /* 0x80-0x7ff: 2 bytes */ ++ { ++ if (dst > end - 2) break; ++ dst[1] = 0x80 | (ch & 0x3f); ++ ch >>= 6; ++ dst[0] = 0xc0 | ch; ++ dst += 2; ++ continue; ++ } ++ if (!__get_utf16( src, srclen, &val )) ++ { ++ val = 0xfffd; ++ status = STATUS_SOME_NOT_MAPPED; ++ } ++ if (val < 0x10000) /* 0x800-0xffff: 3 bytes */ ++ { ++ if (dst > end - 3) break; ++ dst[2] = 0x80 | (val & 0x3f); ++ val >>= 6; ++ dst[1] = 0x80 | (val & 0x3f); ++ val >>= 6; ++ dst[0] = 0xe0 | val; ++ dst += 3; ++ } ++ else /* 0x10000-0x10ffff: 4 bytes */ ++ { ++ if (dst > end - 4) break; ++ dst[3] = 0x80 | (val & 0x3f); ++ val >>= 6; ++ dst[2] = 0x80 | (val & 0x3f); ++ val >>= 6; ++ dst[1] = 0x80 | (val & 0x3f); ++ val >>= 6; ++ dst[0] = 0xf0 | val; ++ dst += 4; ++ src++; ++ srclen--; ++ } ++ } ++ if (srclen) status = STATUS_BUFFER_TOO_SMALL; ++ return status; ++} + struct request_shm + { + int futex; /* signaling futex */ +-- +2.46.1 + diff --git a/0013-server-optimization/0004-time-wait/0007-server-Use-a-dedicated-thread-for-user_shared_data-t.patch b/0013-server-optimization/0004-time-wait/0007-server-Use-a-dedicated-thread-for-user_shared_data-t.patch index f25d2e6..5077d1f 100644 --- a/0013-server-optimization/0004-time-wait/0007-server-Use-a-dedicated-thread-for-user_shared_data-t.patch +++ b/0013-server-optimization/0004-time-wait/0007-server-Use-a-dedicated-thread-for-user_shared_data-t.patch @@ -10,18 +10,18 @@ Inspired by a patch by Torge Matthies. server/fd.c | 87 +++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 75 insertions(+), 14 deletions(-) -diff --git a/server/Makefile.in b/server/Makefile.in -index d6e422c7bc1..dbaa215a422 100644 ---- a/server/Makefile.in -+++ b/server/Makefile.in -@@ -50,6 +50,6 @@ SOURCES = \ - wineserver.man.in \ - winstation.c - --UNIX_LIBS = $(LDEXECFLAGS) $(RT_LIBS) $(INOTIFY_LIBS) $(PROCSTAT_LIBS) -+UNIX_LIBS = $(LDEXECFLAGS) $(RT_LIBS) $(INOTIFY_LIBS) $(PROCSTAT_LIBS) $(PTHREAD_LIBS) - - unicode_EXTRADEFS = -DBINDIR="\"${bindir}\"" -DDATADIR="\"${datadir}\"" +# diff --git a/server/Makefile.in b/server/Makefile.in +# index d6e422c7bc1..dbaa215a422 100644 +# --- a/server/Makefile.in +# +++ b/server/Makefile.in +# @@ -50,6 +50,6 @@ SOURCES = \ +# wineserver.man.in \ +# winstation.c + +# -UNIX_LIBS = $(LDEXECFLAGS) $(RT_LIBS) $(INOTIFY_LIBS) $(PROCSTAT_LIBS) +# +UNIX_LIBS = $(LDEXECFLAGS) $(RT_LIBS) $(INOTIFY_LIBS) $(PROCSTAT_LIBS) $(PTHREAD_LIBS) + +# unicode_EXTRADEFS = -DBINDIR="\"${bindir}\"" -DDATADIR="\"${datadir}\"" diff --git a/server/fd.c b/server/fd.c index 80bf84b5ac0..8538c0e711f 100644 --- a/server/fd.c @@ -126,9 +126,9 @@ index 80bf84b5ac0..8538c0e711f 100644 static inline void fd_poll_event( struct fd *fd, int event ) { @@ -658,7 +677,6 @@ static inline void main_loop_epoll(void) - if (epoll_fd == -1) break; /* an error occurred with epoll */ - + pthread_mutex_unlock( &global_lock ); ret = epoll_wait( epoll_fd, events, ARRAY_SIZE( events ), timeout ); + pthread_mutex_lock( &global_lock ); - set_current_time(); /* put the events into the pollfd array first, like poll does */ diff --git a/0013-server-optimization/0004-time-wait/0008-ntdll-win32u-Use-some-higher-resolution-clock-ticks.patch b/0013-server-optimization/0004-time-wait/0008-ntdll-win32u-Use-some-higher-resolution-clock-ticks.patch deleted file mode 100644 index 8ebca25..0000000 --- a/0013-server-optimization/0004-time-wait/0008-ntdll-win32u-Use-some-higher-resolution-clock-ticks.patch +++ /dev/null @@ -1,113 +0,0 @@ -From aff19ed0d63afdb35cf070a41a02057fc1c432ef Mon Sep 17 00:00:00 2001 -From: William Horvath -Date: Thu, 12 Dec 2024 03:26:33 -0800 -Subject: [PATCH] ntdll, win32u: Use some higher resolution clock - ticks. - ---- - dlls/ntdll/ntdll.spec | 1 + - dlls/ntdll/time.c | 8 ++++++++ - dlls/ntdll/unix/sync.c | 7 +++++++ - dlls/win32u/message.c | 6 +++----------- - include/winternl.h | 1 + - 5 files changed, 23 insertions(+), 11 deletions(-) - -diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec -index dafeb2d2e0b..95d70830bb6 100644 ---- a/dlls/ntdll/ntdll.spec -+++ b/dlls/ntdll/ntdll.spec -@@ -1768,3 +1768,4 @@ - - # Time - @ cdecl __wine_get_tsc_calibration(ptr ptr) -+@ stdcall __wine_get_hires_tick_count() -diff --git a/dlls/ntdll/time.c b/dlls/ntdll/time.c -index 951687ca5e5..e0b4eb5bbb6 100644 ---- a/dlls/ntdll/time.c -+++ b/dlls/ntdll/time.c -@@ -459,6 +459,14 @@ ULONG WINAPI DECLSPEC_HOTPATCH NtGetTickCount(void) - return user_shared_data->TickCount.LowPart; - } - -+/****************************************************************************** -+ * __wine_get_hires_tick_count (NTDLL.@) -+ */ -+DWORD WINAPI __wine_get_hires_tick_count(void) -+{ -+ return user_shared_data->InterruptTime.LowPart / 1000; -+} -+ - /*********************************************************************** - * RtlQueryTimeZoneInformation [NTDLL.@] - * -diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c -index 4c39decfe13..489b8babd28 100644 ---- a/dlls/ntdll/unix/sync.c -+++ b/dlls/ntdll/unix/sync.c -@@ -1961,6 +1961,13 @@ ULONG WINAPI NtGetTickCount(void) - return user_shared_data->TickCount.LowPart; - } - -+/****************************************************************************** -+ * __wine_get_hires_tick_count (NTDLL.@) -+ */ -+DWORD WINAPI __wine_get_hires_tick_count(void) -+{ -+ return user_shared_data->InterruptTime.LowPart / 1000; -+} - - /****************************************************************************** - * RtlGetSystemTimePrecise (NTDLL.@) -diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c -index 8aae1d0da71..d26b717bcca 100644 ---- a/dlls/win32u/message.c -+++ b/dlls/win32u/message.c -@@ -3059,22 +3059,14 @@ static HANDLE get_server_queue_handle(void) - return ret; - } - --/* monotonic timer tick for throttling driver event checks */ --static inline LONGLONG get_driver_check_time(void) --{ -- LARGE_INTEGER counter, freq; -- NtQueryPerformanceCounter( &counter, &freq ); -- return counter.QuadPart * 8000 / freq.QuadPart; /* 8kHz */ --} -- - /* check for driver events if we detect that the app is not properly consuming messages */ - static inline void check_for_driver_events(void) - { -- if (get_user_thread_info()->last_driver_time != get_driver_check_time()) -+ if (get_user_thread_info()->last_driver_time != __wine_get_hires_tick_count()) - { - flush_window_surfaces( FALSE ); - user_driver->pProcessEvents( QS_ALLINPUT ); -- get_user_thread_info()->last_driver_time = get_driver_check_time(); -+ get_user_thread_info()->last_driver_time = __wine_get_hires_tick_count(); - } - } - -@@ -3116,7 +3108,7 @@ static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DW - } - - if (ret == WAIT_TIMEOUT && !count && !timeout) NtYieldExecution(); -- if (ret == count - 1) get_user_thread_info()->last_driver_time = get_driver_check_time(); -+ if (ret == count - 1) get_user_thread_info()->last_driver_time = __wine_get_hires_tick_count(); - - KeUserDispatchCallback( ¶ms.dispatch, sizeof(params), &ret_ptr, &ret_len ); - -diff --git a/include/winternl.h b/include/winternl.h -index 1ae37134ade..aed99fa677b 100644 ---- a/include/winternl.h -+++ b/include/winternl.h -@@ -5372,6 +5372,7 @@ static inline PLIST_ENTRY RemoveTailList(PLIST_ENTRY le) - - NTSYSAPI NTSTATUS WINAPI __wine_unix_spawnvp( char * const argv[], int wait ); - NTSYSAPI NTSTATUS __cdecl __wine_get_tsc_calibration( ULONGLONG *frequency, LONGLONG *offset ); -+NTSYSAPI DWORD WINAPI __wine_get_hires_tick_count(void); - - /* The thread information for 16-bit threads */ - /* NtCurrentTeb()->SubSystemTib points to this */ --- -2.47.1 - diff --git a/0013-server-optimization/0004-time-wait/0008-win32u-Use-fast-user_shared_data-to-check-for-driver.patch b/0013-server-optimization/0004-time-wait/0008-win32u-Use-fast-user_shared_data-to-check-for-driver.patch new file mode 100644 index 0000000..9728b7c --- /dev/null +++ b/0013-server-optimization/0004-time-wait/0008-win32u-Use-fast-user_shared_data-to-check-for-driver.patch @@ -0,0 +1,46 @@ +From 169689879e09c0666f2d9edf55ef2054084bd1b8 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Mon, 16 Dec 2024 05:22:34 -0800 +Subject: [PATCH] win32u: Use fast user_shared_data to check for driver updates + at 10khz. + +--- + dlls/win32u/message.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c +index 59ea115d260..48771f74bdf 100644 +--- a/dlls/win32u/message.c ++++ b/dlls/win32u/message.c +@@ -26,6 +26,8 @@ + #endif + + #include ++#include "winternl.h" ++#include "ddk/wdm.h" + #include "ntstatus.h" + #define WIN32_NO_STATUS + #include "win32u_private.h" +@@ -40,6 +41,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(msg); + WINE_DECLARE_DEBUG_CHANNEL(key); + WINE_DECLARE_DEBUG_CHANNEL(relay); + ++static const struct _KUSER_SHARED_DATA *user_shared_data = (struct _KUSER_SHARED_DATA *)0x7ffe0000; ++ + #define MAX_WINPROC_RECURSION 64 + + #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE +@@ -3064,9 +3068,7 @@ static HANDLE get_server_queue_handle(void) + /* monotonic timer tick for throttling driver event checks */ + static inline LONGLONG get_driver_check_time(void) + { +- LARGE_INTEGER counter, freq; +- NtQueryPerformanceCounter( &counter, &freq ); +- return counter.QuadPart * 8000 / freq.QuadPart; /* 8kHz */ ++ return user_shared_data->InterruptTime.LowPart / 1000; + } + + /* check for driver events if we detect that the app is not properly consuming messages */ +-- +2.47.1 + diff --git a/0013-server-optimization/0004-time-wait/0009-no-CLOCK_REALTIME_COARSE.patch b/0013-server-optimization/0004-time-wait/0009-no-CLOCK_REALTIME_COARSE.patch deleted file mode 100644 index 2f5e8dc..0000000 --- a/0013-server-optimization/0004-time-wait/0009-no-CLOCK_REALTIME_COARSE.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c -index a025005c989..fae32e0de5c 100644 ---- a/dlls/ntdll/unix/sync.c -+++ b/dlls/ntdll/unix/sync.c -@@ -1932,22 +1932,7 @@ NTSTATUS WINAPI NtQuerySystemTime( LARGE_INTEGER *time ) - { - #ifdef HAVE_CLOCK_GETTIME - struct timespec ts; -- static clockid_t clock_id = CLOCK_MONOTONIC; /* placeholder */ -- -- if (clock_id == CLOCK_MONOTONIC) -- { --#ifdef CLOCK_REALTIME_COARSE -- struct timespec res; -- -- /* Use CLOCK_REALTIME_COARSE if it has 1 ms or better resolution */ -- if (!clock_getres( CLOCK_REALTIME_COARSE, &res ) && res.tv_sec == 0 && res.tv_nsec <= 1000000) -- clock_id = CLOCK_REALTIME_COARSE; -- else --#endif /* CLOCK_REALTIME_COARSE */ -- clock_id = CLOCK_REALTIME; -- } -- -- if (!clock_gettime( clock_id, &ts )) -+ if (!clock_gettime( CLOCK_REALTIME, &ts )) - { - time->QuadPart = ticks_from_time_t( ts.tv_sec ) + (ts.tv_nsec + 50) / 100; - } diff --git a/0013-server-optimization/0004-time-wait/0011-remove-yield-syscall.patch b/0013-server-optimization/0004-time-wait/0011-remove-yield-syscall.patch deleted file mode 100644 index 333dd61..0000000 --- a/0013-server-optimization/0004-time-wait/0011-remove-yield-syscall.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c -index 91bab77489a..8bae3cfe686 100644 ---- a/dlls/ntdll/unix/sync.c -+++ b/dlls/ntdll/unix/sync.c -@@ -1848,17 +1848,7 @@ NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE signal, HANDLE wait, - NTSTATUS WINAPI NtYieldExecution(void) - { - #ifdef HAVE_SCHED_YIELD --#ifdef RUSAGE_THREAD -- struct rusage u1, u2; -- int ret; -- -- ret = getrusage( RUSAGE_THREAD, &u1 ); --#endif - sched_yield(); --#ifdef RUSAGE_THREAD -- if (!ret) ret = getrusage( RUSAGE_THREAD, &u2 ); -- if (!ret && u1.ru_nvcsw == u2.ru_nvcsw && u1.ru_nivcsw == u2.ru_nivcsw) return STATUS_NO_YIELD_PERFORMED; --#endif - return STATUS_SUCCESS; - #else - return STATUS_NO_YIELD_PERFORMED; diff --git a/0013-server-optimization/0004-time-wait/0013-kernel32-Reorganize-GetTickCount64.patch b/0013-server-optimization/0004-time-wait/0013-kernel32-Reorganize-GetTickCount64.patch deleted file mode 100644 index 5a6b34d..0000000 --- a/0013-server-optimization/0004-time-wait/0013-kernel32-Reorganize-GetTickCount64.patch +++ /dev/null @@ -1,29 +0,0 @@ -From: William Horvath -Date: Sun, 13 Oct 2024 20:23:16 -0700 -Subject: [PATCH] kernel32: Reorganize GetTickCount64. - -diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c -index 11111111111..11111111111 100644 ---- a/dlls/kernel32/sync.c -+++ b/dlls/kernel32/sync.c -@@ -82,16 +82,7 @@ static BOOL get_open_object_attributes( OBJECT_ATTRIBUTES *attr, UNICODE_STRING - */ - ULONGLONG WINAPI DECLSPEC_HOTPATCH GetTickCount64(void) - { -- ULONG high, low; -- -- do -- { -- high = user_shared_data->TickCount.High1Time; -- low = user_shared_data->TickCount.LowPart; -- } -- while (high != user_shared_data->TickCount.High2Time); -- /* note: we ignore TickCountMultiplier */ -- return (ULONGLONG)high << 32 | low; -+ return __atomic_load_n( &user_shared_data->TickCountQuad, __ATOMIC_ACQUIRE ); - } - - /*********************************************************************** --- -0.0.0 - diff --git a/0013-server-optimization/0007-priority/0001-server-Implement-thread-priorities-on-Linux.patch b/0013-server-optimization/0007-priority/0001-server-Implement-thread-priorities-on-Linux.patch index 76f3893..0ec4507 100644 --- a/0013-server-optimization/0007-priority/0001-server-Implement-thread-priorities-on-Linux.patch +++ b/0013-server-optimization/0007-priority/0001-server-Implement-thread-priorities-on-Linux.patch @@ -82,9 +82,9 @@ diff --git a/server/thread.c b/server/thread.c index 11111111111..11111111111 100644 --- a/server/thread.c +++ b/server/thread.c -@@ -37,6 +37,12 @@ - #define _WITH_CPU_SET_T - #include +@@ -43,6 +43,12 @@ + #ifdef HAVE_SYS_SYSCALL_H + #include #endif +#ifdef HAVE_SYS_TIME_H +#include @@ -95,7 +95,7 @@ index 11111111111..11111111111 100644 #include "ntstatus.h" #define WIN32_NO_STATUS -@@ -257,6 +263,7 @@ static inline void init_thread_structure( struct thread *thread ) +@@ -273,6 +279,7 @@ static inline void init_thread_structure( struct thread *thread ) thread->state = RUNNING; thread->exit_code = 0; thread->priority = 0; @@ -103,7 +103,7 @@ index 11111111111..11111111111 100644 thread->suspend = 0; thread->dbg_hidden = 0; thread->desktop_users = 0; -@@ -677,31 +684,151 @@ affinity_t get_thread_affinity( struct thread *thread ) +@@ -839,9 +846,145 @@ affinity_t get_thread_affinity( struct thread *thread ) return mask; } @@ -186,6 +186,7 @@ index 11111111111..11111111111 100644 + return 0; +} +#endif ++ + #define THREAD_PRIORITY_REALTIME_HIGHEST 6 #define THREAD_PRIORITY_REALTIME_LOWEST -7 @@ -244,9 +245,11 @@ index 11111111111..11111111111 100644 + return 0; /* ignore errors for now */ +} + - /* set all information about a thread */ - static void set_thread_info( struct thread *thread, - const struct set_thread_info_request *req ) ++ + #define MAX_THREAD_NAME_LENGTH 16 + #define MAX_RETRIES 5 + #define RETRY_DELAY_US 1000 +@@ -921,22 +1064,8 @@ static void set_thread_info( struct thread *thread, { if (req->mask & SET_THREAD_INFO_PRIORITY) { @@ -271,7 +274,7 @@ index 11111111111..11111111111 100644 } if (req->mask & SET_THREAD_INFO_AFFINITY) { -@@ -1584,6 +1711,7 @@ DECL_HANDLER(init_thread) +@@ -1862,6 +1991,7 @@ DECL_HANDLER(init_thread) init_thread_context( current ); generate_debug_event( current, DbgCreateThreadStateChange, &req->entry ); diff --git a/9000-misc-additions/HACK-shell32-replace-osu-s-explorer.exe-calls-with-t.patch b/9000-misc-additions/HACK-shell32-replace-osu-s-explorer.exe-calls-with-t.patch new file mode 100644 index 0000000..0713451 --- /dev/null +++ b/9000-misc-additions/HACK-shell32-replace-osu-s-explorer.exe-calls-with-t.patch @@ -0,0 +1,189 @@ +From 5299d1b07a9738999093478afd3723efaac89e2f Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Sun, 15 Dec 2024 17:22:38 -0800 +Subject: [PATCH 1/2] HACK: shell32: replace osu!'s explorer.exe calls with the + folder of the file it's trying to open. + +This allows osu! to open the screenshot folder by clicking +the popup ingame, when WINE_BLOCK_GET_VERSION=1 is used. + +That's under the assumption that the Folder\\shell\\open\\command +registry key is set up correctly with xdg-open and all that +machinery that osu-winello sets up automatically. +--- + dlls/shell32/shlexec.c | 61 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 61 insertions(+) + +diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c +index b9fb6285f39..bde391c4433 100644 +--- a/dlls/shell32/shlexec.c ++++ b/dlls/shell32/shlexec.c +@@ -32,6 +32,7 @@ + #include "winbase.h" + #include "winerror.h" + #include "winreg.h" ++#include "winternl.h" + #include "winuser.h" + #include "shlwapi.h" + #include "ddeml.h" +@@ -1629,6 +1630,23 @@ static WCHAR *expand_environment( const WCHAR *str ) + return buf; + } + ++static BOOL is_osu(void) ++{ ++ static volatile char cache = -1; ++ BOOL ret = cache; ++ if (ret == -1) ++ { ++ const WCHAR *p, *name = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer; ++ if ((p = wcsrchr(name, '/'))) ++ name = p + 1; ++ if ((p = wcsrchr(name, '\\'))) ++ name = p + 1; ++ ret = !wcsicmp(name, L"osu!.exe"); ++ cache = ret; ++ } ++ return ret; ++} ++ + /************************************************************************* + * SHELL_execute [Internal] + */ +@@ -1654,6 +1672,49 @@ static BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) + /* make a local copy of the LPSHELLEXECUTEINFO structure and work with this from now on */ + sei_tmp = *sei; + ++ /* HACK: open screenshot folder directly */ ++ if (is_osu() && !wcscmp(sei_tmp.lpFile, L"explorer.exe") && sei_tmp.lpParameters) ++ { ++ static const WCHAR select_prefix[] = L"/select,"; ++ LPCWSTR path = sei_tmp.lpParameters; ++ ++ if (!wcsncmp(path, select_prefix, ARRAY_SIZE(select_prefix) - 1)) ++ { ++ path += ARRAY_SIZE(select_prefix) - 1; ++ ++ BOOL has_quotes = (*path == '\"'); ++ if (has_quotes) ++ path++; ++ ++ size_t path_len = wcslen(path); ++ if (has_quotes && path_len > 0 && path[path_len - 1] == '\"') ++ path_len--; ++ ++ LPWSTR dir_path = malloc((path_len + 2) * sizeof(WCHAR)); ++ if (!dir_path) ++ return FALSE; ++ ++ memcpy(dir_path, path, path_len); ++ dir_path[path_len] = '\0'; ++ ++ if (!PathRemoveFileSpecW(dir_path)) ++ { ++ free(dir_path); ++ return FALSE; ++ } ++ ++ if (wcslen(dir_path) + 2 <= path_len + 2) ++ PathAddBackslashW(dir_path); ++ ++ sei_tmp.lpFile = dir_path; ++ sei_tmp.lpParameters = sei_tmp.lpVerb = NULL; ++ ++ BOOL ret = SHELL_execute(&sei_tmp, execfunc); ++ free(dir_path); ++ return ret; ++ } ++ } ++ + TRACE("mask=0x%08lx hwnd=%p verb=%s file=%s parm=%s dir=%s show=0x%08x class=%s\n", + sei_tmp.fMask, sei_tmp.hwnd, debugstr_w(sei_tmp.lpVerb), + debugstr_w(sei_tmp.lpFile), debugstr_w(sei_tmp.lpParameters), +-- +2.47.1 + +From ae7fe9133126aafdf5d4669f776a8c35831a9ee7 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Sun, 15 Dec 2024 17:23:53 -0800 +Subject: [PATCH 2/2] wine.inf.in: Remove default folder/ddeexec handler. + +--- + loader/wine.inf.in | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/loader/wine.inf.in b/loader/wine.inf.in +index 928d3e64e15..6cfd05fb7e3 100644 +--- a/loader/wine.inf.in ++++ b/loader/wine.inf.in +@@ -73,6 +73,7 @@ AddReg=\ + Tapi,\ + ThemeManager,\ + LicenseInformation ++DelReg=RemoveClasses + + [DefaultInstall.NT] + RegisterDlls=RegisterDllsSection +@@ -99,6 +100,7 @@ AddReg=\ + ThemeManager,\ + VersionInfo,\ + LicenseInformation ++DelReg=RemoveClasses + + [DefaultInstall.ntamd64] + RegisterDlls=RegisterDllsSection +@@ -126,6 +128,7 @@ AddReg=\ + ThemeManager,\ + VersionInfo,\ + LicenseInformation ++DelReg=RemoveClasses + + [DefaultInstall.ntarm64] + RegisterDlls=RegisterDllsSection +@@ -151,6 +154,7 @@ AddReg=\ + ThemeManager,\ + VersionInfo,\ + LicenseInformation ++DelReg=RemoveClasses + + [Wow64Install.ntx86] + RegisterDlls=RegisterDllsSection +@@ -168,6 +172,7 @@ AddReg=\ + ThemeManager,\ + VersionInfo,\ + LicenseInformation ++DelReg=RemoveClasses + + [Wow64Install.ntarm] + RegisterDlls=RegisterDllsSection +@@ -183,6 +188,7 @@ AddReg=\ + Tapi,\ + VersionInfo,\ + LicenseInformation ++DelReg=RemoveClasses + + [DefaultInstall.Services] + AddService=BITS,0,BITSService +@@ -297,9 +303,6 @@ HKCR,exefile,,2,"Application" + HKCR,exefile\DefaultIcon,,2,"%1" + HKCR,exefile\shell\open\command,,2,"""%1"" %*" + HKCR,exefile\shell\runas\command,,2,"""%1"" %*" +-HKCR,folder\shell\open\ddeexec,,2,"[ViewFolder("%l", %I, %S)]" +-HKCR,folder\shell\open\ddeexec,"NoActivateHandler",2,"" +-HKCR,folder\shell\open\ddeexec\application,,2,"Folders" + HKCR,folder\shellex\ContextMenuHandlers,,16 + HKCR,folder\shellnew,"Directory",,"" + HKCR,folder\shellnew,"ItemName",,"@%11%\shell32.dll,-142" +@@ -344,6 +347,9 @@ HKCR,http\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" + HKCR,https\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" + HKCR,mailto\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" + ++[RemoveClasses] ++HKCR,folder\shell\open\ddeexec ++ + [ContentIndex] + HKLM,System\CurrentControlSet\Control\ContentIndex\Language\Neutral,"WBreakerClass",,"{369647e0-17b0-11ce-9950-00aa004bbb1f}" + HKLM,System\CurrentControlSet\Control\ContentIndex\Language\Neutral,"StemmerClass",,"" +-- +2.47.1 + diff --git a/9000-misc-additions/Revert-ntdll-Report-the-space-completely-outside-of-.patch b/9000-misc-additions/Revert-ntdll-Report-the-space-completely-outside-of-.patch deleted file mode 100644 index 578867c..0000000 --- a/9000-misc-additions/Revert-ntdll-Report-the-space-completely-outside-of-.patch +++ /dev/null @@ -1,61 +0,0 @@ -From b962e1fd1f8a4eb3a599940b3ae50034fcf31953 Mon Sep 17 00:00:00 2001 -From: William Horvath -Date: Tue, 10 Dec 2024 01:12:10 -0800 -Subject: [PATCH] Revert "ntdll: Report the space completely outside of - reserved areas as allocated on i386." - -This reverts commit 233f6f288c8a6aa5aae127660ab00f392fe2cf67. - -The commit breaks osu! when WINE_BLOCK_GET_VERSION=0, because it fixes the bug -that the game tries to work around when it knows it's running under wine. ---- - dlls/ntdll/unix/virtual.c | 8 +------- - 1 file changed, 1 insertion(+), 7 deletions(-) - -diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c -index 7330519bbb5..e2c3eb7c339 100644 ---- a/dlls/ntdll/unix/virtual.c -+++ b/dlls/ntdll/unix/virtual.c -@@ -5603,7 +5603,6 @@ static unsigned int fill_basic_memory_info( const void *addr, MEMORY_BASIC_INFOR - * so that the app doesn't believe it's fully available */ - { - struct reserved_area *area; -- BOOL in_reserved = FALSE; - - LIST_FOR_EACH_ENTRY( area, &reserved_areas, struct reserved_area, entry ) - { -@@ -5618,7 +5617,6 @@ static unsigned int fill_basic_memory_info( const void *addr, MEMORY_BASIC_INFOR - if (area_start <= base || area_start <= (char *)address_space_start) - { - if (area_end < alloc_end) info->RegionSize = area_end - base; -- in_reserved = TRUE; - break; - } - /* report the remaining part of the 64K after the view as free */ -@@ -5629,22 +5627,18 @@ static unsigned int fill_basic_memory_info( const void *addr, MEMORY_BASIC_INFOR - if (base < next) - { - info->RegionSize = min( next, alloc_end ) - base; -- in_reserved = TRUE; - break; - } - else alloc_base = base; - } - /* pretend it's allocated */ - if (area_start < alloc_end) info->RegionSize = area_start - base; -- break; -- } -- if (!in_reserved) -- { - info->State = MEM_RESERVE; - info->Protect = PAGE_NOACCESS; - info->AllocationBase = alloc_base; - info->AllocationProtect = PAGE_NOACCESS; - info->Type = MEM_PRIVATE; -+ break; - } - } - #endif --- -2.47.1 - diff --git a/9000-misc-additions/ntdll-Silence-HeapEnableTerminationOnCorruption.patch b/9000-misc-additions/ntdll-Silence-HeapEnableTerminationOnCorruption.patch new file mode 100644 index 0000000..70cf8ce --- /dev/null +++ b/9000-misc-additions/ntdll-Silence-HeapEnableTerminationOnCorruption.patch @@ -0,0 +1,42 @@ +From 31c781dd33f48ddd2a12f6f9fba0901a2a64b394 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Fri, 13 Dec 2024 19:58:02 -0800 +Subject: [PATCH] ntdll: Silence HeapEnableTerminationOnCorruption. + +--- + dlls/ntdll/heap.c | 6 ++++++ + include/winnt.h | 1 + + 2 files changed, 7 insertions(+) + +diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c +index 164b8714459..5c4563e44d9 100644 +--- a/dlls/ntdll/heap.c ++++ b/dlls/ntdll/heap.c +@@ -2601,6 +2601,12 @@ NTSTATUS WINAPI RtlSetHeapInformation( HANDLE handle, HEAP_INFORMATION_CLASS inf + return STATUS_UNSUCCESSFUL; + return STATUS_SUCCESS; + } ++ case HeapEnableTerminationOnCorruption: ++ { ++ /* From Microsoft SDK: ++ * Unsupported until Vista+, returns success */ ++ return STATUS_SUCCESS; ++ } + + default: + FIXME( "HEAP_INFORMATION_CLASS %u not implemented!\n", info_class ); +diff --git a/include/winnt.h b/include/winnt.h +index db39262979e..f865002089e 100644 +--- a/include/winnt.h ++++ b/include/winnt.h +@@ -1068,6 +1068,7 @@ NTSYSAPI WORD WINAPI RtlQueryDepthSList(PSLIST_HEADER); + + typedef enum _HEAP_INFORMATION_CLASS { + HeapCompatibilityInformation, ++ HeapEnableTerminationOnCorruption + } HEAP_INFORMATION_CLASS; + + /* Processor feature flags. */ +-- +2.47.1 + diff --git a/9000-misc-additions/wine.inf-default-overrides.patch b/9000-misc-additions/wine.inf-default-overrides.patch deleted file mode 100644 index 4557b2b..0000000 --- a/9000-misc-additions/wine.inf-default-overrides.patch +++ /dev/null @@ -1,55 +0,0 @@ -winemenubuilder is bloat -## wine(bus/sys/hid) are prone to crashing after some time (maybe fixed?) with strange error messages; they are unnecessary for osu anyways -^ this is now achieved achieved through a different method (fake load driver) that doesn't cause error messages on startup -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 11111111111..11111111111 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -98,7 +98,8 @@ AddReg=\ - Tapi,\ - ThemeManager,\ - VersionInfo,\ -- LicenseInformation -+ LicenseInformation,\ -+ Overrides - - [DefaultInstall.ntamd64] - RegisterDlls=RegisterDllsSection -@@ -125,7 +126,8 @@ AddReg=\ - Tapi,\ - ThemeManager,\ - VersionInfo,\ -- LicenseInformation -+ LicenseInformation,\ -+ Overrides - - [DefaultInstall.ntarm64] - RegisterDlls=RegisterDllsSection -@@ -168,7 +170,8 @@ AddReg=\ - Packages.wow64,\ - Tapi,\ - VersionInfo,\ -- LicenseInformation -+ LicenseInformation,\ -+ Overrides - - [Wow64Install.ntarm] - RegisterDlls=RegisterDllsSection -@@ -2500,7 +2503,6 @@ StartType=3 - ErrorControl=1 - - [Services] --HKLM,%CurrentVersion%\RunServices,"winemenubuilder",2,"%11%\winemenubuilder.exe -a -r" - HKLM,"System\CurrentControlSet\Services\Eventlog\Application",,16 - HKLM,"System\CurrentControlSet\Services\Eventlog\System","Sources",0x10000,"" - HKLM,"System\CurrentControlSet\Services\Tcpip\Parameters","DataBasePath",,"%12%\etc" -@@ -3025,3 +3028,9 @@ EtcFiles = 12,etc - InfFiles = 17 - NlsFiles = 11 - SortFiles = 10,globalization\sorting -+ -+[Overrides] -+;;HKCU,Software\Wine\DllOverrides,"winebus.sys",0x2,"" -+;;HKCU,Software\Wine\DllOverrides,"winehid.sys",0x2,"" -+;;HKCU,Software\Wine\DllOverrides,"wineusb.sys",0x2,"" -+ diff --git a/9000-misc-additions/winedmo-Add-envvar-option-to-enable-disable.patch b/9000-misc-additions/winedmo-Add-envvar-option-to-enable-disable.patch new file mode 100644 index 0000000..9de0589 --- /dev/null +++ b/9000-misc-additions/winedmo-Add-envvar-option-to-enable-disable.patch @@ -0,0 +1,32 @@ +From dd9c36d3af5b9734b72eda478568b401ab21a459 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Sat, 14 Dec 2024 00:46:21 -0800 +Subject: [PATCH] winedmo: Add envvar option to enable/disable. + +--- + dlls/mfsrcsnk/media_source.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c +index ac5f013d9cd..98556c93ad7 100644 +--- a/dlls/mfsrcsnk/media_source.c ++++ b/dlls/mfsrcsnk/media_source.c +@@ -1893,6 +1893,15 @@ static BOOL use_gst_byte_stream_handler(void) + { + BOOL result; + DWORD size = sizeof(result); ++ WCHAR buffer[2]; ++ ++ if (GetEnvironmentVariableW( L"WINEDMO", buffer, ARRAY_SIZE(buffer) )) ++ { ++ if (!wcscmp( buffer, L"0" )) ++ return TRUE; ++ else ++ return FALSE; ++ } + + /* @@ Wine registry key: HKCU\Software\Wine\MediaFoundation */ + if (!RegGetValueW( HKEY_CURRENT_USER, L"Software\\Wine\\MediaFoundation", L"DisableGstByteStreamHandler", +-- +2.47.1 + diff --git a/9999-nowow64/0004-ps4914-Avoid-sending-context-in-wait_suspend-when-not-req.3264.patch b/9999-nowow64/0004-ps4914-Avoid-sending-context-in-wait_suspend-when-not-req.3264.patch new file mode 100644 index 0000000..fc8d6f5 --- /dev/null +++ b/9999-nowow64/0004-ps4914-Avoid-sending-context-in-wait_suspend-when-not-req.3264.patch @@ -0,0 +1,188 @@ +From 493a967dd951ef7cf83bd87e330348bd562d3763 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 22 Jan 2024 19:34:47 -0600 +Subject: [PATCH] ntdll: Avoid sending context in wait_suspend() when not + required. + +--- + dlls/ntdll/unix/server.c | 7 ++++--- + dlls/ntdll/unix/signal_arm.c | 2 ++ + dlls/ntdll/unix/signal_arm64.c | 2 ++ + dlls/ntdll/unix/signal_i386.c | 2 ++ + dlls/ntdll/unix/signal_x86_64.c | 2 ++ + dlls/ntdll/unix/thread.c | 12 +++++++----- + dlls/ntdll/unix/unix_private.h | 2 +- + server/protocol.def | 1 + + server/thread.c | 8 ++++++++ + 9 files changed, 29 insertions(+), 9 deletions(-) + +diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c +index 69e6567c911..f96a08e40b2 100644 +--- a/dlls/ntdll/unix/server.c ++++ b/dlls/ntdll/unix/server.c +@@ -693,7 +693,6 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT + unsigned int ret; + int cookie; + obj_handle_t apc_handle = 0; +- BOOL suspend_context = !!context; + union apc_result result; + sigset_t old_set; + int signaled; +@@ -704,6 +703,8 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT + context_t context[2]; + } reply_data; + ++ assert(!context || (flags & SELECT_SUSPEND)); ++ + memset( &result, 0, sizeof(result) ); + + do +@@ -720,11 +721,11 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT + req->size = size; + wine_server_add_data( req, &result, sizeof(result) ); + wine_server_add_data( req, select_op, size ); +- if (suspend_context) ++ if (context && flags & SELECT_SUSPEND) + { + data_size_t ctx_size = (context[1].machine ? 2 : 1) * sizeof(*context); + wine_server_add_data( req, context, ctx_size ); +- suspend_context = FALSE; /* server owns the context now */ ++ flags &= ~SELECT_SUSPEND; /* server owns the context now */ + } + wine_server_set_reply( req, &reply_data, + context ? sizeof(reply_data) : sizeof(reply_data.call) ); +diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c +index 5115fa7ec3a..46f8d93cdb4 100644 +--- a/dlls/ntdll/unix/signal_arm.c ++++ b/dlls/ntdll/unix/signal_arm.c +@@ -1518,6 +1518,8 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) + { + CONTEXT context; + ++ if (wait_suspend( NULL ) != STATUS_MORE_PROCESSING_REQUIRED) return; ++ + if (is_inside_syscall( sigcontext )) + { + context.ContextFlags = CONTEXT_FULL; +diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c +index f96ec330796..ac8d23f918e 100644 +--- a/dlls/ntdll/unix/signal_arm64.c ++++ b/dlls/ntdll/unix/signal_arm64.c +@@ -1485,6 +1485,8 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) + { + CONTEXT context; + ++ if (wait_suspend( NULL ) != STATUS_MORE_PROCESSING_REQUIRED) return; ++ + if (is_inside_syscall( sigcontext )) + { + context.ContextFlags = CONTEXT_FULL; +diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c +index 751b0081534..f7ee66b926c 100644 +--- a/dlls/ntdll/unix/signal_i386.c ++++ b/dlls/ntdll/unix/signal_i386.c +@@ -2129,6 +2129,8 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) + + init_handler( sigcontext ); + ++ if (wait_suspend( NULL ) != STATUS_MORE_PROCESSING_REQUIRED) return; ++ + if (is_inside_syscall( ucontext )) + { + struct syscall_frame *frame = x86_thread_data()->syscall_frame; +diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c +index 53827629af4..e8f8cda53d4 100644 +--- a/dlls/ntdll/unix/signal_x86_64.c ++++ b/dlls/ntdll/unix/signal_x86_64.c +@@ -2151,6 +2151,8 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) + { + ucontext_t *ucontext = init_handler( sigcontext ); + ++ if (wait_suspend( NULL ) != STATUS_MORE_PROCESSING_REQUIRED) return; ++ + if (is_inside_syscall( ucontext )) + { + struct syscall_frame *frame = amd64_thread_data()->syscall_frame; +diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c +index 9e84ec3cc96..c67e29e47fd 100644 +--- a/dlls/ntdll/unix/thread.c ++++ b/dlls/ntdll/unix/thread.c +@@ -1458,16 +1458,18 @@ void exit_process( int status ) + * + * Wait until the thread is no longer suspended. + */ +-void wait_suspend( CONTEXT *context ) ++NTSTATUS wait_suspend( CONTEXT *context ) + { + int saved_errno = errno; + struct context_data server_contexts[2]; ++ NTSTATUS status; + +- contexts_to_server( server_contexts, context ); ++ if (context) contexts_to_server( server_contexts, context ); + /* wait with 0 timeout, will only return once the thread is no longer suspended */ +- server_select( NULL, 0, SELECT_INTERRUPTIBLE, 0, server_contexts, NULL ); +- contexts_from_server( context, server_contexts ); ++ status = server_select( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_SUSPEND, 0, context ? server_contexts : NULL, NULL ); ++ if (context) contexts_from_server( context, server_contexts ); + errno = saved_errno; ++ return status; + } + + +@@ -1513,7 +1515,7 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_c + contexts_to_server( server_contexts, context ); + server_contexts[0].flags |= SERVER_CTX_EXEC_SPACE; + server_contexts[0].exec_space.space.space = exception ? EXEC_SPACE_EXCEPTION : EXEC_SPACE_SYSCALL; +- server_select( &select_op, offsetof( union select_op, wait.handles[1] ), SELECT_INTERRUPTIBLE, ++ server_select( &select_op, offsetof( union select_op, wait.handles[1] ), SELECT_INTERRUPTIBLE | SELECT_SUSPEND, + TIMEOUT_INFINITE, server_contexts, NULL ); + + SERVER_START_REQ( get_exception_status ) +diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h +index 07f2724eac7..1c8016e6471 100644 +--- a/dlls/ntdll/unix/unix_private.h ++++ b/dlls/ntdll/unix/unix_private.h +@@ -218,7 +218,7 @@ extern NTSTATUS init_thread_stack( TEB *teb, ULONG_PTR limit, SIZE_T reserve_size, SIZE_T commit_size ); + extern void DECLSPEC_NORETURN abort_thread( int status ); + extern void DECLSPEC_NORETURN abort_process( int status ); + extern void DECLSPEC_NORETURN exit_process( int status ); +-extern void wait_suspend( CONTEXT *context ); ++extern NTSTATUS wait_suspend( CONTEXT *context ); + extern NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance, BOOL exception ); + extern NTSTATUS set_thread_context( HANDLE handle, const void *context, BOOL *self, USHORT machine ); + extern NTSTATUS get_thread_context( HANDLE handle, void *context, BOOL *self, USHORT machine ); +diff --git a/server/protocol.def b/server/protocol.def +index 5d60e7fcda3..86019a1ad32 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -1237,6 +1237,7 @@ typedef struct + @END + #define SELECT_ALERTABLE 1 + #define SELECT_INTERRUPTIBLE 2 ++#define SELECT_SUSPEND 4 + + + /* Create an event */ +diff --git a/server/thread.c b/server/thread.c +index 56f57cefd8f..99dda8f7287 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -1656,6 +1656,14 @@ DECL_HANDLER(select) + release_object( apc ); + } + ++ if (!ctx_count && current->context && req->flags & SELECT_SUSPEND) ++ { ++ /* select is called from signal and thread context is required. */ ++ set_error( STATUS_MORE_PROCESSING_REQUIRED ); ++ reply->signaled = 1; ++ return; ++ } ++ + reply->signaled = select_on( &select_op, op_size, req->cookie, req->flags, req->timeout ); + + if (get_error() == STATUS_USER_APC && get_reply_max_size() >= sizeof(apc_call_t)) +-- +GitLab + diff --git a/staging-commit b/staging-commit index 8cc838a..0d63a1b 100644 --- a/staging-commit +++ b/staging-commit @@ -1 +1 @@ -c8d46d4ca3c505014f55cc92296592119abf84f1 \ No newline at end of file +c2de76b8048c67aa33c57cff60f98ba1b1675e72 \ No newline at end of file diff --git a/wine-commit b/wine-commit index 5e33d68..d39c624 100644 --- a/wine-commit +++ b/wine-commit @@ -1 +1 @@ -5bfbeb677f472d30c5dc5d855b0a045a7157cc43 \ No newline at end of file +538cae099cde66706428ead4ae8951c1e389d3f2 \ No newline at end of file