ntdll: Cache error information for cacheable handles with no fd.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2016-10-24 17:48:49 +02:00 committed by Alexandre Julliard
parent 5ede16eb40
commit 3b30002aec
1 changed files with 26 additions and 19 deletions

View File

@ -876,22 +876,25 @@ static BOOL add_fd_to_cache( HANDLE handle, int fd, enum server_fd_type type,
/***********************************************************************
* get_cached_fd
*/
static inline int get_cached_fd( HANDLE handle, enum server_fd_type *type,
unsigned int *access, unsigned int *options )
static inline NTSTATUS get_cached_fd( HANDLE handle, int *fd, enum server_fd_type *type,
unsigned int *access, unsigned int *options )
{
unsigned int entry, idx = handle_to_index( handle, &entry );
int fd = -1;
union fd_cache_entry cache;
if (entry < FD_CACHE_ENTRIES && fd_cache[entry])
{
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;
if (entry >= FD_CACHE_ENTRIES || !fd_cache[entry]) return STATUS_INVALID_HANDLE;
cache.data = interlocked_cmpxchg64( &fd_cache[entry][idx].data, 0, 0 );
if (!cache.data) return STATUS_INVALID_HANDLE;
/* if fd type is invalid, fd stores an error value */
if (cache.s.type == FD_TYPE_INVALID) return cache.s.fd - 1;
*fd = cache.s.fd - 1;
if (type) *type = cache.s.type;
if (access) *access = cache.s.access;
if (options) *options = cache.s.options;
return STATUS_SUCCESS;
}
@ -907,7 +910,7 @@ int server_remove_fd_from_cache( HANDLE handle )
{
union fd_cache_entry cache;
cache.data = interlocked_xchg64( &fd_cache[entry][idx].data, 0 );
fd = cache.s.fd - 1;
if (cache.s.type != FD_TYPE_INVALID) fd = cache.s.fd - 1;
}
return fd;
@ -924,19 +927,19 @@ int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd,
{
sigset_t sigset;
obj_handle_t fd_handle;
int ret = 0, fd;
int ret, fd = -1;
unsigned int access = 0;
*unix_fd = -1;
*needs_close = 0;
wanted_access &= FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA;
fd = get_cached_fd( handle, type, &access, options );
if (fd != -1) goto done;
ret = get_cached_fd( handle, &fd, type, &access, options );
if (ret != STATUS_INVALID_HANDLE) goto done;
server_enter_uninterrupted_section( &fd_cache_section, &sigset );
fd = get_cached_fd( handle, type, &access, options );
if (fd == -1)
ret = get_cached_fd( handle, &fd, type, &access, options );
if (ret == STATUS_INVALID_HANDLE)
{
SERVER_START_REQ( get_handle_fd )
{
@ -955,6 +958,10 @@ int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd,
}
else ret = STATUS_TOO_MANY_OPENED_FILES;
}
else if (reply->cacheable)
{
add_fd_to_cache( handle, ret, FD_TYPE_INVALID, 0, 0 );
}
}
SERVER_END_REQ;
}