ntdll: Move fd cache functions to the Unix library.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
feature/deterministic
Alexandre Julliard 2020-05-29 15:35:16 +02:00
parent 8a63b688ac
commit 1a743c9af3
15 changed files with 335 additions and 270 deletions

View File

@ -2844,7 +2844,7 @@ NTSTATUS CDROM_DeviceIoControl(HANDLE hDevice,
piosb->Information = 0; piosb->Information = 0;
if ((status = server_get_unix_fd( hDevice, 0, &fd, &needs_close, NULL, NULL ))) if ((status = unix_funcs->server_get_unix_fd( hDevice, 0, &fd, &needs_close, NULL, NULL )))
{ {
if (status == STATUS_BAD_DEVICE_TYPE) return status; /* no associated fd */ if (status == STATUS_BAD_DEVICE_TYPE) return status; /* no associated fd */
goto error; goto error;

View File

@ -1946,7 +1946,7 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH NtQueryDirectoryFile( HANDLE handle, HANDLE ev
} }
if (!buffer) return STATUS_ACCESS_VIOLATION; if (!buffer) return STATUS_ACCESS_VIOLATION;
if ((status = server_get_unix_fd( handle, FILE_LIST_DIRECTORY, &fd, &needs_close, NULL, NULL )) != STATUS_SUCCESS) if ((status = unix_funcs->server_get_unix_fd( handle, FILE_LIST_DIRECTORY, &fd, &needs_close, NULL, NULL )) != STATUS_SUCCESS)
return status; return status;
io->Information = 0; io->Information = 0;
@ -2436,7 +2436,7 @@ NTSTATUS file_id_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, ANSI_STRING *
return STATUS_NO_MEMORY; return STATUS_NO_MEMORY;
strcpy( unix_name->Buffer, "." ); strcpy( unix_name->Buffer, "." );
if ((status = server_get_unix_fd( attr->RootDirectory, 0, &root_fd, &needs_close, &type, NULL ))) if ((status = unix_funcs->server_get_unix_fd( attr->RootDirectory, 0, &root_fd, &needs_close, &type, NULL )))
goto done; goto done;
if (type != FD_TYPE_DIR) if (type != FD_TYPE_DIR)
@ -2638,7 +2638,7 @@ NTSTATUS nt_to_unix_file_name_attr( const OBJECT_ATTRIBUTES *attr, ANSI_STRING *
return STATUS_NO_MEMORY; return STATUS_NO_MEMORY;
unix_name[0] = '.'; unix_name[0] = '.';
if (!(status = server_get_unix_fd( attr->RootDirectory, 0, &root_fd, &needs_close, &type, NULL ))) if (!(status = unix_funcs->server_get_unix_fd( attr->RootDirectory, 0, &root_fd, &needs_close, &type, NULL )))
{ {
if (type != FD_TYPE_DIR) if (type != FD_TYPE_DIR)
{ {
@ -2867,7 +2867,7 @@ NTSTATUS DIR_unmount_device( HANDLE handle )
NTSTATUS status; NTSTATUS status;
int unix_fd, needs_close; int unix_fd, needs_close;
if (!(status = server_get_unix_fd( handle, 0, &unix_fd, &needs_close, NULL, NULL ))) if (!(status = unix_funcs->server_get_unix_fd( handle, 0, &unix_fd, &needs_close, NULL, NULL )))
{ {
struct stat st; struct stat st;
char *mount_point = NULL; char *mount_point = NULL;
@ -2949,7 +2949,7 @@ NTSTATUS DIR_get_unix_cwd( char **cwd )
if (status != STATUS_SUCCESS) goto done; if (status != STATUS_SUCCESS) goto done;
} }
if ((status = server_get_unix_fd( handle, 0, &unix_fd, &needs_close, NULL, NULL )) == STATUS_SUCCESS) if ((status = unix_funcs->server_get_unix_fd( handle, 0, &unix_fd, &needs_close, NULL, NULL )) == STATUS_SUCCESS)
{ {
RtlEnterCriticalSection( &dir_section ); RtlEnterCriticalSection( &dir_section );

View File

@ -542,8 +542,8 @@ static NTSTATUS FILE_AsyncReadService( void *user, IO_STATUS_BLOCK *iosb, NTSTAT
{ {
case STATUS_ALERTED: /* got some new data */ case STATUS_ALERTED: /* got some new data */
/* check to see if the data is ready (non-blocking) */ /* check to see if the data is ready (non-blocking) */
if ((status = server_get_unix_fd( fileio->io.handle, FILE_READ_DATA, &fd, if ((status = unix_funcs->server_get_unix_fd( fileio->io.handle, FILE_READ_DATA, &fd,
&needs_close, NULL, NULL ))) &needs_close, NULL, NULL )))
break; break;
result = virtual_locked_read(fd, &fileio->buffer[fileio->already], fileio->count-fileio->already); result = virtual_locked_read(fd, &fileio->buffer[fileio->already], fileio->count-fileio->already);
@ -862,8 +862,8 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
if (!io_status) return STATUS_ACCESS_VIOLATION; if (!io_status) return STATUS_ACCESS_VIOLATION;
status = server_get_unix_fd( hFile, FILE_READ_DATA, &unix_handle, status = unix_funcs->server_get_unix_fd( hFile, FILE_READ_DATA, &unix_handle,
&needs_close, &type, &options ); &needs_close, &type, &options );
if (status && status != STATUS_BAD_DEVICE_TYPE) return status; if (status && status != STATUS_BAD_DEVICE_TYPE) return status;
if (!virtual_check_buffer_for_write( buffer, length )) return STATUS_ACCESS_VIOLATION; if (!virtual_check_buffer_for_write( buffer, length )) return STATUS_ACCESS_VIOLATION;
@ -1062,8 +1062,8 @@ NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap
if (!io_status) return STATUS_ACCESS_VIOLATION; if (!io_status) return STATUS_ACCESS_VIOLATION;
status = server_get_unix_fd( file, FILE_READ_DATA, &unix_handle, status = unix_funcs->server_get_unix_fd( file, FILE_READ_DATA, &unix_handle,
&needs_close, &type, &options ); &needs_close, &type, &options );
if (status) return status; if (status) return status;
if ((type != FD_TYPE_FILE) || if ((type != FD_TYPE_FILE) ||
@ -1137,8 +1137,8 @@ static NTSTATUS FILE_AsyncWriteService( void *user, IO_STATUS_BLOCK *iosb, NTSTA
{ {
case STATUS_ALERTED: case STATUS_ALERTED:
/* write some data (non-blocking) */ /* write some data (non-blocking) */
if ((status = server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd, if ((status = unix_funcs->server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd,
&needs_close, &type, NULL ))) &needs_close, &type, NULL )))
break; break;
if (!fileio->count && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_SOCKET)) if (!fileio->count && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_SOCKET))
@ -1231,12 +1231,12 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
if (!io_status) return STATUS_ACCESS_VIOLATION; if (!io_status) return STATUS_ACCESS_VIOLATION;
status = server_get_unix_fd( hFile, FILE_WRITE_DATA, &unix_handle, status = unix_funcs->server_get_unix_fd( hFile, FILE_WRITE_DATA, &unix_handle,
&needs_close, &type, &options ); &needs_close, &type, &options );
if (status == STATUS_ACCESS_DENIED) if (status == STATUS_ACCESS_DENIED)
{ {
status = server_get_unix_fd( hFile, FILE_APPEND_DATA, &unix_handle, status = unix_funcs->server_get_unix_fd( hFile, FILE_APPEND_DATA, &unix_handle,
&needs_close, &type, &options ); &needs_close, &type, &options );
append_write = TRUE; append_write = TRUE;
} }
if (status && status != STATUS_BAD_DEVICE_TYPE) return status; if (status && status != STATUS_BAD_DEVICE_TYPE) return status;
@ -1458,8 +1458,8 @@ NTSTATUS WINAPI NtWriteFileGather( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap
if (length % page_size) return STATUS_INVALID_PARAMETER; if (length % page_size) return STATUS_INVALID_PARAMETER;
if (!io_status) return STATUS_ACCESS_VIOLATION; if (!io_status) return STATUS_ACCESS_VIOLATION;
status = server_get_unix_fd( file, FILE_WRITE_DATA, &unix_handle, status = unix_funcs->server_get_unix_fd( file, FILE_WRITE_DATA, &unix_handle,
&needs_close, &type, &options ); &needs_close, &type, &options );
if (status) return status; if (status) return status;
if ((type != FD_TYPE_FILE) || if ((type != FD_TYPE_FILE) ||
@ -2459,7 +2459,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
if (len < info_sizes[class]) if (len < info_sizes[class])
return io->u.Status = STATUS_INFO_LENGTH_MISMATCH; return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
if ((io->u.Status = server_get_unix_fd( hFile, 0, &fd, &needs_close, NULL, &options ))) if ((io->u.Status = unix_funcs->server_get_unix_fd( hFile, 0, &fd, &needs_close, NULL, &options )))
{ {
if (io->u.Status != STATUS_BAD_DEVICE_TYPE) return io->u.Status; if (io->u.Status != STATUS_BAD_DEVICE_TYPE) return io->u.Status;
return server_get_file_info( hFile, io, ptr, len, class ); return server_get_file_info( hFile, io, ptr, len, class );
@ -2561,7 +2561,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
if (size > 0x10000) size = 0x10000; if (size > 0x10000) size = 0x10000;
if ((tmpbuf = RtlAllocateHeap( GetProcessHeap(), 0, size ))) if ((tmpbuf = RtlAllocateHeap( GetProcessHeap(), 0, size )))
{ {
if (!server_get_unix_fd( hFile, FILE_READ_DATA, &fd, &needs_close, NULL, NULL )) if (!unix_funcs->server_get_unix_fd( hFile, FILE_READ_DATA, &fd, &needs_close, NULL, NULL ))
{ {
int res = recv( fd, tmpbuf, size, MSG_PEEK ); int res = recv( fd, tmpbuf, size, MSG_PEEK );
info->MessagesAvailable = (res > 0); info->MessagesAvailable = (res > 0);
@ -2693,7 +2693,7 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
const FILE_BASIC_INFORMATION *info = ptr; const FILE_BASIC_INFORMATION *info = ptr;
LARGE_INTEGER mtime, atime; LARGE_INTEGER mtime, atime;
if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))) if ((io->u.Status = unix_funcs->server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
return io->u.Status; return io->u.Status;
mtime.QuadPart = info->LastWriteTime.QuadPart == -1 ? 0 : info->LastWriteTime.QuadPart; mtime.QuadPart = info->LastWriteTime.QuadPart == -1 ? 0 : info->LastWriteTime.QuadPart;
@ -2733,7 +2733,7 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
{ {
const FILE_POSITION_INFORMATION *info = ptr; const FILE_POSITION_INFORMATION *info = ptr;
if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))) if ((io->u.Status = unix_funcs->server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
return io->u.Status; return io->u.Status;
if (lseek( fd, info->CurrentByteOffset.QuadPart, SEEK_SET ) == (off_t)-1) if (lseek( fd, info->CurrentByteOffset.QuadPart, SEEK_SET ) == (off_t)-1)
@ -2750,7 +2750,7 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
struct stat st; struct stat st;
const FILE_END_OF_FILE_INFORMATION *info = ptr; const FILE_END_OF_FILE_INFORMATION *info = ptr;
if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))) if ((io->u.Status = unix_funcs->server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
return io->u.Status; return io->u.Status;
/* first try normal truncate */ /* first try normal truncate */
@ -2869,7 +2869,7 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
struct stat st; struct stat st;
const FILE_VALID_DATA_LENGTH_INFORMATION *info = ptr; const FILE_VALID_DATA_LENGTH_INFORMATION *info = ptr;
if ((io->u.Status = server_get_unix_fd( handle, FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))) if ((io->u.Status = unix_funcs->server_get_unix_fd( handle, FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL )))
return io->u.Status; return io->u.Status;
if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus(); if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
@ -3269,7 +3269,7 @@ NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, PIO_STATUS_BLOCK io
int fd, needs_close; int fd, needs_close;
struct stat st; struct stat st;
io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ); io->u.Status = unix_funcs->server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL );
if (io->u.Status == STATUS_BAD_DEVICE_TYPE) if (io->u.Status == STATUS_BAD_DEVICE_TYPE)
{ {
SERVER_START_REQ( get_volume_info ) SERVER_START_REQ( get_volume_info )
@ -3577,9 +3577,9 @@ NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK *io )
if (!io || !virtual_check_buffer_for_write( io, sizeof(*io) )) return STATUS_ACCESS_VIOLATION; if (!io || !virtual_check_buffer_for_write( io, sizeof(*io) )) return STATUS_ACCESS_VIOLATION;
ret = server_get_unix_fd( hFile, FILE_WRITE_DATA, &fd, &needs_close, &type, NULL ); ret = unix_funcs->server_get_unix_fd( hFile, FILE_WRITE_DATA, &fd, &needs_close, &type, NULL );
if (ret == STATUS_ACCESS_DENIED) if (ret == STATUS_ACCESS_DENIED)
ret = server_get_unix_fd( hFile, FILE_APPEND_DATA, &fd, &needs_close, &type, NULL ); ret = unix_funcs->server_get_unix_fd( hFile, FILE_APPEND_DATA, &fd, &needs_close, &type, NULL );
if (!ret && type == FD_TYPE_SERIAL) if (!ret && type == FD_TYPE_SERIAL)
{ {

View File

@ -2340,7 +2340,7 @@ static NTSTATUS open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm,
return STATUS_DLL_NOT_FOUND; return STATUS_DLL_NOT_FOUND;
} }
if (!server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )) if (!unix_funcs->server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))
{ {
fstat( fd, st ); fstat( fd, st );
if (needs_close) close( fd ); if (needs_close) close( fd );

View File

@ -127,9 +127,6 @@ extern unsigned int server_select( const select_op_t *select_op, data_size_t siz
extern unsigned int server_wait( const select_op_t *select_op, data_size_t size, extern unsigned int server_wait( const select_op_t *select_op, data_size_t size,
UINT flags, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; UINT flags, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN;
extern unsigned int server_queue_process_apc( HANDLE process, const apc_call_t *call, apc_result_t *result ) DECLSPEC_HIDDEN; extern unsigned int server_queue_process_apc( HANDLE process, const apc_call_t *call, apc_result_t *result ) DECLSPEC_HIDDEN;
extern int server_remove_fd_from_cache( HANDLE handle ) DECLSPEC_HIDDEN;
extern int server_get_unix_fd( HANDLE handle, unsigned int access, int *unix_fd,
int *needs_close, enum server_fd_type *type, unsigned int *options ) DECLSPEC_HIDDEN;
extern NTSTATUS alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct object_attributes **ret, extern NTSTATUS alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct object_attributes **ret,
data_size_t *ret_len ) DECLSPEC_HIDDEN; data_size_t *ret_len ) DECLSPEC_HIDDEN;
extern NTSTATUS validate_open_object_attributes( const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; extern NTSTATUS validate_open_object_attributes( const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN;

View File

@ -366,7 +366,7 @@ NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source,
if (dest) *dest = wine_server_ptr_handle( reply->handle ); if (dest) *dest = wine_server_ptr_handle( reply->handle );
if (reply->closed && reply->self) if (reply->closed && reply->self)
{ {
int fd = server_remove_fd_from_cache( source ); int fd = unix_funcs->server_remove_fd_from_cache( source );
if (fd != -1) close( fd ); if (fd != -1) close( fd );
} }
} }
@ -385,7 +385,7 @@ static LONG WINAPI invalid_handle_exception_handler( EXCEPTION_POINTERS *eptr )
NTSTATUS close_handle( HANDLE handle ) NTSTATUS close_handle( HANDLE handle )
{ {
NTSTATUS ret; NTSTATUS ret;
int fd = server_remove_fd_from_cache( handle ); int fd = unix_funcs->server_remove_fd_from_cache( handle );
SERVER_START_REQ( close_handle ) SERVER_START_REQ( close_handle )
{ {

View File

@ -951,7 +951,7 @@ static DWORD CALLBACK wait_for_event(LPVOID arg)
async_commio *commio = arg; async_commio *commio = arg;
int fd, needs_close; int fd, needs_close;
if (!server_get_unix_fd( commio->hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL )) if (!unix_funcs->server_get_unix_fd( commio->hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))
{ {
serial_irq_info new_irq_info; serial_irq_info new_irq_info;
DWORD new_mstat, dummy, cookie; DWORD new_mstat, dummy, cookie;
@ -1141,7 +1141,7 @@ static inline NTSTATUS io_control(HANDLE hDevice,
piosb->Information = 0; piosb->Information = 0;
if ((status = server_get_unix_fd( hDevice, access, &fd, &needs_close, &type, NULL ))) if ((status = unix_funcs->server_get_unix_fd( hDevice, access, &fd, &needs_close, &type, NULL )))
goto error; goto error;
if (type != FD_TYPE_SERIAL) if (type != FD_TYPE_SERIAL)
{ {

View File

@ -93,8 +93,6 @@
#include "ntdll_misc.h" #include "ntdll_misc.h"
#include "ddk/wdm.h" #include "ddk/wdm.h"
WINE_DEFAULT_DEBUG_CHANNEL(server);
/* Some versions of glibc don't define this */ /* Some versions of glibc don't define this */
#ifndef SCM_RIGHTS #ifndef SCM_RIGHTS
#define SCM_RIGHTS 1 #define SCM_RIGHTS 1
@ -118,27 +116,6 @@ timeout_t server_start_time = 0; /* time of server startup */
sigset_t server_block_set; /* signals to block during server calls */ sigset_t server_block_set; /* signals to block during server calls */
static RTL_CRITICAL_SECTION fd_cache_section;
static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &fd_cache_section,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": fd_cache_section") }
};
static RTL_CRITICAL_SECTION fd_cache_section = { &critsect_debug, -1, 0, 0, 0, 0 };
/* atomically exchange a 64-bit value */
static inline LONG64 interlocked_xchg64( LONG64 *dest, LONG64 val )
{
#ifdef _WIN64
return (LONG64)InterlockedExchangePointer( (void **)dest, (void *)val );
#else
LONG64 tmp = *dest;
while (InterlockedCompareExchange64( dest, val, tmp ) != tmp) tmp = *dest;
return tmp;
#endif
}
/*********************************************************************** /***********************************************************************
* server_protocol_error * server_protocol_error
*/ */
@ -750,182 +727,6 @@ void CDECL wine_server_send_fd( int fd )
} }
/***********************************************************************/
/* fd cache support */
union fd_cache_entry
{
LONG64 data;
struct
{
int fd;
enum server_fd_type type : 5;
unsigned int access : 3;
unsigned int options : 24;
} s;
};
C_ASSERT( sizeof(union fd_cache_entry) == sizeof(LONG64) );
#define FD_CACHE_BLOCK_SIZE (65536 / sizeof(union fd_cache_entry))
#define FD_CACHE_ENTRIES 128
static union fd_cache_entry *fd_cache[FD_CACHE_ENTRIES];
static union fd_cache_entry fd_cache_initial_block[FD_CACHE_BLOCK_SIZE];
static inline unsigned int handle_to_index( HANDLE handle, unsigned int *entry )
{
unsigned int idx = (wine_server_obj_handle(handle) >> 2) - 1;
*entry = idx / FD_CACHE_BLOCK_SIZE;
return idx % FD_CACHE_BLOCK_SIZE;
}
/***********************************************************************
* add_fd_to_cache
*
* Caller must hold fd_cache_section.
*/
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 );
union fd_cache_entry cache;
if (entry >= FD_CACHE_ENTRIES)
{
FIXME( "too many allocated handles, not caching %p\n", handle );
return FALSE;
}
if (!fd_cache[entry]) /* do we need to allocate a new block of entries? */
{
if (!entry) fd_cache[0] = fd_cache_initial_block;
else
{
void *ptr = wine_anon_mmap( NULL, FD_CACHE_BLOCK_SIZE * sizeof(union fd_cache_entry),
PROT_READ | PROT_WRITE, 0 );
if (ptr == MAP_FAILED) return FALSE;
fd_cache[entry] = ptr;
}
}
/* store fd+1 so that 0 can be used as the unset value */
cache.s.fd = fd + 1;
cache.s.type = type;
cache.s.access = access;
cache.s.options = options;
cache.data = interlocked_xchg64( &fd_cache[entry][idx].data, cache.data );
assert( !cache.s.fd );
return TRUE;
}
/***********************************************************************
* get_cached_fd
*/
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 );
union fd_cache_entry cache;
if (entry >= FD_CACHE_ENTRIES || !fd_cache[entry]) return STATUS_INVALID_HANDLE;
cache.data = InterlockedCompareExchange64( &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;
}
/***********************************************************************
* server_remove_fd_from_cache
*/
int server_remove_fd_from_cache( HANDLE handle )
{
unsigned int entry, idx = handle_to_index( handle, &entry );
int fd = -1;
if (entry < FD_CACHE_ENTRIES && fd_cache[entry])
{
union fd_cache_entry cache;
cache.data = interlocked_xchg64( &fd_cache[entry][idx].data, 0 );
if (cache.s.type != FD_TYPE_INVALID) fd = cache.s.fd - 1;
}
return fd;
}
/***********************************************************************
* server_get_unix_fd
*
* The returned unix_fd should be closed iff needs_close is non-zero.
*/
int server_get_unix_fd( HANDLE 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, fd = -1;
unsigned int access = 0;
*unix_fd = -1;
*needs_close = 0;
wanted_access &= FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA;
ret = get_cached_fd( handle, &fd, type, &access, options );
if (ret != STATUS_INVALID_HANDLE) goto done;
server_enter_uninterrupted_section( &fd_cache_section, &sigset );
ret = get_cached_fd( handle, &fd, type, &access, options );
if (ret == STATUS_INVALID_HANDLE)
{
SERVER_START_REQ( get_handle_fd )
{
req->handle = wine_server_obj_handle( handle );
if (!(ret = wine_server_call( req )))
{
if (type) *type = reply->type;
if (options) *options = reply->options;
access = reply->access;
if ((fd = unix_funcs->receive_fd( &fd_handle )) != -1)
{
assert( wine_server_ptr_handle(fd_handle) == handle );
*needs_close = (!reply->cacheable ||
!add_fd_to_cache( handle, fd, reply->type,
reply->access, reply->options ));
}
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;
}
server_leave_uninterrupted_section( &fd_cache_section, &sigset );
done:
if (!ret && ((access & wanted_access) != wanted_access))
{
ret = STATUS_ACCESS_DENIED;
if (*needs_close) close( fd );
}
if (!ret) *unix_fd = fd;
return ret;
}
/*********************************************************************** /***********************************************************************
* wine_server_fd_to_handle (NTDLL.@) * wine_server_fd_to_handle (NTDLL.@)
* *
@ -942,20 +743,7 @@ done:
*/ */
int CDECL wine_server_fd_to_handle( int fd, unsigned int access, unsigned int attributes, HANDLE *handle ) int CDECL wine_server_fd_to_handle( int fd, unsigned int access, unsigned int attributes, HANDLE *handle )
{ {
int ret; return unix_funcs->server_fd_to_handle( fd, access, attributes, handle );
*handle = 0;
wine_server_send_fd( fd );
SERVER_START_REQ( alloc_file_handle )
{
req->access = access;
req->attributes = attributes;
req->fd = fd;
if (!(ret = wine_server_call( req ))) *handle = wine_server_ptr_handle( reply->handle );
}
SERVER_END_REQ;
return ret;
} }
@ -974,15 +762,9 @@ int CDECL wine_server_fd_to_handle( int fd, unsigned int access, unsigned int at
* NTSTATUS code * NTSTATUS code
*/ */
int CDECL wine_server_handle_to_fd( HANDLE handle, unsigned int access, int *unix_fd, int CDECL wine_server_handle_to_fd( HANDLE handle, unsigned int access, int *unix_fd,
unsigned int *options ) unsigned int *options )
{ {
int needs_close, ret = server_get_unix_fd( handle, access, unix_fd, &needs_close, NULL, options ); return unix_funcs->server_handle_to_fd( handle, access, unix_fd, options );
if (!ret && !needs_close)
{
if ((*unix_fd = dup(*unix_fd)) == -1) ret = FILE_GetNtStatus();
}
return ret;
} }
@ -1000,7 +782,7 @@ int CDECL wine_server_handle_to_fd( HANDLE handle, unsigned int access, int *uni
*/ */
void CDECL wine_server_release_fd( HANDLE handle, int unix_fd ) void CDECL wine_server_release_fd( HANDLE handle, int unix_fd )
{ {
close( unix_fd ); unix_funcs->server_release_fd( handle, unix_fd );
} }

View File

@ -530,7 +530,7 @@ NTSTATUS TAPE_DeviceIoControl( HANDLE device, HANDLE event,
io_status->Information = 0; io_status->Information = 0;
if ((status = server_get_unix_fd( device, 0, &fd, &needs_close, NULL, NULL ))) if ((status = unix_funcs->server_get_unix_fd( device, 0, &fd, &needs_close, NULL, NULL )))
goto error; goto error;
switch (io_control) switch (io_control)

View File

@ -199,7 +199,7 @@ void map_user_shared_data(void)
MESSAGE( "wine: failed to open the USD section: %08x\n", status ); MESSAGE( "wine: failed to open the USD section: %08x\n", status );
exit(1); exit(1);
} }
if ((res = server_get_unix_fd( section, 0, &fd, &needs_close, NULL, NULL )) || if ((res = unix_funcs->server_get_unix_fd( section, 0, &fd, &needs_close, NULL, NULL )) ||
(user_shared_data != mmap( user_shared_data, sizeof(*user_shared_data), (user_shared_data != mmap( user_shared_data, sizeof(*user_shared_data),
PROT_READ, MAP_SHARED | MAP_FIXED, fd, 0 ))) PROT_READ, MAP_SHARED | MAP_FIXED, fd, 0 )))
{ {

View File

@ -997,7 +997,11 @@ static struct unix_funcs unix_funcs =
mmap_is_in_reserved_area, mmap_is_in_reserved_area,
mmap_enum_reserved_areas, mmap_enum_reserved_areas,
server_send_fd, server_send_fd,
receive_fd, server_remove_fd_from_cache,
server_get_unix_fd,
server_fd_to_handle,
server_handle_to_fd,
server_release_fd,
server_pipe, server_pipe,
server_init_process, server_init_process,
server_init_process_done, server_init_process_done,

View File

@ -91,7 +91,7 @@
#include "unix_private.h" #include "unix_private.h"
#include "ddk/wdm.h" #include "ddk/wdm.h"
WINE_DECLARE_DEBUG_CHANNEL(server); WINE_DEFAULT_DEBUG_CHANNEL(server);
#ifndef MSG_CMSG_CLOEXEC #ifndef MSG_CMSG_CLOEXEC
#define MSG_CMSG_CLOEXEC 0 #define MSG_CMSG_CLOEXEC 0
@ -127,6 +127,27 @@ sigset_t server_block_set; /* signals to block during server calls */
static int fd_socket = -1; /* socket to exchange file descriptors with the server */ static int fd_socket = -1; /* socket to exchange file descriptors with the server */
static pid_t server_pid; static pid_t server_pid;
static RTL_CRITICAL_SECTION fd_cache_section;
static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &fd_cache_section,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": fd_cache_section") }
};
static RTL_CRITICAL_SECTION fd_cache_section = { &critsect_debug, -1, 0, 0, 0, 0 };
/* atomically exchange a 64-bit value */
static inline LONG64 interlocked_xchg64( LONG64 *dest, LONG64 val )
{
#ifdef _WIN64
return (LONG64)InterlockedExchangePointer( (void **)dest, (void *)val );
#else
LONG64 tmp = *dest;
while (InterlockedCompareExchange64( dest, val, tmp ) != tmp) tmp = *dest;
return tmp;
#endif
}
#ifdef __GNUC__ #ifdef __GNUC__
static void fatal_error( const char *err, ... ) __attribute__((noreturn, format(printf,1,2))); static void fatal_error( const char *err, ... ) __attribute__((noreturn, format(printf,1,2)));
static void fatal_perror( const char *err, ... ) __attribute__((noreturn, format(printf,1,2))); static void fatal_perror( const char *err, ... ) __attribute__((noreturn, format(printf,1,2)));
@ -184,6 +205,26 @@ static DECLSPEC_NORETURN void server_protocol_perror( const char *err )
} }
/***********************************************************************
* server_enter_uninterrupted_section
*/
void server_enter_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset )
{
pthread_sigmask( SIG_BLOCK, &server_block_set, sigset );
RtlEnterCriticalSection( cs );
}
/***********************************************************************
* server_leave_uninterrupted_section
*/
void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset )
{
RtlLeaveCriticalSection( cs );
pthread_sigmask( SIG_SETMASK, sigset, NULL );
}
/*********************************************************************** /***********************************************************************
* server_send_fd * server_send_fd
* *
@ -240,7 +281,7 @@ void CDECL server_send_fd( int fd )
* *
* Receive a file descriptor passed from the server. * Receive a file descriptor passed from the server.
*/ */
int CDECL receive_fd( obj_handle_t *handle ) static int receive_fd( obj_handle_t *handle )
{ {
struct iovec vec; struct iovec vec;
struct msghdr msghdr; struct msghdr msghdr;
@ -295,6 +336,232 @@ int CDECL receive_fd( obj_handle_t *handle )
} }
/***********************************************************************/
/* fd cache support */
union fd_cache_entry
{
LONG64 data;
struct
{
int fd;
enum server_fd_type type : 5;
unsigned int access : 3;
unsigned int options : 24;
} s;
};
C_ASSERT( sizeof(union fd_cache_entry) == sizeof(LONG64) );
#define FD_CACHE_BLOCK_SIZE (65536 / sizeof(union fd_cache_entry))
#define FD_CACHE_ENTRIES 128
static union fd_cache_entry *fd_cache[FD_CACHE_ENTRIES];
static union fd_cache_entry fd_cache_initial_block[FD_CACHE_BLOCK_SIZE];
static inline unsigned int handle_to_index( HANDLE handle, unsigned int *entry )
{
unsigned int idx = (wine_server_obj_handle(handle) >> 2) - 1;
*entry = idx / FD_CACHE_BLOCK_SIZE;
return idx % FD_CACHE_BLOCK_SIZE;
}
/***********************************************************************
* add_fd_to_cache
*
* Caller must hold fd_cache_section.
*/
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 );
union fd_cache_entry cache;
if (entry >= FD_CACHE_ENTRIES)
{
FIXME( "too many allocated handles, not caching %p\n", handle );
return FALSE;
}
if (!fd_cache[entry]) /* do we need to allocate a new block of entries? */
{
if (!entry) fd_cache[0] = fd_cache_initial_block;
else
{
void *ptr = wine_anon_mmap( NULL, FD_CACHE_BLOCK_SIZE * sizeof(union fd_cache_entry),
PROT_READ | PROT_WRITE, 0 );
if (ptr == MAP_FAILED) return FALSE;
fd_cache[entry] = ptr;
}
}
/* store fd+1 so that 0 can be used as the unset value */
cache.s.fd = fd + 1;
cache.s.type = type;
cache.s.access = access;
cache.s.options = options;
cache.data = interlocked_xchg64( &fd_cache[entry][idx].data, cache.data );
assert( !cache.s.fd );
return TRUE;
}
/***********************************************************************
* get_cached_fd
*/
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 );
union fd_cache_entry cache;
if (entry >= FD_CACHE_ENTRIES || !fd_cache[entry]) return STATUS_INVALID_HANDLE;
cache.data = InterlockedCompareExchange64( &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;
}
/***********************************************************************
* server_remove_fd_from_cache
*/
int CDECL server_remove_fd_from_cache( HANDLE handle )
{
unsigned int entry, idx = handle_to_index( handle, &entry );
int fd = -1;
if (entry < FD_CACHE_ENTRIES && fd_cache[entry])
{
union fd_cache_entry cache;
cache.data = interlocked_xchg64( &fd_cache[entry][idx].data, 0 );
if (cache.s.type != FD_TYPE_INVALID) fd = cache.s.fd - 1;
}
return fd;
}
/***********************************************************************
* server_get_unix_fd
*
* The returned unix_fd should be closed iff needs_close is non-zero.
*/
int CDECL server_get_unix_fd( HANDLE 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, fd = -1;
unsigned int access = 0;
*unix_fd = -1;
*needs_close = 0;
wanted_access &= FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA;
ret = get_cached_fd( handle, &fd, type, &access, options );
if (ret != STATUS_INVALID_HANDLE) goto done;
server_enter_uninterrupted_section( &fd_cache_section, &sigset );
ret = get_cached_fd( handle, &fd, type, &access, options );
if (ret == STATUS_INVALID_HANDLE)
{
SERVER_START_REQ( get_handle_fd )
{
req->handle = wine_server_obj_handle( handle );
if (!(ret = wine_server_call( req )))
{
if (type) *type = reply->type;
if (options) *options = reply->options;
access = reply->access;
if ((fd = receive_fd( &fd_handle )) != -1)
{
assert( wine_server_ptr_handle(fd_handle) == handle );
*needs_close = (!reply->cacheable ||
!add_fd_to_cache( handle, fd, reply->type,
reply->access, reply->options ));
}
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;
}
server_leave_uninterrupted_section( &fd_cache_section, &sigset );
done:
if (!ret && ((access & wanted_access) != wanted_access))
{
ret = STATUS_ACCESS_DENIED;
if (*needs_close) close( fd );
}
if (!ret) *unix_fd = fd;
return ret;
}
/***********************************************************************
* server_fd_to_handle
*/
NTSTATUS CDECL server_fd_to_handle( int fd, unsigned int access, unsigned int attributes, HANDLE *handle )
{
NTSTATUS ret;
*handle = 0;
wine_server_send_fd( fd );
SERVER_START_REQ( alloc_file_handle )
{
req->access = access;
req->attributes = attributes;
req->fd = fd;
if (!(ret = wine_server_call( req ))) *handle = wine_server_ptr_handle( reply->handle );
}
SERVER_END_REQ;
return ret;
}
/***********************************************************************
* server_handle_to_fd
*
* Retrieve the file descriptor corresponding to a file handle.
*/
NTSTATUS CDECL server_handle_to_fd( HANDLE handle, unsigned int access, int *unix_fd,
unsigned int *options )
{
int needs_close;
NTSTATUS ret = server_get_unix_fd( handle, access, unix_fd, &needs_close, NULL, options );
if (!ret && !needs_close)
{
if ((*unix_fd = dup(*unix_fd)) == -1) ret = STATUS_TOO_MANY_OPENED_FILES;
}
return ret;
}
/***********************************************************************
* server_release_fd
*/
void CDECL server_release_fd( HANDLE handle, int unix_fd )
{
close( unix_fd );
}
/*********************************************************************** /***********************************************************************
* server_pipe * server_pipe
* *

View File

@ -61,7 +61,15 @@ extern void virtual_init(void) DECLSPEC_HIDDEN;
extern void CDECL dbg_init(void) DECLSPEC_HIDDEN; extern void CDECL dbg_init(void) DECLSPEC_HIDDEN;
extern void CDECL server_send_fd( int fd ) DECLSPEC_HIDDEN; extern void CDECL server_send_fd( int fd ) DECLSPEC_HIDDEN;
extern int CDECL receive_fd( obj_handle_t *handle ) DECLSPEC_HIDDEN; extern int CDECL server_remove_fd_from_cache( HANDLE handle ) DECLSPEC_HIDDEN;
extern int CDECL server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd,
int *needs_close, enum server_fd_type *type,
unsigned int *options ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL server_fd_to_handle( int fd, unsigned int access, unsigned int attributes,
HANDLE *handle ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL server_handle_to_fd( HANDLE handle, unsigned int access, int *unix_fd,
unsigned int *options ) DECLSPEC_HIDDEN;
extern void CDECL server_release_fd( HANDLE handle, int unix_fd ) DECLSPEC_HIDDEN;
extern int CDECL server_pipe( int fd[2] ) DECLSPEC_HIDDEN; extern int CDECL server_pipe( int fd[2] ) DECLSPEC_HIDDEN;
extern void CDECL server_init_process(void) DECLSPEC_HIDDEN; extern void CDECL server_init_process(void) DECLSPEC_HIDDEN;
extern void CDECL server_init_process_done(void) DECLSPEC_HIDDEN; extern void CDECL server_init_process_done(void) DECLSPEC_HIDDEN;

View File

@ -25,7 +25,7 @@
#include "wine/debug.h" #include "wine/debug.h"
/* increment this when you change the function table */ /* increment this when you change the function table */
#define NTDLL_UNIXLIB_VERSION 8 #define NTDLL_UNIXLIB_VERSION 9
struct unix_funcs struct unix_funcs
{ {
@ -52,7 +52,14 @@ struct unix_funcs
/* server functions */ /* server functions */
void (CDECL *server_send_fd)( int fd ); void (CDECL *server_send_fd)( int fd );
int (CDECL *receive_fd)( obj_handle_t *handle ); int (CDECL *server_remove_fd_from_cache)( HANDLE handle );
int (CDECL *server_get_unix_fd)( HANDLE handle, unsigned int wanted_access, int *unix_fd,
int *needs_close, enum server_fd_type *type, unsigned int *options );
NTSTATUS (CDECL *server_fd_to_handle)( int fd, unsigned int access, unsigned int attributes,
HANDLE *handle );
NTSTATUS (CDECL *server_handle_to_fd)( HANDLE handle, unsigned int access, int *unix_fd,
unsigned int *options );
void (CDECL *server_release_fd)( HANDLE handle, int unix_fd );
int (CDECL *server_pipe)( int fd[2] ); int (CDECL *server_pipe)( int fd[2] );
void (CDECL *server_init_process)(void); void (CDECL *server_init_process)(void);
void (CDECL *server_init_process_done)(void); void (CDECL *server_init_process_done)(void);

View File

@ -1815,7 +1815,7 @@ NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, unsigned short zer
SERVER_END_REQ; SERVER_END_REQ;
if (res) return res; if (res) return res;
if ((res = server_get_unix_fd( handle, 0, &unix_handle, &needs_close, NULL, NULL ))) goto done; if ((res = unix_funcs->server_get_unix_fd( handle, 0, &unix_handle, &needs_close, NULL, NULL ))) goto done;
if (sec_flags & SEC_IMAGE) if (sec_flags & SEC_IMAGE)
{ {
@ -1823,8 +1823,8 @@ NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, unsigned short zer
{ {
int shared_fd, shared_needs_close; int shared_fd, shared_needs_close;
if ((res = server_get_unix_fd( shared_file, FILE_READ_DATA|FILE_WRITE_DATA, if ((res = unix_funcs->server_get_unix_fd( shared_file, FILE_READ_DATA|FILE_WRITE_DATA,
&shared_fd, &shared_needs_close, NULL, NULL ))) goto done; &shared_fd, &shared_needs_close, NULL, NULL ))) goto done;
res = map_image( handle, access, unix_handle, alloc_type & MEM_TOP_DOWN, zero_bits_64, image_info, res = map_image( handle, access, unix_handle, alloc_type & MEM_TOP_DOWN, zero_bits_64, image_info,
shared_fd, needs_close, addr_ptr ); shared_fd, needs_close, addr_ptr );
if (shared_needs_close) close( shared_fd ); if (shared_needs_close) close( shared_fd );