ntdll: Avoid heap allocation in fd cache. Fixed a couple of races.
This commit is contained in:
parent
a6947bde23
commit
027491f6af
|
@ -1107,7 +1107,11 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc
|
||||||
{
|
{
|
||||||
req->handle = handle;
|
req->handle = handle;
|
||||||
io->u.Status = wine_server_call(req);
|
io->u.Status = wine_server_call(req);
|
||||||
if (!io->u.Status) server_remove_fd_from_cache( handle );
|
if (!io->u.Status)
|
||||||
|
{
|
||||||
|
int fd = server_remove_fd_from_cache( handle );
|
||||||
|
if (fd != -1) close( fd );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -313,7 +313,10 @@ NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source,
|
||||||
{
|
{
|
||||||
if (dest) *dest = reply->handle;
|
if (dest) *dest = reply->handle;
|
||||||
if (reply->closed)
|
if (reply->closed)
|
||||||
server_remove_fd_from_cache( source );
|
{
|
||||||
|
int fd = server_remove_fd_from_cache( source );
|
||||||
|
if (fd != -1) close( fd );
|
||||||
|
}
|
||||||
else if (options & DUPLICATE_CLOSE_SOURCE)
|
else if (options & DUPLICATE_CLOSE_SOURCE)
|
||||||
WARN( "failed to close handle %p in process %p\n", source, source_process );
|
WARN( "failed to close handle %p in process %p\n", source, source_process );
|
||||||
}
|
}
|
||||||
|
@ -337,13 +340,15 @@ NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source,
|
||||||
NTSTATUS WINAPI NtClose( HANDLE Handle )
|
NTSTATUS WINAPI NtClose( HANDLE Handle )
|
||||||
{
|
{
|
||||||
NTSTATUS ret;
|
NTSTATUS ret;
|
||||||
|
int fd = server_remove_fd_from_cache( Handle );
|
||||||
|
|
||||||
SERVER_START_REQ( close_handle )
|
SERVER_START_REQ( close_handle )
|
||||||
{
|
{
|
||||||
req->handle = Handle;
|
req->handle = Handle;
|
||||||
ret = wine_server_call( req );
|
ret = wine_server_call( req );
|
||||||
if (!ret) server_remove_fd_from_cache( Handle );
|
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
|
if (fd != -1) close( fd );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -458,10 +458,8 @@ static int receive_fd( obj_handle_t *handle )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline static unsigned int handle_to_index( obj_handle_t handle )
|
/***********************************************************************/
|
||||||
{
|
/* fd cache support */
|
||||||
return ((unsigned long)handle >> 2) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fd_cache_entry
|
struct fd_cache_entry
|
||||||
{
|
{
|
||||||
|
@ -469,8 +467,19 @@ struct fd_cache_entry
|
||||||
enum server_fd_type type;
|
enum server_fd_type type;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct fd_cache_entry *fd_cache;
|
#define FD_CACHE_BLOCK_SIZE (65536 / sizeof(struct fd_cache_entry))
|
||||||
static unsigned int fd_cache_size;
|
#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];
|
||||||
|
|
||||||
|
inline static unsigned int handle_to_index( obj_handle_t handle, unsigned int *entry )
|
||||||
|
{
|
||||||
|
unsigned long idx = ((unsigned long)handle >> 2) - 1;
|
||||||
|
*entry = idx / FD_CACHE_BLOCK_SIZE;
|
||||||
|
return idx % FD_CACHE_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* add_fd_to_cache
|
* add_fd_to_cache
|
||||||
|
@ -479,35 +488,31 @@ static unsigned int fd_cache_size;
|
||||||
*/
|
*/
|
||||||
static int add_fd_to_cache( obj_handle_t handle, int fd, enum server_fd_type type )
|
static int add_fd_to_cache( obj_handle_t handle, int fd, enum server_fd_type type )
|
||||||
{
|
{
|
||||||
unsigned int idx = handle_to_index( handle );
|
unsigned int entry, idx = handle_to_index( handle, &entry );
|
||||||
|
int prev_fd;
|
||||||
|
|
||||||
if (idx >= fd_cache_size)
|
if (entry >= FD_CACHE_ENTRIES)
|
||||||
{
|
{
|
||||||
unsigned int i, size = max( 32, fd_cache_size * 2 );
|
FIXME( "too many allocated handles, not caching %p\n", handle );
|
||||||
struct fd_cache_entry *new_cache;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (size <= idx) size = idx + 1;
|
if (!fd_cache[entry]) /* do we need to allocate a new block of entries? */
|
||||||
if (fd_cache)
|
{
|
||||||
new_cache = RtlReAllocateHeap( GetProcessHeap(), 0, fd_cache, size*sizeof(fd_cache[0]) );
|
if (!entry) fd_cache[0] = fd_cache_initial_block;
|
||||||
else
|
else
|
||||||
new_cache = RtlAllocateHeap( GetProcessHeap(), 0, size*sizeof(fd_cache[0]) );
|
|
||||||
|
|
||||||
if (new_cache)
|
|
||||||
{
|
{
|
||||||
for (i = fd_cache_size; i < size; i++) new_cache[i].fd = -1;
|
void *ptr = wine_anon_mmap( NULL, FD_CACHE_BLOCK_SIZE * sizeof(struct fd_cache_entry),
|
||||||
fd_cache = new_cache;
|
PROT_READ | PROT_WRITE, 0 );
|
||||||
fd_cache_size = size;
|
if (ptr == MAP_FAILED) return 0;
|
||||||
|
fd_cache[entry] = ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (idx < fd_cache_size)
|
/* store fd+1 so that 0 can be used as the unset value */
|
||||||
{
|
prev_fd = interlocked_xchg( &fd_cache[entry][idx].fd, fd + 1 ) - 1;
|
||||||
assert( fd_cache[idx].fd == -1 );
|
fd_cache[entry][idx].type = type;
|
||||||
fd_cache[idx].fd = fd;
|
if (prev_fd != -1) close( prev_fd );
|
||||||
fd_cache[idx].type = type;
|
return 1;
|
||||||
TRACE("added %p (%d) type %d to cache\n", handle, fd, type );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -518,13 +523,13 @@ static int add_fd_to_cache( obj_handle_t handle, int fd, enum server_fd_type typ
|
||||||
*/
|
*/
|
||||||
static inline int get_cached_fd( obj_handle_t handle, enum server_fd_type *type )
|
static inline int get_cached_fd( obj_handle_t handle, enum server_fd_type *type )
|
||||||
{
|
{
|
||||||
unsigned int idx = handle_to_index( handle );
|
unsigned int entry, idx = handle_to_index( handle, &entry );
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
|
|
||||||
if (idx < fd_cache_size)
|
if (entry < FD_CACHE_ENTRIES && fd_cache[entry])
|
||||||
{
|
{
|
||||||
fd = fd_cache[idx].fd;
|
fd = fd_cache[entry][idx].fd - 1;
|
||||||
if (type) *type = fd_cache[idx].type;
|
if (type) *type = fd_cache[entry][idx].type;
|
||||||
}
|
}
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
@ -535,22 +540,12 @@ static inline int get_cached_fd( obj_handle_t handle, enum server_fd_type *type
|
||||||
*/
|
*/
|
||||||
int server_remove_fd_from_cache( obj_handle_t handle )
|
int server_remove_fd_from_cache( obj_handle_t handle )
|
||||||
{
|
{
|
||||||
unsigned int idx = handle_to_index( handle );
|
unsigned int entry, idx = handle_to_index( handle, &entry );
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
|
|
||||||
RtlEnterCriticalSection( &fd_cache_section );
|
if (entry < FD_CACHE_ENTRIES && fd_cache[entry])
|
||||||
if (idx < fd_cache_size)
|
fd = interlocked_xchg( &fd_cache[entry][idx].fd, 0 ) - 1;
|
||||||
{
|
|
||||||
fd = fd_cache[idx].fd;
|
|
||||||
fd_cache[idx].fd = -1;
|
|
||||||
}
|
|
||||||
RtlLeaveCriticalSection( &fd_cache_section );
|
|
||||||
|
|
||||||
if (fd != -1)
|
|
||||||
{
|
|
||||||
close( fd );
|
|
||||||
TRACE("removed %p (%d) from cache\n", handle, fd );
|
|
||||||
}
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue