From: Sebastian Lackner Subject: ntdll: Use lockfree implementation for get_cached_fd. (resend) Message-Id: <54FFA0A0.3050509@fds-team.de> Date: Wed, 11 Mar 2015 02:55:44 +0100 Contains a couple of small improvements compared with the last attempt. As a reminder, the #ifdefs are there because we do not have 64-bit interlocked instructions on PowerPC (and I have also no idea if its possible at all to implement them properly). --- dlls/ntdll/server.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) From 5a6c09ad9c161e84218d99121041e44c5b40ddc7 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. --- 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.1