ntdll: Store the file access and options in the fd cache, and get rid of the dynamic flags.

This avoids server round-trips for all file I/O.
This commit is contained in:
Alexandre Julliard 2007-04-10 22:32:46 +02:00
parent 7a9363a4d4
commit d85121f199
9 changed files with 91 additions and 104 deletions

View File

@ -526,7 +526,8 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
PLARGE_INTEGER offset, PULONG key)
{
int result, unix_handle, needs_close, flags, timeout_init_done = 0;
int result, unix_handle, needs_close, timeout_init_done = 0;
unsigned int options;
struct io_timeouts timeouts;
NTSTATUS status;
ULONG total = 0;
@ -538,7 +539,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
if (!io_status) return STATUS_ACCESS_VIOLATION;
status = server_get_unix_fd( hFile, FILE_READ_DATA, &unix_handle,
&needs_close, &type, &flags );
&needs_close, &type, &options );
if (status) return status;
if (type == FD_TYPE_FILE && offset && offset->QuadPart != (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */ )
@ -552,7 +553,8 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
goto done;
}
}
if (!(flags & FD_FLAG_OVERLAPPED)) /* update file pointer position */
if (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
/* update file pointer position */
lseek( unix_handle, offset->QuadPart + result, SEEK_SET );
total = result;
@ -584,7 +586,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
}
}
if (flags & FD_FLAG_OVERLAPPED)
if (!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
{
async_fileio_read *fileio;
BOOL avail_mode;
@ -761,7 +763,8 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
const void* buffer, ULONG length,
PLARGE_INTEGER offset, PULONG key)
{
int result, unix_handle, needs_close, flags, timeout_init_done = 0;
int result, unix_handle, needs_close, timeout_init_done = 0;
unsigned int options;
struct io_timeouts timeouts;
NTSTATUS status;
ULONG total = 0;
@ -773,7 +776,7 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
if (!io_status) return STATUS_ACCESS_VIOLATION;
status = server_get_unix_fd( hFile, FILE_WRITE_DATA, &unix_handle,
&needs_close, &type, &flags );
&needs_close, &type, &options );
if (status) return status;
if (type == FD_TYPE_FILE && offset && offset->QuadPart != (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */ )
@ -789,7 +792,8 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
}
}
if (!(flags & FD_FLAG_OVERLAPPED)) /* update file pointer position */
if (options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
/* update file pointer position */
lseek( unix_handle, offset->QuadPart + result, SEEK_SET );
total = result;
@ -825,7 +829,7 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
}
}
if (flags & FD_FLAG_OVERLAPPED)
if (!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
{
async_fileio_write *fileio;
@ -1089,7 +1093,7 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc
case FSCTL_PIPE_PEEK:
{
FILE_PIPE_PEEK_BUFFER *buffer = out_buffer;
int avail = 0, fd, needs_close, flags;
int avail = 0, fd, needs_close;
if (out_size < FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ))
{
@ -1097,16 +1101,9 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc
break;
}
if ((status = server_get_unix_fd( handle, FILE_READ_DATA, &fd, &needs_close, NULL, &flags )))
if ((status = server_get_unix_fd( handle, FILE_READ_DATA, &fd, &needs_close, NULL, NULL )))
break;
if (flags & FD_FLAG_RECV_SHUTDOWN)
{
if (needs_close) close( fd );
status = STATUS_PIPE_DISCONNECTED;
break;
}
#ifdef FIONREAD
if (ioctl( fd, FIONREAD, &avail ) != 0)
{

View File

@ -69,7 +69,7 @@ extern void server_enter_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset
extern void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset );
extern int server_remove_fd_from_cache( obj_handle_t handle );
extern int server_get_unix_fd( obj_handle_t handle, unsigned int access, int *unix_fd,
int *needs_close, enum server_fd_type *type, int *flags );
int *needs_close, enum server_fd_type *type, unsigned int *options );
/* module handling */
extern NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved );

View File

@ -464,7 +464,9 @@ static int receive_fd( obj_handle_t *handle )
struct fd_cache_entry
{
int fd;
enum server_fd_type type;
enum server_fd_type type : 6;
unsigned int access : 2;
unsigned int options : 24;
};
#define FD_CACHE_BLOCK_SIZE (65536 / sizeof(struct fd_cache_entry))
@ -486,7 +488,8 @@ static inline unsigned int handle_to_index( obj_handle_t handle, unsigned int *e
*
* Caller must hold fd_cache_section.
*/
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 access, unsigned int options )
{
unsigned int entry, idx = handle_to_index( handle, &entry );
int prev_fd;
@ -511,6 +514,8 @@ static int add_fd_to_cache( obj_handle_t handle, int fd, enum server_fd_type typ
/* 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;
fd_cache[entry][idx].type = type;
fd_cache[entry][idx].access = access;
fd_cache[entry][idx].options = options;
if (prev_fd != -1) close( prev_fd );
return 1;
}
@ -521,7 +526,8 @@ static int add_fd_to_cache( obj_handle_t handle, int fd, enum server_fd_type typ
*
* Caller must hold fd_cache_section.
*/
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 *access, unsigned int *options )
{
unsigned int entry, idx = handle_to_index( handle, &entry );
int fd = -1;
@ -530,6 +536,8 @@ static inline int get_cached_fd( obj_handle_t handle, enum server_fd_type *type
{
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;
}
return fd;
}
@ -555,46 +563,50 @@ int server_remove_fd_from_cache( obj_handle_t handle )
*
* The returned unix_fd should be closed iff needs_close is non-zero.
*/
int server_get_unix_fd( obj_handle_t handle, unsigned int access, int *unix_fd,
int *needs_close, enum server_fd_type *type, int *flags )
int server_get_unix_fd( obj_handle_t handle, unsigned int wanted_access, int *unix_fd,
int *needs_close, enum server_fd_type *type, unsigned int *options )
{
sigset_t sigset;
obj_handle_t fd_handle;
int ret = 0, removable = 0, fd;
int ret = 0, fd;
unsigned int access;
*unix_fd = -1;
*needs_close = 0;
wanted_access &= FILE_READ_DATA | FILE_WRITE_DATA;
server_enter_uninterrupted_section( &fd_cache_section, &sigset );
fd = get_cached_fd( handle, type );
if (fd != -1 && !flags) goto done;
fd = get_cached_fd( handle, type, &access, options );
if (fd != -1) goto done;
SERVER_START_REQ( get_handle_fd )
{
req->handle = handle;
req->access = access;
req->cached = (fd != -1);
if (!(ret = wine_server_call( req )))
{
removable = reply->flags & FD_FLAG_REMOVABLE;
if (type) *type = reply->type;
if (flags) *flags = reply->flags;
if (fd == -1)
if (options) *options = reply->options;
access = reply->access;
if ((fd = receive_fd( &fd_handle )) != -1)
{
if ((fd = receive_fd( &fd_handle )) != -1)
{
assert( fd_handle == handle );
*needs_close = removable || !add_fd_to_cache( handle, fd, reply->type );
}
else ret = STATUS_TOO_MANY_OPENED_FILES;
assert( fd_handle == handle );
*needs_close = (reply->removable ||
!add_fd_to_cache( handle, fd, reply->type,
reply->access, reply->options ));
}
else ret = STATUS_TOO_MANY_OPENED_FILES;
}
}
SERVER_END_REQ;
done:
server_leave_uninterrupted_section( &fd_cache_section, &sigset );
if (!ret && ((access & wanted_access) != wanted_access))
{
ret = STATUS_ACCESS_DENIED;
if (*needs_close) close( fd );
}
if (!ret) *unix_fd = fd;
return ret;
}
@ -642,14 +654,15 @@ int wine_server_fd_to_handle( int fd, unsigned int access, unsigned int attribut
* handle [I] Wine file handle.
* access [I] Win32 file access rights requested.
* unix_fd [O] Address where Unix file descriptor will be stored.
* flags [O] Address where the Unix flags associated with file will be stored. Optional.
* options [O] Address where the file open options will be stored. Optional.
*
* RETURNS
* NTSTATUS code
*/
int wine_server_handle_to_fd( obj_handle_t handle, unsigned int access, int *unix_fd, int *flags )
int wine_server_handle_to_fd( obj_handle_t handle, unsigned int access, int *unix_fd,
unsigned int *options )
{
int needs_close, ret = server_get_unix_fd( handle, access, unix_fd, &needs_close, NULL, flags );
int needs_close, ret = server_get_unix_fd( handle, access, unix_fd, &needs_close, NULL, options );
if (!ret && !needs_close)
{

View File

@ -384,10 +384,10 @@ static inline unsigned int set_error( unsigned int err )
return err;
}
static inline int get_sock_fd( SOCKET s, DWORD access, int *flags )
static inline int get_sock_fd( SOCKET s, DWORD access, unsigned int *options )
{
int fd;
if (set_error( wine_server_handle_to_fd( SOCKET2HANDLE(s), access, &fd, flags ) ))
if (set_error( wine_server_handle_to_fd( SOCKET2HANDLE(s), access, &fd, options ) ))
return -1;
return fd;
}
@ -2754,8 +2754,8 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
{
unsigned int i;
int n, fd, err = WSAENOTSOCK, flags, ret;
unsigned int i, options;
int n, fd, err = WSAENOTSOCK, ret;
struct iovec* iovec;
struct ws2_async *wsa;
IO_STATUS_BLOCK* iosb;
@ -2764,17 +2764,11 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
s, lpBuffers, dwBufferCount, dwFlags,
to, tolen, lpOverlapped, lpCompletionRoutine);
fd = get_sock_fd( s, FILE_WRITE_DATA, &flags );
TRACE( "fd=%d, flags=%x\n", fd, flags );
fd = get_sock_fd( s, FILE_WRITE_DATA, &options );
TRACE( "fd=%d, options=%x\n", fd, options );
if ( fd == -1 ) return SOCKET_ERROR;
if (flags & FD_FLAG_SEND_SHUTDOWN)
{
WSASetLastError( WSAESHUTDOWN );
goto err_close;
}
if ( !lpNumberOfBytesSent )
{
err = WSAEFAULT;
@ -2795,7 +2789,8 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
iovec[i].iov_len = lpBuffers[i].len;
}
if ( (lpOverlapped || lpCompletionRoutine) && flags & FD_FLAG_OVERLAPPED )
if ( (lpOverlapped || lpCompletionRoutine) &&
!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
{
wsa = WS2_make_async( s, ws2m_write, iovec, dwBufferCount,
&dwFlags, (struct WS_sockaddr*) to, &tolen,
@ -3175,11 +3170,11 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname,
*/
int WINAPI WS_shutdown(SOCKET s, int how)
{
int fd, flags, err = WSAENOTSOCK;
unsigned int clear_flags = 0;
int fd, err = WSAENOTSOCK;
unsigned int options, clear_flags = 0;
fd = get_sock_fd( s, 0, &flags );
TRACE("socket %04x, how %i %x\n", s, how, flags );
fd = get_sock_fd( s, 0, &options );
TRACE("socket %04x, how %i %x\n", s, how, options );
if (fd == -1)
return SOCKET_ERROR;
@ -3198,8 +3193,8 @@ int WINAPI WS_shutdown(SOCKET s, int how)
clear_flags |= FD_WINE_LISTENING;
}
if ( flags & FD_FLAG_OVERLAPPED ) {
if (!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
{
switch ( how )
{
case SD_RECEIVE:
@ -4265,8 +4260,8 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
{
unsigned int i;
int n, fd, err = WSAENOTSOCK, flags, ret;
unsigned int i, options;
int n, fd, err = WSAENOTSOCK, ret;
struct iovec* iovec;
struct ws2_async *wsa;
IO_STATUS_BLOCK* iosb;
@ -4276,17 +4271,11 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
(lpFromlen ? *lpFromlen : -1),
lpOverlapped, lpCompletionRoutine);
fd = get_sock_fd( s, FILE_READ_DATA, &flags );
TRACE( "fd=%d, flags=%x\n", fd, flags );
fd = get_sock_fd( s, FILE_READ_DATA, &options );
TRACE( "fd=%d, options=%x\n", fd, options );
if (fd == -1) return SOCKET_ERROR;
if (flags & FD_FLAG_RECV_SHUTDOWN)
{
WSASetLastError( WSAESHUTDOWN );
goto err_close;
}
iovec = HeapAlloc( GetProcessHeap(), 0, dwBufferCount * sizeof (struct iovec) );
if ( !iovec )
{
@ -4300,7 +4289,8 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
iovec[i].iov_len = lpBuffers[i].len;
}
if ( (lpOverlapped || lpCompletionRoutine) && flags & FD_FLAG_OVERLAPPED )
if ( (lpOverlapped || lpCompletionRoutine) &&
!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
{
wsa = WS2_make_async( s, ws2m_read, iovec, dwBufferCount,
lpFlags, lpFrom, lpFromlen,

View File

@ -52,7 +52,7 @@ struct __server_request_info
extern unsigned int wine_server_call( void *req_ptr );
extern void wine_server_send_fd( int fd );
extern int wine_server_fd_to_handle( int fd, unsigned int access, unsigned int attributes, obj_handle_t *handle );
extern int wine_server_handle_to_fd( obj_handle_t handle, unsigned int access, int *unix_fd, int *flags );
extern int wine_server_handle_to_fd( obj_handle_t handle, unsigned int access, int *unix_fd, unsigned int *options );
extern void wine_server_release_fd( obj_handle_t handle, int unix_fd );
/* do a server call and set the last error code */

View File

@ -1067,14 +1067,14 @@ 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 type;
int flags;
int removable;
unsigned int access;
unsigned int options;
};
enum server_fd_type
{
@ -1088,13 +1088,7 @@ enum server_fd_type
FD_TYPE_DEVICE,
FD_TYPE_NB_TYPES
};
#define FD_FLAG_OVERLAPPED 0x01
#define FD_FLAG_TIMEOUT 0x02
#define FD_FLAG_RECV_SHUTDOWN 0x04
#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 flush_file_request
@ -4677,6 +4671,6 @@ union generic_reply
struct allocate_locally_unique_id_reply allocate_locally_unique_id_reply;
};
#define SERVER_PROTOCOL_VERSION 291
#define SERVER_PROTOCOL_VERSION 292
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -1905,19 +1905,18 @@ DECL_HANDLER(get_handle_fd)
{
struct fd *fd;
if ((fd = get_handle_fd_obj( current->process, req->handle, req->access )))
if ((fd = get_handle_fd_obj( current->process, req->handle, 0 )))
{
reply->flags = 0;
reply->type = fd->fd_ops->get_fd_type( fd );
if (reply->type != FD_TYPE_INVALID)
{
if (!(fd->options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
reply->flags |= FD_FLAG_OVERLAPPED;
if (is_fd_removable(fd)) reply->flags |= FD_FLAG_REMOVABLE;
if (!req->cached)
int unix_fd = get_unix_fd( fd );
if (unix_fd != -1)
{
int unix_fd = get_unix_fd( fd );
if (unix_fd != -1) send_client_fd( current->process, unix_fd, req->handle );
send_client_fd( current->process, unix_fd, req->handle );
reply->removable = is_fd_removable(fd);
reply->options = fd->options;
reply->access = get_handle_access( current->process, req->handle );
}
}
else set_error( STATUS_OBJECT_TYPE_MISMATCH );

View File

@ -883,11 +883,11 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
/* Get a Unix fd to access a file */
@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 type; /* file type (see below) */
int flags; /* file read/write flags (see below) */
int removable; /* is file removable? */
unsigned int access; /* file access rights */
unsigned int options; /* file open options */
@END
enum server_fd_type
{
@ -901,13 +901,7 @@ enum server_fd_type
FD_TYPE_DEVICE, /* Windows device file */
FD_TYPE_NB_TYPES
};
#define FD_FLAG_OVERLAPPED 0x01 /* fd opened in overlapped mode */
#define FD_FLAG_TIMEOUT 0x02 /* read/write is synchronous */
#define FD_FLAG_RECV_SHUTDOWN 0x04
#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? */
/* Flush a file buffers */
@REQ(flush_file)

View File

@ -1274,15 +1274,15 @@ 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, " cached=%d", req->cached );
fprintf( stderr, " handle=%p", req->handle );
}
static void dump_get_handle_fd_reply( const struct get_handle_fd_reply *req )
{
fprintf( stderr, " type=%d,", req->type );
fprintf( stderr, " flags=%d", req->flags );
fprintf( stderr, " removable=%d,", req->removable );
fprintf( stderr, " access=%08x,", req->access );
fprintf( stderr, " options=%08x", req->options );
}
static void dump_flush_file_request( const struct flush_file_request *req )