From 12842d4a5d9f10cf1c9ebe0ba07001bfcee58aa4 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Sat, 2 May 2015 07:12:06 +0200 Subject: [PATCH] ntdll-FD_Cache: Update patchset with recent changes. --- ...nterlocked_cmpxchg64-on-PowerPC-usin.patch | 50 +++++ ...ree-implementation-for-get_cached_fd.patch | 163 -------------- ...ee-implementation-for-get_cached_fd..patch | 207 ++++++++++++++++++ patches/patchinstall.sh | 8 +- 4 files changed, 262 insertions(+), 166 deletions(-) create mode 100644 patches/ntdll-FD_Cache/0001-libs-Implement-interlocked_cmpxchg64-on-PowerPC-usin.patch delete mode 100644 patches/ntdll-FD_Cache/0001-ntdll-Use-lockfree-implementation-for-get_cached_fd.patch create mode 100644 patches/ntdll-FD_Cache/0002-ntdll-Use-lockfree-implementation-for-get_cached_fd..patch diff --git a/patches/ntdll-FD_Cache/0001-libs-Implement-interlocked_cmpxchg64-on-PowerPC-usin.patch b/patches/ntdll-FD_Cache/0001-libs-Implement-interlocked_cmpxchg64-on-PowerPC-usin.patch new file mode 100644 index 00000000..27fea97e --- /dev/null +++ b/patches/ntdll-FD_Cache/0001-libs-Implement-interlocked_cmpxchg64-on-PowerPC-usin.patch @@ -0,0 +1,50 @@ +From 27e4c293824d5e133f2b30e7cda68d96142b8fb5 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Sat, 2 May 2015 07:04:17 +0200 +Subject: libs: Implement interlocked_cmpxchg64 on PowerPC using pthread mutex. + +--- + libs/port/interlocked.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/libs/port/interlocked.c b/libs/port/interlocked.c +index f5e405c..80e43cf 100644 +--- a/libs/port/interlocked.c ++++ b/libs/port/interlocked.c +@@ -181,6 +181,11 @@ __ASM_GLOBAL_FUNC(interlocked_cmpxchg128, + "ret") + + #elif defined(__powerpc__) ++ ++#include ++ ++static pthread_mutex_t interlocked_mutex = PTHREAD_MUTEX_INITIALIZER; ++ + void* interlocked_cmpxchg_ptr( void **dest, void* xchg, void* compare) + { + void *ret = 0; +@@ -199,10 +204,18 @@ void* interlocked_cmpxchg_ptr( void **dest, void* xchg, void* compare) + return ret; + } + +-__int64 interlocked_cmpxchg64( __int64 *dest, __int64 xchg, __int64 compare) ++/* FIXME: replace with assembler implementation */ ++__int64 interlocked_cmpxchg64( __int64 *dest, __int64 xchg, __int64 compare ) + { +- /* FIXME: add code */ +- assert(0); ++ pthread_mutex_lock( &interlocked_mutex ); ++ ++ if (*dest == compare) ++ *dest = xchg; ++ else ++ compare = *dest; ++ ++ pthread_mutex_unlock( &interlocked_mutex ); ++ return compare; + } + + int interlocked_cmpxchg( int *dest, int xchg, int compare) +-- +2.3.5 + diff --git a/patches/ntdll-FD_Cache/0001-ntdll-Use-lockfree-implementation-for-get_cached_fd.patch b/patches/ntdll-FD_Cache/0001-ntdll-Use-lockfree-implementation-for-get_cached_fd.patch deleted file mode 100644 index 72ebe03b..00000000 --- a/patches/ntdll-FD_Cache/0001-ntdll-Use-lockfree-implementation-for-get_cached_fd.patch +++ /dev/null @@ -1,163 +0,0 @@ -From d27bb6018ce273ab2aa29d436a64dc2507992f84 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Wed, 26 Nov 2014 09:03:17 +0100 -Subject: ntdll: Use lockfree implementation for get_cached_fd. (try 5) - ---- - dlls/ntdll/server.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 66 insertions(+), 1 deletion(-) - -diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c -index 69d01be..29cfcb5 100644 ---- a/dlls/ntdll/server.c -+++ b/dlls/ntdll/server.c -@@ -75,6 +75,8 @@ - - #include "ntstatus.h" - #define WIN32_NO_STATUS -+#include "windef.h" -+#include "winnt.h" - #include "wine/library.h" - #include "wine/server.h" - #include "wine/debug.h" -@@ -790,6 +792,7 @@ static int receive_fd( obj_handle_t *handle ) - /***********************************************************************/ - /* fd cache support */ - -+#include "pshpack1.h" - struct fd_cache_entry - { - int fd; -@@ -797,6 +800,7 @@ struct fd_cache_entry - unsigned int access : 3; - unsigned int options : 24; - }; -+#include "poppack.h" - - #define FD_CACHE_BLOCK_SIZE (65536 / sizeof(struct fd_cache_entry)) - #define FD_CACHE_ENTRIES 128 -@@ -811,6 +815,36 @@ static inline unsigned int handle_to_index( HANDLE handle, unsigned int *entry ) - return idx % FD_CACHE_BLOCK_SIZE; - } - -+#if !defined(__powerpc__) -+ -+static inline LONG64 interlocked_xchg64( LONG64 *dest, LONG64 val ) -+{ -+#ifdef _WIN64 -+ return (LONG64)interlocked_xchg_ptr( (void **)dest, (void *)val ); -+#else -+ LONG64 cmp = *dest; -+ while (interlocked_cmpxchg64( dest, val, cmp ) != cmp) cmp = *dest; -+ return cmp; -+#endif -+} -+ -+C_ASSERT( sizeof(struct fd_cache_entry) == sizeof(LONG64) ); -+ -+/* atomically updates a fd cache entry and fetches the old value */ -+static inline void interlocked_xchg_fd_cache( struct fd_cache_entry *cache, -+ struct fd_cache_entry *val ) -+{ -+ *(LONG64 *)val = interlocked_xchg64( (LONG64 *)cache, *(LONG64 *)val ); -+} -+ -+/* atomically reads a fd cache entry */ -+static inline void interlocked_read_fd_cache( struct fd_cache_entry *cache, -+ struct fd_cache_entry *val ) -+{ -+ *(LONG64 *)val = interlocked_cmpxchg64( (LONG64 *)cache, 0, 0 ); -+} -+ -+#endif /* !defined(__powerpc__) */ - - /*********************************************************************** - * add_fd_to_cache -@@ -821,6 +855,9 @@ static BOOL add_fd_to_cache( HANDLE handle, int fd, enum server_fd_type type, - unsigned int access, unsigned int options ) - { - unsigned int entry, idx = handle_to_index( handle, &entry ); -+#if !defined(__powerpc__) -+ struct fd_cache_entry cache; -+#endif - - if (entry >= FD_CACHE_ENTRIES) - { -@@ -839,12 +876,22 @@ static BOOL add_fd_to_cache( HANDLE handle, int fd, enum server_fd_type type, - fd_cache[entry] = ptr; - } - } -+ - /* store fd+1 so that 0 can be used as the unset value */ -+#if defined(__powerpc__) - fd = interlocked_xchg( &fd_cache[entry][idx].fd, fd + 1 ); - fd_cache[entry][idx].type = type; - fd_cache[entry][idx].access = access; - fd_cache[entry][idx].options = options; - assert( !fd ); -+#else -+ cache.fd = fd + 1; -+ cache.type = type; -+ cache.access = access; -+ cache.options = options; -+ interlocked_xchg_fd_cache( &fd_cache[entry][idx], &cache ); -+ assert( !cache.fd ); -+#endif - return TRUE; - } - -@@ -852,7 +899,7 @@ static BOOL add_fd_to_cache( HANDLE handle, int fd, enum server_fd_type type, - /*********************************************************************** - * get_cached_fd - * -- * Caller must hold fd_cache_section. -+ * Caller must hold fd_cache_section on PowerPC processor architecture. - */ - static inline int get_cached_fd( HANDLE handle, enum server_fd_type *type, - unsigned int *access, unsigned int *options ) -@@ -862,10 +909,19 @@ static inline int get_cached_fd( HANDLE handle, enum server_fd_type *type, - - if (entry < FD_CACHE_ENTRIES && fd_cache[entry]) - { -+ #if defined(__powerpc__) - fd = fd_cache[entry][idx].fd - 1; - if (type) *type = fd_cache[entry][idx].type; - if (access) *access = fd_cache[entry][idx].access; - if (options) *options = fd_cache[entry][idx].options; -+ #else -+ struct fd_cache_entry cache; -+ interlocked_read_fd_cache( &fd_cache[entry][idx], &cache ); -+ fd = cache.fd - 1; -+ if (type) *type = cache.type; -+ if (access) *access = cache.access; -+ if (options) *options = cache.options; -+ #endif - } - return fd; - } -@@ -903,6 +959,11 @@ int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd, - *needs_close = 0; - wanted_access &= FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA; - -+#if !defined(__powerpc__) -+ fd = get_cached_fd( handle, type, &access, options ); -+ if (fd != -1) goto done_unlocked; -+#endif -+ - server_enter_uninterrupted_section( &fd_cache_section, &sigset ); - - fd = get_cached_fd( handle, type, &access, options ); -@@ -930,6 +991,10 @@ int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd, - - done: - server_leave_uninterrupted_section( &fd_cache_section, &sigset ); -+ -+#if !defined(__powerpc__) -+done_unlocked: -+#endif - if (!ret && ((access & wanted_access) != wanted_access)) - { - ret = STATUS_ACCESS_DENIED; --- -2.3.0 - diff --git a/patches/ntdll-FD_Cache/0002-ntdll-Use-lockfree-implementation-for-get_cached_fd..patch b/patches/ntdll-FD_Cache/0002-ntdll-Use-lockfree-implementation-for-get_cached_fd..patch new file mode 100644 index 00000000..a9bdf0d9 --- /dev/null +++ b/patches/ntdll-FD_Cache/0002-ntdll-Use-lockfree-implementation-for-get_cached_fd..patch @@ -0,0 +1,207 @@ +From 65cdd8fabe3124792f9dc3c14ae4bdb96b47c481 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Thu, 30 Apr 2015 05:43:16 +0200 +Subject: ntdll: Use lockfree implementation for get_cached_fd. (try 2) + +v2: Avoid #ifdefs and simplify code a bit. On PowerPC all interlocked operations will use +interlocked_cmpxchg64, which means that we can implement it using a pthread lock. +--- + dlls/ntdll/server.c | 105 ++++++++++++++++++++++++++++++++++------------------ + 1 file changed, 68 insertions(+), 37 deletions(-) + +diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c +index 69d01be..652a1aa 100644 +--- a/dlls/ntdll/server.c ++++ b/dlls/ntdll/server.c +@@ -75,6 +75,8 @@ + + #include "ntstatus.h" + #define WIN32_NO_STATUS ++#include "windef.h" ++#include "winnt.h" + #include "wine/library.h" + #include "wine/server.h" + #include "wine/debug.h" +@@ -126,6 +128,17 @@ static RTL_CRITICAL_SECTION_DEBUG critsect_debug = + }; + static RTL_CRITICAL_SECTION fd_cache_section = { &critsect_debug, -1, 0, 0, 0, 0 }; + ++/* atomically exchange a 64-bit value */ ++static inline LONG64 interlocked_xchg64( LONG64 *dest, LONG64 val ) ++{ ++#ifdef _WIN64 ++ return (LONG64)interlocked_xchg_ptr( (void **)dest, (void *)val ); ++#else ++ LONG64 tmp = *dest; ++ while (interlocked_cmpxchg64( dest, val, tmp ) != tmp) tmp = *dest; ++ return tmp; ++#endif ++} + + #ifdef __GNUC__ + static void fatal_error( const char *err, ... ) __attribute__((noreturn, format(printf,1,2))); +@@ -790,19 +803,27 @@ static int receive_fd( obj_handle_t *handle ) + /***********************************************************************/ + /* fd cache support */ + +-struct fd_cache_entry ++#include "pshpack1.h" ++union fd_cache_entry + { +- int fd; +- enum server_fd_type type : 5; +- unsigned int access : 3; +- unsigned int options : 24; ++ LONG64 data; ++ struct ++ { ++ int fd; ++ enum server_fd_type type : 5; ++ unsigned int access : 3; ++ unsigned int options : 24; ++ } s; + }; ++#include "poppack.h" + +-#define FD_CACHE_BLOCK_SIZE (65536 / sizeof(struct fd_cache_entry)) ++C_ASSERT( sizeof(union fd_cache_entry) == sizeof(LONG64) ); ++ ++#define FD_CACHE_BLOCK_SIZE (65536 / sizeof(union fd_cache_entry)) + #define FD_CACHE_ENTRIES 128 + +-static struct fd_cache_entry *fd_cache[FD_CACHE_ENTRIES]; +-static struct fd_cache_entry fd_cache_initial_block[FD_CACHE_BLOCK_SIZE]; ++static union fd_cache_entry *fd_cache[FD_CACHE_ENTRIES]; ++static union fd_cache_entry fd_cache_initial_block[FD_CACHE_BLOCK_SIZE]; + + static inline unsigned int handle_to_index( HANDLE handle, unsigned int *entry ) + { +@@ -821,6 +842,7 @@ static BOOL add_fd_to_cache( HANDLE handle, int fd, enum server_fd_type type, + unsigned int access, unsigned int options ) + { + unsigned int entry, idx = handle_to_index( handle, &entry ); ++ union fd_cache_entry cache; + + if (entry >= FD_CACHE_ENTRIES) + { +@@ -833,26 +855,26 @@ static BOOL add_fd_to_cache( HANDLE handle, int fd, enum server_fd_type type, + if (!entry) fd_cache[0] = fd_cache_initial_block; + else + { +- void *ptr = wine_anon_mmap( NULL, FD_CACHE_BLOCK_SIZE * sizeof(struct fd_cache_entry), ++ void *ptr = wine_anon_mmap( NULL, FD_CACHE_BLOCK_SIZE * sizeof(union fd_cache_entry), + PROT_READ | PROT_WRITE, 0 ); + if (ptr == MAP_FAILED) return FALSE; + fd_cache[entry] = ptr; + } + } ++ + /* store fd+1 so that 0 can be used as the unset value */ +- fd = interlocked_xchg( &fd_cache[entry][idx].fd, fd + 1 ); +- fd_cache[entry][idx].type = type; +- fd_cache[entry][idx].access = access; +- fd_cache[entry][idx].options = options; +- assert( !fd ); ++ cache.s.fd = fd + 1; ++ cache.s.type = type; ++ cache.s.access = access; ++ cache.s.options = options; ++ cache.data = interlocked_xchg64( &fd_cache[entry][idx].data, cache.data ); ++ assert( !cache.s.fd ); + return TRUE; + } + + + /*********************************************************************** + * get_cached_fd +- * +- * Caller must hold fd_cache_section. + */ + static inline int get_cached_fd( HANDLE handle, enum server_fd_type *type, + unsigned int *access, unsigned int *options ) +@@ -862,10 +884,12 @@ static inline int get_cached_fd( HANDLE handle, enum server_fd_type *type, + + if (entry < FD_CACHE_ENTRIES && fd_cache[entry]) + { +- fd = fd_cache[entry][idx].fd - 1; +- if (type) *type = fd_cache[entry][idx].type; +- if (access) *access = fd_cache[entry][idx].access; +- if (options) *options = fd_cache[entry][idx].options; ++ union fd_cache_entry cache; ++ cache.data = interlocked_cmpxchg64( &fd_cache[entry][idx].data, 0, 0 ); ++ fd = cache.s.fd - 1; ++ if (type) *type = cache.s.type; ++ if (access) *access = cache.s.access; ++ if (options) *options = cache.s.options; + } + return fd; + } +@@ -880,7 +904,11 @@ int server_remove_fd_from_cache( HANDLE handle ) + int fd = -1; + + if (entry < FD_CACHE_ENTRIES && fd_cache[entry]) +- fd = interlocked_xchg( &fd_cache[entry][idx].fd, 0 ) - 1; ++ { ++ union fd_cache_entry cache; ++ cache.data = interlocked_xchg64( &fd_cache[entry][idx].data, 0 ); ++ fd = cache.s.fd - 1; ++ } + + return fd; + } +@@ -903,33 +931,36 @@ int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd, + *needs_close = 0; + wanted_access &= FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA; + +- server_enter_uninterrupted_section( &fd_cache_section, &sigset ); +- + fd = get_cached_fd( handle, type, &access, options ); + if (fd != -1) goto done; + +- SERVER_START_REQ( get_handle_fd ) ++ server_enter_uninterrupted_section( &fd_cache_section, &sigset ); ++ fd = get_cached_fd( handle, type, &access, options ); ++ if (fd == -1) + { +- req->handle = wine_server_obj_handle( handle ); +- if (!(ret = wine_server_call( req ))) ++ SERVER_START_REQ( get_handle_fd ) + { +- if (type) *type = reply->type; +- if (options) *options = reply->options; +- access = reply->access; +- if ((fd = receive_fd( &fd_handle )) != -1) ++ req->handle = wine_server_obj_handle( handle ); ++ if (!(ret = wine_server_call( req ))) + { +- assert( wine_server_ptr_handle(fd_handle) == handle ); +- *needs_close = (!reply->cacheable || +- !add_fd_to_cache( handle, fd, reply->type, +- reply->access, reply->options )); ++ if (type) *type = reply->type; ++ if (options) *options = reply->options; ++ access = reply->access; ++ if ((fd = receive_fd( &fd_handle )) != -1) ++ { ++ assert( wine_server_ptr_handle(fd_handle) == handle ); ++ *needs_close = (!reply->cacheable || ++ !add_fd_to_cache( handle, fd, reply->type, ++ reply->access, reply->options )); ++ } ++ else ret = STATUS_TOO_MANY_OPENED_FILES; + } +- else ret = STATUS_TOO_MANY_OPENED_FILES; + } ++ SERVER_END_REQ; + } +- SERVER_END_REQ; ++ server_leave_uninterrupted_section( &fd_cache_section, &sigset ); + + done: +- server_leave_uninterrupted_section( &fd_cache_section, &sigset ); + if (!ret && ((access & wanted_access) != wanted_access)) + { + ret = STATUS_ACCESS_DENIED; +-- +2.3.5 + diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index c36b7e0a..18879cc4 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -3433,12 +3433,14 @@ fi # Patchset ntdll-FD_Cache # | # | Modified files: -# | * dlls/ntdll/server.c +# | * dlls/ntdll/server.c, libs/port/interlocked.c # | if test "$enable_ntdll_FD_Cache" -eq 1; then - patch_apply ntdll-FD_Cache/0001-ntdll-Use-lockfree-implementation-for-get_cached_fd.patch + patch_apply ntdll-FD_Cache/0001-libs-Implement-interlocked_cmpxchg64-on-PowerPC-usin.patch + patch_apply ntdll-FD_Cache/0002-ntdll-Use-lockfree-implementation-for-get_cached_fd..patch ( - echo '+ { "Sebastian Lackner", "ntdll: Use lockfree implementation for get_cached_fd.", 5 },'; + echo '+ { "Sebastian Lackner", "libs: Implement interlocked_cmpxchg64 on PowerPC using pthread mutex.", 1 },'; + echo '+ { "Sebastian Lackner", "ntdll: Use lockfree implementation for get_cached_fd.", 2 },'; ) >> "$patchlist" fi