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;
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 */
goto error;

View File

@ -1946,7 +1946,7 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH NtQueryDirectoryFile( HANDLE handle, HANDLE ev
}
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;
io->Information = 0;
@ -2436,7 +2436,7 @@ NTSTATUS file_id_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, ANSI_STRING *
return STATUS_NO_MEMORY;
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;
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;
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)
{
@ -2867,7 +2867,7 @@ NTSTATUS DIR_unmount_device( HANDLE handle )
NTSTATUS status;
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;
char *mount_point = NULL;
@ -2949,7 +2949,7 @@ NTSTATUS DIR_get_unix_cwd( char **cwd )
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 );

View File

@ -542,8 +542,8 @@ static NTSTATUS FILE_AsyncReadService( void *user, IO_STATUS_BLOCK *iosb, NTSTAT
{
case STATUS_ALERTED: /* got some new data */
/* check to see if the data is ready (non-blocking) */
if ((status = server_get_unix_fd( fileio->io.handle, FILE_READ_DATA, &fd,
&needs_close, NULL, NULL )))
if ((status = unix_funcs->server_get_unix_fd( fileio->io.handle, FILE_READ_DATA, &fd,
&needs_close, NULL, NULL )))
break;
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;
status = server_get_unix_fd( hFile, FILE_READ_DATA, &unix_handle,
&needs_close, &type, &options );
status = unix_funcs->server_get_unix_fd( hFile, FILE_READ_DATA, &unix_handle,
&needs_close, &type, &options );
if (status && status != STATUS_BAD_DEVICE_TYPE) return status;
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;
status = server_get_unix_fd( file, FILE_READ_DATA, &unix_handle,
&needs_close, &type, &options );
status = unix_funcs->server_get_unix_fd( file, FILE_READ_DATA, &unix_handle,
&needs_close, &type, &options );
if (status) return status;
if ((type != FD_TYPE_FILE) ||
@ -1137,8 +1137,8 @@ static NTSTATUS FILE_AsyncWriteService( void *user, IO_STATUS_BLOCK *iosb, NTSTA
{
case STATUS_ALERTED:
/* write some data (non-blocking) */
if ((status = server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd,
&needs_close, &type, NULL )))
if ((status = unix_funcs->server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd,
&needs_close, &type, NULL )))
break;
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;
status = server_get_unix_fd( hFile, FILE_WRITE_DATA, &unix_handle,
&needs_close, &type, &options );
status = unix_funcs->server_get_unix_fd( hFile, FILE_WRITE_DATA, &unix_handle,
&needs_close, &type, &options );
if (status == STATUS_ACCESS_DENIED)
{
status = server_get_unix_fd( hFile, FILE_APPEND_DATA, &unix_handle,
&needs_close, &type, &options );
status = unix_funcs->server_get_unix_fd( hFile, FILE_APPEND_DATA, &unix_handle,
&needs_close, &type, &options );
append_write = TRUE;
}
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 (!io_status) return STATUS_ACCESS_VIOLATION;
status = server_get_unix_fd( file, FILE_WRITE_DATA, &unix_handle,
&needs_close, &type, &options );
status = unix_funcs->server_get_unix_fd( file, FILE_WRITE_DATA, &unix_handle,
&needs_close, &type, &options );
if (status) return status;
if ((type != FD_TYPE_FILE) ||
@ -2459,7 +2459,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
if (len < info_sizes[class])
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;
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 ((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 );
info->MessagesAvailable = (res > 0);
@ -2693,7 +2693,7 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
const FILE_BASIC_INFORMATION *info = ptr;
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;
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;
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;
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;
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;
/* first try normal truncate */
@ -2869,7 +2869,7 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
struct stat st;
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;
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;
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)
{
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;
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)
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)
{

View File

@ -2340,7 +2340,7 @@ static NTSTATUS open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm,
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 );
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,
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 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,
data_size_t *ret_len ) 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 (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 );
}
}
@ -385,7 +385,7 @@ static LONG WINAPI invalid_handle_exception_handler( EXCEPTION_POINTERS *eptr )
NTSTATUS close_handle( HANDLE handle )
{
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 )
{

View File

@ -951,7 +951,7 @@ static DWORD CALLBACK wait_for_event(LPVOID arg)
async_commio *commio = arg;
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;
DWORD new_mstat, dummy, cookie;
@ -1141,7 +1141,7 @@ static inline NTSTATUS io_control(HANDLE hDevice,
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;
if (type != FD_TYPE_SERIAL)
{

View File

@ -93,8 +93,6 @@
#include "ntdll_misc.h"
#include "ddk/wdm.h"
WINE_DEFAULT_DEBUG_CHANNEL(server);
/* Some versions of glibc don't define this */
#ifndef SCM_RIGHTS
#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 */
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
*/
@ -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.@)
*
@ -942,20 +743,7 @@ done:
*/
int CDECL wine_server_fd_to_handle( int fd, unsigned int access, unsigned int attributes, HANDLE *handle )
{
int 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;
return unix_funcs->server_fd_to_handle( fd, access, attributes, handle );
}
@ -974,15 +762,9 @@ int CDECL wine_server_fd_to_handle( int fd, unsigned int access, unsigned int at
* NTSTATUS code
*/
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 );
if (!ret && !needs_close)
{
if ((*unix_fd = dup(*unix_fd)) == -1) ret = FILE_GetNtStatus();
}
return ret;
return unix_funcs->server_handle_to_fd( handle, access, unix_fd, options );
}
@ -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 )
{
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;
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;
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 );
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),
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_enum_reserved_areas,
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_init_process,
server_init_process_done,

View File

@ -91,7 +91,7 @@
#include "unix_private.h"
#include "ddk/wdm.h"
WINE_DECLARE_DEBUG_CHANNEL(server);
WINE_DEFAULT_DEBUG_CHANNEL(server);
#ifndef MSG_CMSG_CLOEXEC
#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 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__
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)));
@ -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
*
@ -240,7 +281,7 @@ void CDECL server_send_fd( int fd )
*
* 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 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
*

View File

@ -61,7 +61,15 @@ extern void virtual_init(void) DECLSPEC_HIDDEN;
extern void CDECL dbg_init(void) 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 void CDECL server_init_process(void) DECLSPEC_HIDDEN;
extern void CDECL server_init_process_done(void) DECLSPEC_HIDDEN;

View File

@ -25,7 +25,7 @@
#include "wine/debug.h"
/* increment this when you change the function table */
#define NTDLL_UNIXLIB_VERSION 8
#define NTDLL_UNIXLIB_VERSION 9
struct unix_funcs
{
@ -52,7 +52,14 @@ struct unix_funcs
/* server functions */
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] );
void (CDECL *server_init_process)(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;
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)
{
@ -1823,8 +1823,8 @@ NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, unsigned short zer
{
int shared_fd, shared_needs_close;
if ((res = server_get_unix_fd( shared_file, FILE_READ_DATA|FILE_WRITE_DATA,
&shared_fd, &shared_needs_close, NULL, NULL ))) goto done;
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;
res = map_image( handle, access, unix_handle, alloc_type & MEM_TOP_DOWN, zero_bits_64, image_info,
shared_fd, needs_close, addr_ptr );
if (shared_needs_close) close( shared_fd );