ntdll: Maintain a file descriptor cache on the client side.
This commit is contained in:
parent
258008012c
commit
28418cc919
|
@ -1093,7 +1093,7 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc
|
|||
{
|
||||
req->handle = handle;
|
||||
io->u.Status = wine_server_call(req);
|
||||
if (!io->u.Status && reply->fd != -1) close(reply->fd);
|
||||
if (!io->u.Status) server_remove_fd_from_cache( handle );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
break;
|
||||
|
|
|
@ -61,6 +61,7 @@ extern void DECLSPEC_NORETURN server_protocol_error( const char *err, ... );
|
|||
extern void DECLSPEC_NORETURN server_protocol_perror( const char *err );
|
||||
extern void DECLSPEC_NORETURN server_exit_thread( int status );
|
||||
extern void DECLSPEC_NORETURN server_abort_thread( int status );
|
||||
extern int server_remove_fd_from_cache( obj_handle_t handle );
|
||||
|
||||
/* module handling */
|
||||
extern NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved );
|
||||
|
|
|
@ -312,7 +312,10 @@ NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source,
|
|||
if (!(ret = wine_server_call( req )))
|
||||
{
|
||||
if (dest) *dest = reply->handle;
|
||||
if (reply->fd != -1) close( reply->fd );
|
||||
if (reply->closed)
|
||||
server_remove_fd_from_cache( source );
|
||||
else if (options & DUPLICATE_CLOSE_SOURCE)
|
||||
WARN( "failed to close handle %p in process %p\n", source, source_process );
|
||||
}
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
@ -338,7 +341,7 @@ NTSTATUS WINAPI NtClose( HANDLE Handle )
|
|||
{
|
||||
req->handle = Handle;
|
||||
ret = wine_server_call( req );
|
||||
if (!ret && reply->fd != -1) close( reply->fd );
|
||||
if (!ret) server_remove_fd_from_cache( Handle );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
return ret;
|
||||
|
|
|
@ -438,6 +438,92 @@ static int receive_fd( obj_handle_t *handle )
|
|||
}
|
||||
|
||||
|
||||
inline static unsigned int handle_to_index( obj_handle_t handle )
|
||||
{
|
||||
return ((unsigned long)handle >> 2) - 1;
|
||||
}
|
||||
|
||||
static int *fd_cache;
|
||||
static unsigned int fd_cache_size;
|
||||
|
||||
/***********************************************************************
|
||||
* add_fd_to_cache
|
||||
*
|
||||
* Caller must hold fd_cache_section.
|
||||
*/
|
||||
static int add_fd_to_cache( obj_handle_t handle, int fd )
|
||||
{
|
||||
unsigned int idx = handle_to_index( handle );
|
||||
|
||||
if (idx >= fd_cache_size)
|
||||
{
|
||||
unsigned int i, size = max( 32, fd_cache_size * 2 );
|
||||
int *new_cache;
|
||||
|
||||
if (size <= idx) size = idx + 1;
|
||||
if (fd_cache)
|
||||
new_cache = RtlReAllocateHeap( GetProcessHeap(), 0, fd_cache, size*sizeof(fd_cache[0]) );
|
||||
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] = -1;
|
||||
fd_cache = new_cache;
|
||||
fd_cache_size = size;
|
||||
}
|
||||
}
|
||||
if (idx < fd_cache_size)
|
||||
{
|
||||
assert( fd_cache[idx] == -1 );
|
||||
fd_cache[idx] = fd;
|
||||
TRACE("added %p (%d) to cache\n", handle, fd );
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_cached_fd
|
||||
*
|
||||
* Caller must hold fd_cache_section.
|
||||
*/
|
||||
static inline int get_cached_fd( obj_handle_t handle )
|
||||
{
|
||||
unsigned int idx = handle_to_index( handle );
|
||||
int fd = -1;
|
||||
|
||||
if (idx < fd_cache_size) fd = fd_cache[idx];
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* server_remove_fd_from_cache
|
||||
*/
|
||||
int server_remove_fd_from_cache( obj_handle_t handle )
|
||||
{
|
||||
unsigned int idx = handle_to_index( handle );
|
||||
int fd = -1;
|
||||
|
||||
RtlEnterCriticalSection( &fd_cache_section );
|
||||
if (idx < fd_cache_size)
|
||||
{
|
||||
fd = fd_cache[idx];
|
||||
fd_cache[idx] = -1;
|
||||
}
|
||||
RtlLeaveCriticalSection( &fd_cache_section );
|
||||
|
||||
if (fd != -1)
|
||||
{
|
||||
close( fd );
|
||||
TRACE("removed %p (%d) from cache\n", handle, fd );
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* wine_server_fd_to_handle (NTDLL.@)
|
||||
*
|
||||
|
@ -488,20 +574,27 @@ int wine_server_fd_to_handle( int fd, unsigned int access, unsigned int attribut
|
|||
int wine_server_handle_to_fd( obj_handle_t handle, unsigned int access, int *unix_fd, int *flags )
|
||||
{
|
||||
obj_handle_t fd_handle;
|
||||
int ret, removable = -1, fd = -1;
|
||||
int ret = 0, removable = 0, fd = -1;
|
||||
|
||||
RtlEnterCriticalSection( &fd_cache_section );
|
||||
|
||||
*unix_fd = -1;
|
||||
|
||||
fd = get_cached_fd( handle );
|
||||
if (fd != -1 && !flags)
|
||||
{
|
||||
if ((fd = dup(fd)) == -1) ret = FILE_GetNtStatus();
|
||||
goto done;
|
||||
}
|
||||
|
||||
SERVER_START_REQ( get_handle_fd )
|
||||
{
|
||||
req->handle = handle;
|
||||
req->access = access;
|
||||
req->cached = (fd != -1);
|
||||
if (!(ret = wine_server_call( req )))
|
||||
{
|
||||
fd = reply->fd;
|
||||
removable = reply->removable;
|
||||
removable = reply->flags & FD_FLAG_REMOVABLE;
|
||||
if (flags) *flags = reply->flags;
|
||||
}
|
||||
}
|
||||
|
@ -525,26 +618,10 @@ int wine_server_handle_to_fd( obj_handle_t handle, unsigned int access, int *uni
|
|||
|
||||
if (removable) goto done; /* don't cache it */
|
||||
|
||||
/* and store it back into the cache */
|
||||
SERVER_START_REQ( set_handle_fd )
|
||||
if (add_fd_to_cache( handle, fd ))
|
||||
{
|
||||
req->handle = fd_handle;
|
||||
req->fd = fd;
|
||||
if (!(ret = wine_server_call( req )))
|
||||
{
|
||||
if (reply->cur_fd != -1) /* it has been cached */
|
||||
{
|
||||
if (reply->cur_fd != fd) close( fd ); /* someone was here before us */
|
||||
if ((fd = dup(reply->cur_fd)) == -1) ret = FILE_GetNtStatus();
|
||||
if ((fd = dup(fd)) == -1) ret = FILE_GetNtStatus();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
close( fd );
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
done:
|
||||
RtlLeaveCriticalSection( &fd_cache_section );
|
||||
|
|
|
@ -585,7 +585,7 @@ struct dup_handle_reply
|
|||
{
|
||||
struct reply_header __header;
|
||||
obj_handle_t handle;
|
||||
int fd;
|
||||
int closed;
|
||||
};
|
||||
#define DUP_HANDLE_CLOSE_SOURCE DUPLICATE_CLOSE_SOURCE
|
||||
#define DUP_HANDLE_SAME_ACCESS DUPLICATE_SAME_ACCESS
|
||||
|
@ -840,12 +840,11 @@ struct get_handle_fd_request
|
|||
struct request_header __header;
|
||||
obj_handle_t handle;
|
||||
unsigned int access;
|
||||
int cached;
|
||||
};
|
||||
struct get_handle_fd_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
int fd;
|
||||
int removable;
|
||||
int flags;
|
||||
};
|
||||
#define FD_FLAG_OVERLAPPED 0x01
|
||||
|
@ -854,6 +853,7 @@ struct get_handle_fd_reply
|
|||
#define FD_FLAG_SEND_SHUTDOWN 0x08
|
||||
#define FD_FLAG_AVAILABLE 0x10 /* in overlap read/write operation,
|
||||
* only handle available data (don't wait) */
|
||||
#define FD_FLAG_REMOVABLE 0x20
|
||||
|
||||
|
||||
struct set_handle_fd_request
|
||||
|
@ -4425,6 +4425,6 @@ union generic_reply
|
|||
struct query_symlink_reply query_symlink_reply;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 256
|
||||
#define SERVER_PROTOCOL_VERSION 257
|
||||
|
||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||
|
|
12
server/fd.c
12
server/fd.c
|
@ -1944,19 +1944,15 @@ DECL_HANDLER(get_handle_fd)
|
|||
{
|
||||
struct fd *fd;
|
||||
|
||||
reply->fd = -1;
|
||||
|
||||
if ((fd = get_handle_fd_obj( current->process, req->handle, req->access )))
|
||||
{
|
||||
int unix_fd = get_unix_fd( fd );
|
||||
if (unix_fd != -1)
|
||||
if (!req->cached)
|
||||
{
|
||||
int cached_fd = get_handle_unix_fd( current->process, req->handle, req->access );
|
||||
if (cached_fd != -1) reply->fd = cached_fd;
|
||||
else if (!get_error()) send_client_fd( current->process, unix_fd, req->handle );
|
||||
int unix_fd = get_unix_fd( fd );
|
||||
if (unix_fd != -1) send_client_fd( current->process, unix_fd, req->handle );
|
||||
}
|
||||
if (fd->inode) reply->removable = fd->inode->device->removable;
|
||||
reply->flags = fd->fd_ops->get_file_info( fd );
|
||||
if (fd->inode && fd->inode->device->removable) reply->flags |= FD_FLAG_REMOVABLE;
|
||||
release_object( fd );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -562,7 +562,6 @@ DECL_HANDLER(dup_handle)
|
|||
struct process *src, *dst;
|
||||
|
||||
reply->handle = 0;
|
||||
reply->fd = -1;
|
||||
if ((src = get_process_from_handle( req->src_process, PROCESS_DUP_HANDLE )))
|
||||
{
|
||||
if (req->options & DUP_HANDLE_MAKE_GLOBAL)
|
||||
|
@ -579,8 +578,9 @@ DECL_HANDLER(dup_handle)
|
|||
/* close the handle no matter what happened */
|
||||
if (req->options & DUP_HANDLE_CLOSE_SOURCE)
|
||||
{
|
||||
if (src == current->process) close_handle( src, req->src_handle, &reply->fd );
|
||||
else close_handle( src, req->src_handle, NULL );
|
||||
unsigned int err = get_error(); /* don't overwrite error from the above calls */
|
||||
reply->closed = close_handle( src, req->src_handle, NULL );
|
||||
set_error( err );
|
||||
}
|
||||
release_object( src );
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@ enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC_IO };
|
|||
unsigned int options; /* duplicate options (see below) */
|
||||
@REPLY
|
||||
obj_handle_t handle; /* duplicated handle in dst process */
|
||||
int fd; /* associated fd to close */
|
||||
int closed; /* whether the source handle has been closed */
|
||||
@END
|
||||
#define DUP_HANDLE_CLOSE_SOURCE DUPLICATE_CLOSE_SOURCE
|
||||
#define DUP_HANDLE_SAME_ACCESS DUPLICATE_SAME_ACCESS
|
||||
|
@ -661,9 +661,8 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
|
|||
@REQ(get_handle_fd)
|
||||
obj_handle_t handle; /* handle to the file */
|
||||
unsigned int access; /* wanted access rights */
|
||||
int cached; /* is it cached on the client already? */
|
||||
@REPLY
|
||||
int fd; /* file descriptor */
|
||||
int removable; /* is device removable? (-1 if unknown) */
|
||||
int flags; /* file read/write flags (see below) */
|
||||
@END
|
||||
#define FD_FLAG_OVERLAPPED 0x01 /* fd opened in overlapped mode */
|
||||
|
@ -672,6 +671,7 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
|
|||
#define FD_FLAG_SEND_SHUTDOWN 0x08
|
||||
#define FD_FLAG_AVAILABLE 0x10 /* in overlap read/write operation,
|
||||
* only handle available data (don't wait) */
|
||||
#define FD_FLAG_REMOVABLE 0x20 /* is it on a removable device? */
|
||||
|
||||
/* Set the cached file descriptor of a handle */
|
||||
@REQ(set_handle_fd)
|
||||
|
|
|
@ -901,7 +901,7 @@ static void dump_dup_handle_request( const struct dup_handle_request *req )
|
|||
static void dump_dup_handle_reply( const struct dup_handle_reply *req )
|
||||
{
|
||||
fprintf( stderr, " handle=%p,", req->handle );
|
||||
fprintf( stderr, " fd=%d", req->fd );
|
||||
fprintf( stderr, " closed=%d", req->closed );
|
||||
}
|
||||
|
||||
static void dump_open_process_request( const struct open_process_request *req )
|
||||
|
@ -1103,13 +1103,12 @@ static void dump_alloc_file_handle_reply( const struct alloc_file_handle_reply *
|
|||
static void dump_get_handle_fd_request( const struct get_handle_fd_request *req )
|
||||
{
|
||||
fprintf( stderr, " handle=%p,", req->handle );
|
||||
fprintf( stderr, " access=%08x", req->access );
|
||||
fprintf( stderr, " access=%08x,", req->access );
|
||||
fprintf( stderr, " cached=%d", req->cached );
|
||||
}
|
||||
|
||||
static void dump_get_handle_fd_reply( const struct get_handle_fd_reply *req )
|
||||
{
|
||||
fprintf( stderr, " fd=%d,", req->fd );
|
||||
fprintf( stderr, " removable=%d,", req->removable );
|
||||
fprintf( stderr, " flags=%d", req->flags );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue