Export SYSDEPS_SwitchToThreadStack() functionality from libwine as
wine_switch_to_stack().
This commit is contained in:
parent
d4c1ebabdb
commit
ca3bfd8318
|
@ -115,7 +115,7 @@ void SYSDEPS_SetCurThread( TEB *teb )
|
||||||
inline static char *get_temp_stack(void)
|
inline static char *get_temp_stack(void)
|
||||||
{
|
{
|
||||||
unsigned int next = interlocked_xchg_add( &next_temp_stack, 1 );
|
unsigned int next = interlocked_xchg_add( &next_temp_stack, 1 );
|
||||||
return temp_stacks[next % NB_TEMP_STACKS];
|
return temp_stacks[next % NB_TEMP_STACKS] + TEMP_STACK_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -192,73 +192,6 @@ int SYSDEPS_SpawnThread( void (*func)(TEB *), TEB *teb )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* SYSDEPS_SwitchToThreadStack
|
|
||||||
*
|
|
||||||
* Switch to the stack specified in the current thread TEB
|
|
||||||
* and call the specified function.
|
|
||||||
*/
|
|
||||||
void DECLSPEC_NORETURN SYSDEPS_SwitchToThreadStack( void (*func)(void *), void *arg );
|
|
||||||
#ifdef __i386__
|
|
||||||
# ifdef __GNUC__
|
|
||||||
__ASM_GLOBAL_FUNC( SYSDEPS_SwitchToThreadStack,
|
|
||||||
"movl 4(%esp),%ecx\n\t" /* func */
|
|
||||||
"movl 8(%esp),%edx\n\t" /* arg */
|
|
||||||
".byte 0x64\n\tmovl 0x04,%esp\n\t" /* teb->Tib.StackBase */
|
|
||||||
"pushl %edx\n\t"
|
|
||||||
"xorl %ebp,%ebp\n\t"
|
|
||||||
"call *%ecx\n\t"
|
|
||||||
"int $3" /* we never return here */ );
|
|
||||||
# elif defined(_MSC_VER)
|
|
||||||
__declspec(naked) void SYSDEPS_SwitchToThreadStack( void (*func)(void *), void *arg )
|
|
||||||
{
|
|
||||||
__asm mov ecx, 4[esp];
|
|
||||||
__asm mov edx, 8[esp];
|
|
||||||
__asm mov fs:[0x04], esp;
|
|
||||||
__asm push edx;
|
|
||||||
__asm xor ebp, ebp;
|
|
||||||
__asm call [ecx];
|
|
||||||
__asm int 3;
|
|
||||||
}
|
|
||||||
# endif /* defined(__GNUC__) || defined(_MSC_VER) */
|
|
||||||
#elif defined(__sparc__) && defined(__GNUC__)
|
|
||||||
__ASM_GLOBAL_FUNC( SYSDEPS_SwitchToThreadStack,
|
|
||||||
"mov %o0, %l0\n\t" /* store first argument */
|
|
||||||
"call " __ASM_NAME("NtCurrentTeb") ", 0\n\t"
|
|
||||||
"mov %o1, %l1\n\t" /* delay slot: store second argument */
|
|
||||||
"ld [%o0+4], %sp\n\t" /* teb->Tib.StackBase */
|
|
||||||
"call %l0, 0\n\t" /* call func */
|
|
||||||
"mov %l1, %o0\n\t" /* delay slot: arg for func */
|
|
||||||
"ta 0x01\n\t"); /* breakpoint - we never get here */
|
|
||||||
#elif defined(__powerpc__) && defined(__APPLE__)
|
|
||||||
/* Darwin SYSDEPS_SwitchToThreadStack
|
|
||||||
Function Pointer to call is on r3, Args to pass on r4 and stack on r1 */
|
|
||||||
__ASM_GLOBAL_FUNC( SYSDEPS_SwitchToThreadStack,
|
|
||||||
"stw r1, 0x4(r13)\n\t" /* teb->Tib.StackBase */
|
|
||||||
"mr r12,r3\n\t"
|
|
||||||
"mtctr r12\n\t" /* func->ctr */
|
|
||||||
"mr r3,r4\n\t" /* args->function param 1 (r3) */
|
|
||||||
"bctr\n\t" /* call ctr */
|
|
||||||
"b _SYSDEPS_SwitchToThreadStack+24\n\t"); /* loop */
|
|
||||||
#elif defined(__powerpc__) && defined(__GNUC__)
|
|
||||||
/* Linux SYSDEPS_SwitchToThreadStack
|
|
||||||
Function Pointer to call is on r3, Args to pass on r4 and stack on r1 */
|
|
||||||
__ASM_GLOBAL_FUNC( SYSDEPS_SwitchToThreadStack,
|
|
||||||
"stw 1, 0x4(13)\n\t" /* teb->Tib.StackBase */
|
|
||||||
"mr 12,3\n\t"
|
|
||||||
"mtctr 12\n\t" /* func->ctr */
|
|
||||||
"mr 3,4\n\t" /* args->function param 1 (r3) */
|
|
||||||
"bctr\n\t" /* call ctr */
|
|
||||||
"b _SYSDEPS_SwitchToThreadStack+24\n\t"); /* loop */
|
|
||||||
#else /* !powerpc, !sparc, !i386 */
|
|
||||||
void SYSDEPS_SwitchToThreadStack( void (*func)(void *), void *arg )
|
|
||||||
{
|
|
||||||
func( arg );
|
|
||||||
while(1); /* avoid warning */
|
|
||||||
}
|
|
||||||
#endif /* !defined(__i386__) && !defined(__sparc__) */
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* SYSDEPS_ExitThread
|
* SYSDEPS_ExitThread
|
||||||
*
|
*
|
||||||
|
@ -285,7 +218,6 @@ void SYSDEPS_ExitThread( int status )
|
||||||
ptr = free_teb->DeallocationStack;
|
ptr = free_teb->DeallocationStack;
|
||||||
NtFreeVirtualMemory( GetCurrentProcess(), &ptr, &size, MEM_RELEASE );
|
NtFreeVirtualMemory( GetCurrentProcess(), &ptr, &size, MEM_RELEASE );
|
||||||
}
|
}
|
||||||
SIGNAL_Block();
|
|
||||||
SYSDEPS_AbortThread( status );
|
SYSDEPS_AbortThread( status );
|
||||||
#else
|
#else
|
||||||
struct thread_cleanup_info info;
|
struct thread_cleanup_info info;
|
||||||
|
@ -305,9 +237,7 @@ void SYSDEPS_ExitThread( int status )
|
||||||
close( teb->reply_fd );
|
close( teb->reply_fd );
|
||||||
close( teb->request_fd );
|
close( teb->request_fd );
|
||||||
SIGNAL_Reset();
|
SIGNAL_Reset();
|
||||||
teb->Tib.StackLimit = get_temp_stack();
|
wine_switch_to_stack( cleanup_thread, &info, get_temp_stack() );
|
||||||
teb->Tib.StackBase = (char *)teb->Tib.StackLimit + TEMP_STACK_SIZE;
|
|
||||||
SYSDEPS_SwitchToThreadStack( cleanup_thread, &info );
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,6 @@ extern void SYSDEPS_SetCurThread( TEB *teb );
|
||||||
extern int SYSDEPS_GetUnixTid(void);
|
extern int SYSDEPS_GetUnixTid(void);
|
||||||
extern void DECLSPEC_NORETURN SYSDEPS_ExitThread( int status );
|
extern void DECLSPEC_NORETURN SYSDEPS_ExitThread( int status );
|
||||||
extern void DECLSPEC_NORETURN SYSDEPS_AbortThread( int status );
|
extern void DECLSPEC_NORETURN SYSDEPS_AbortThread( int status );
|
||||||
extern void DECLSPEC_NORETURN SYSDEPS_SwitchToThreadStack( void (*func)(void *), void *arg );
|
|
||||||
|
|
||||||
/* signal handling */
|
/* signal handling */
|
||||||
extern BOOL SIGNAL_Init(void);
|
extern BOOL SIGNAL_Init(void);
|
||||||
|
|
|
@ -61,12 +61,9 @@ extern int wine_dbg_parse_options( const char *str );
|
||||||
|
|
||||||
/* portability */
|
/* portability */
|
||||||
|
|
||||||
|
extern void DECLSPEC_NORETURN wine_switch_to_stack( void (*func)(void *), void *arg, void *stack );
|
||||||
extern void *wine_anon_mmap( void *start, size_t size, int prot, int flags );
|
extern void *wine_anon_mmap( void *start, size_t size, int prot, int flags );
|
||||||
|
|
||||||
/* errno support */
|
|
||||||
extern int* (*wine_errno_location)(void);
|
|
||||||
extern int* (*wine_h_errno_location)(void);
|
|
||||||
|
|
||||||
/* LDT management */
|
/* LDT management */
|
||||||
|
|
||||||
extern void wine_ldt_init_locking( void (*lock_func)(void), void (*unlock_func)(void) );
|
extern void wine_ldt_init_locking( void (*lock_func)(void), void (*unlock_func)(void) );
|
||||||
|
|
|
@ -11,7 +11,8 @@ C_SRCS = \
|
||||||
config.c \
|
config.c \
|
||||||
debug.c \
|
debug.c \
|
||||||
ldt.c \
|
ldt.c \
|
||||||
loader.c
|
loader.c \
|
||||||
|
port.c
|
||||||
|
|
||||||
@MAKE_LIB_RULES@
|
@MAKE_LIB_RULES@
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,6 @@
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_STDINT_H
|
|
||||||
# include <stdint.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define NONAMELESSUNION
|
#define NONAMELESSUNION
|
||||||
#define NONAMELESSSTRUCT
|
#define NONAMELESSSTRUCT
|
||||||
|
@ -428,134 +425,6 @@ void wine_init( int argc, char *argv[], char *error, int error_size )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if (defined(__svr4__) || defined(__NetBSD__)) && !defined(MAP_TRYFIXED)
|
|
||||||
/***********************************************************************
|
|
||||||
* try_mmap_fixed
|
|
||||||
*
|
|
||||||
* The purpose of this routine is to emulate the behaviour of
|
|
||||||
* the Linux mmap() routine if a non-NULL address is passed,
|
|
||||||
* but the MAP_FIXED flag is not set. Linux in this case tries
|
|
||||||
* to place the mapping at the specified address, *unless* the
|
|
||||||
* range is already in use. Solaris, however, completely ignores
|
|
||||||
* the address argument in this case.
|
|
||||||
*
|
|
||||||
* As Wine code occasionally relies on the Linux behaviour, e.g. to
|
|
||||||
* be able to map non-relocateable PE executables to their proper
|
|
||||||
* start addresses, or to map the DOS memory to 0, this routine
|
|
||||||
* emulates the Linux behaviour by checking whether the desired
|
|
||||||
* address range is still available, and placing the mapping there
|
|
||||||
* using MAP_FIXED if so.
|
|
||||||
*/
|
|
||||||
static int try_mmap_fixed (void *addr, size_t len, int prot, int flags,
|
|
||||||
int fildes, off_t off)
|
|
||||||
{
|
|
||||||
char * volatile result = NULL;
|
|
||||||
int pagesize = getpagesize();
|
|
||||||
pid_t pid;
|
|
||||||
|
|
||||||
/* We only try to map to a fixed address if
|
|
||||||
addr is non-NULL and properly aligned,
|
|
||||||
and MAP_FIXED isn't already specified. */
|
|
||||||
|
|
||||||
if ( !addr )
|
|
||||||
return 0;
|
|
||||||
if ( (uintptr_t)addr & (pagesize-1) )
|
|
||||||
return 0;
|
|
||||||
if ( flags & MAP_FIXED )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* We use vfork() to freeze all threads of the
|
|
||||||
current process. This allows us to check without
|
|
||||||
race condition whether the desired memory range is
|
|
||||||
already in use. Note that because vfork() shares
|
|
||||||
the address spaces between parent and child, we
|
|
||||||
can actually perform the mapping in the child. */
|
|
||||||
|
|
||||||
if ( (pid = vfork()) == -1 )
|
|
||||||
{
|
|
||||||
perror("try_mmap_fixed: vfork");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if ( pid == 0 )
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char vec;
|
|
||||||
|
|
||||||
/* We call mincore() for every page in the desired range.
|
|
||||||
If any of these calls succeeds, the page is already
|
|
||||||
mapped and we must fail. */
|
|
||||||
for ( i = 0; i < len; i += pagesize )
|
|
||||||
if ( mincore( (caddr_t)addr + i, pagesize, &vec ) != -1 )
|
|
||||||
_exit(1);
|
|
||||||
|
|
||||||
/* Perform the mapping with MAP_FIXED set. This is safe
|
|
||||||
now, as none of the pages is currently in use. */
|
|
||||||
result = mmap( addr, len, prot, flags | MAP_FIXED, fildes, off );
|
|
||||||
if ( result == addr )
|
|
||||||
_exit(0);
|
|
||||||
|
|
||||||
if ( result != (void *) -1 ) /* This should never happen ... */
|
|
||||||
munmap( result, len );
|
|
||||||
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vfork() lets the parent continue only after the child
|
|
||||||
has exited. Furthermore, Wine sets SIGCHLD to SIG_IGN,
|
|
||||||
so we don't need to wait for the child. */
|
|
||||||
|
|
||||||
return result == addr;
|
|
||||||
}
|
|
||||||
#endif /* (__svr4__ || __NetBSD__) && !MAP_TRYFIXED */
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* wine_anon_mmap
|
|
||||||
*
|
|
||||||
* Portable wrapper for anonymous mmaps
|
|
||||||
*/
|
|
||||||
void *wine_anon_mmap( void *start, size_t size, int prot, int flags )
|
|
||||||
{
|
|
||||||
#ifdef HAVE_MMAP
|
|
||||||
static int fdzero = -1;
|
|
||||||
|
|
||||||
#ifdef MAP_ANON
|
|
||||||
flags |= MAP_ANON;
|
|
||||||
#else
|
|
||||||
if (fdzero == -1)
|
|
||||||
{
|
|
||||||
if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
|
|
||||||
{
|
|
||||||
perror( "/dev/zero: open" );
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* MAP_ANON */
|
|
||||||
|
|
||||||
#ifdef MAP_SHARED
|
|
||||||
flags &= ~MAP_SHARED;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
|
|
||||||
#ifdef MAP_PRIVATE
|
|
||||||
flags |= MAP_PRIVATE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MAP_TRYFIXED
|
|
||||||
/* If available, this will attempt a fixed mapping in-kernel */
|
|
||||||
flags |= MAP_TRYFIXED;
|
|
||||||
#elif defined(__svr4__) || defined(__NetBSD__)
|
|
||||||
if ( try_mmap_fixed( start, size, prot, flags, fdzero, 0 ) )
|
|
||||||
return start;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return mmap( start, size, prot, flags, fdzero, 0 );
|
|
||||||
#else
|
|
||||||
return (void *)-1;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These functions provide wrappers around dlopen() and associated
|
* These functions provide wrappers around dlopen() and associated
|
||||||
* functions. They work around a bug in glibc 2.1.x where calling
|
* functions. They work around a bug in glibc 2.1.x where calling
|
||||||
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
/*
|
||||||
|
* Wine portability routines
|
||||||
|
*
|
||||||
|
* Copyright 2000 Alexandre Julliard
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "wine/port.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#ifdef HAVE_SYS_MMAN_H
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_STDINT_H
|
||||||
|
# include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "wine/library.h"
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* wine_switch_to_stack
|
||||||
|
*
|
||||||
|
* Switch to the specified stack and call the function.
|
||||||
|
*/
|
||||||
|
void DECLSPEC_NORETURN wine_switch_to_stack( void (*func)(void *), void *arg, void *stack );
|
||||||
|
#if defined(__i386__) && defined(__GNUC__)
|
||||||
|
__ASM_GLOBAL_FUNC( wine_switch_to_stack,
|
||||||
|
"movl 4(%esp),%ecx\n\t" /* func */
|
||||||
|
"movl 8(%esp),%edx\n\t" /* arg */
|
||||||
|
"movl 12(%esp),%esp\n\t" /* stack */
|
||||||
|
"pushl %edx\n\t"
|
||||||
|
"xorl %ebp,%ebp\n\t"
|
||||||
|
"call *%ecx\n\t"
|
||||||
|
"int $3" /* we never return here */ );
|
||||||
|
#elif defined(__i386__) && defined(_MSC_VER)
|
||||||
|
__declspec(naked) void wine_switch_to_stack( void (*func)(void *), void *arg, void *stack )
|
||||||
|
{
|
||||||
|
__asm mov ecx, 4[esp];
|
||||||
|
__asm mov edx, 8[esp];
|
||||||
|
__asm mov esp, 12[esp];
|
||||||
|
__asm push edx;
|
||||||
|
__asm xor ebp, ebp;
|
||||||
|
__asm call [ecx];
|
||||||
|
__asm int 3;
|
||||||
|
}
|
||||||
|
#elif defined(__sparc__) && defined(__GNUC__)
|
||||||
|
__ASM_GLOBAL_FUNC( wine_switch_to_stack,
|
||||||
|
"mov %o0, %l0\n\t" /* store first argument */
|
||||||
|
"mov %o1, %l1\n\t" /* store second argument */
|
||||||
|
"mov %o2, %sp\n\t" /* store stack */
|
||||||
|
"call %l0, 0\n\t" /* call func */
|
||||||
|
"mov %l1, %o0\n\t" /* delay slot: arg for func */
|
||||||
|
"ta 0x01"); /* breakpoint - we never get here */
|
||||||
|
#elif defined(__powerpc__) && defined(__APPLE__)
|
||||||
|
__ASM_GLOBAL_FUNC( wine_switch_to_stack,
|
||||||
|
"mtctr r3\n\t" /* func -> ctr */
|
||||||
|
"mr r3,r4\n\t" /* args -> function param 1 (r3) */
|
||||||
|
"mr r1,r5\n\t" /* stack */
|
||||||
|
"bctr\n" /* call ctr */
|
||||||
|
"1:\tb 1b"); /* loop */
|
||||||
|
#elif defined(__powerpc__) && defined(__GNUC__)
|
||||||
|
__ASM_GLOBAL_FUNC( wine_switch_to_stack,
|
||||||
|
"mtctr 3\n\t" /* func -> ctr */
|
||||||
|
"mr 3,4\n\t" /* args -> function param 1 (r3) */
|
||||||
|
"mr 1,5\n\t" /* stack */
|
||||||
|
"bctr\n\t" /* call ctr */
|
||||||
|
"1:\tb 1b"); /* loop */
|
||||||
|
#else
|
||||||
|
#error You must implement wine_switch_to_stack for your platform
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if (defined(__svr4__) || defined(__NetBSD__)) && !defined(MAP_TRYFIXED)
|
||||||
|
/***********************************************************************
|
||||||
|
* try_mmap_fixed
|
||||||
|
*
|
||||||
|
* The purpose of this routine is to emulate the behaviour of
|
||||||
|
* the Linux mmap() routine if a non-NULL address is passed,
|
||||||
|
* but the MAP_FIXED flag is not set. Linux in this case tries
|
||||||
|
* to place the mapping at the specified address, *unless* the
|
||||||
|
* range is already in use. Solaris, however, completely ignores
|
||||||
|
* the address argument in this case.
|
||||||
|
*
|
||||||
|
* As Wine code occasionally relies on the Linux behaviour, e.g. to
|
||||||
|
* be able to map non-relocateable PE executables to their proper
|
||||||
|
* start addresses, or to map the DOS memory to 0, this routine
|
||||||
|
* emulates the Linux behaviour by checking whether the desired
|
||||||
|
* address range is still available, and placing the mapping there
|
||||||
|
* using MAP_FIXED if so.
|
||||||
|
*/
|
||||||
|
static int try_mmap_fixed (void *addr, size_t len, int prot, int flags,
|
||||||
|
int fildes, off_t off)
|
||||||
|
{
|
||||||
|
char * volatile result = NULL;
|
||||||
|
int pagesize = getpagesize();
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
/* We only try to map to a fixed address if
|
||||||
|
addr is non-NULL and properly aligned,
|
||||||
|
and MAP_FIXED isn't already specified. */
|
||||||
|
|
||||||
|
if ( !addr )
|
||||||
|
return 0;
|
||||||
|
if ( (uintptr_t)addr & (pagesize-1) )
|
||||||
|
return 0;
|
||||||
|
if ( flags & MAP_FIXED )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* We use vfork() to freeze all threads of the
|
||||||
|
current process. This allows us to check without
|
||||||
|
race condition whether the desired memory range is
|
||||||
|
already in use. Note that because vfork() shares
|
||||||
|
the address spaces between parent and child, we
|
||||||
|
can actually perform the mapping in the child. */
|
||||||
|
|
||||||
|
if ( (pid = vfork()) == -1 )
|
||||||
|
{
|
||||||
|
perror("try_mmap_fixed: vfork");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if ( pid == 0 )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char vec;
|
||||||
|
|
||||||
|
/* We call mincore() for every page in the desired range.
|
||||||
|
If any of these calls succeeds, the page is already
|
||||||
|
mapped and we must fail. */
|
||||||
|
for ( i = 0; i < len; i += pagesize )
|
||||||
|
if ( mincore( (caddr_t)addr + i, pagesize, &vec ) != -1 )
|
||||||
|
_exit(1);
|
||||||
|
|
||||||
|
/* Perform the mapping with MAP_FIXED set. This is safe
|
||||||
|
now, as none of the pages is currently in use. */
|
||||||
|
result = mmap( addr, len, prot, flags | MAP_FIXED, fildes, off );
|
||||||
|
if ( result == addr )
|
||||||
|
_exit(0);
|
||||||
|
|
||||||
|
if ( result != (void *) -1 ) /* This should never happen ... */
|
||||||
|
munmap( result, len );
|
||||||
|
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vfork() lets the parent continue only after the child
|
||||||
|
has exited. Furthermore, Wine sets SIGCHLD to SIG_IGN,
|
||||||
|
so we don't need to wait for the child. */
|
||||||
|
|
||||||
|
return result == addr;
|
||||||
|
}
|
||||||
|
#endif /* (__svr4__ || __NetBSD__) && !MAP_TRYFIXED */
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* wine_anon_mmap
|
||||||
|
*
|
||||||
|
* Portable wrapper for anonymous mmaps
|
||||||
|
*/
|
||||||
|
void *wine_anon_mmap( void *start, size_t size, int prot, int flags )
|
||||||
|
{
|
||||||
|
#ifdef HAVE_MMAP
|
||||||
|
static int fdzero = -1;
|
||||||
|
|
||||||
|
#ifdef MAP_ANON
|
||||||
|
flags |= MAP_ANON;
|
||||||
|
#else
|
||||||
|
if (fdzero == -1)
|
||||||
|
{
|
||||||
|
if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
|
||||||
|
{
|
||||||
|
perror( "/dev/zero: open" );
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* MAP_ANON */
|
||||||
|
|
||||||
|
#ifdef MAP_SHARED
|
||||||
|
flags &= ~MAP_SHARED;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
|
||||||
|
#ifdef MAP_PRIVATE
|
||||||
|
flags |= MAP_PRIVATE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MAP_TRYFIXED
|
||||||
|
/* If available, this will attempt a fixed mapping in-kernel */
|
||||||
|
flags |= MAP_TRYFIXED;
|
||||||
|
#elif defined(__svr4__) || defined(__NetBSD__)
|
||||||
|
if ( try_mmap_fixed( start, size, prot, flags, fdzero, 0 ) )
|
||||||
|
return start;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return mmap( start, size, prot, flags, fdzero, 0 );
|
||||||
|
#else
|
||||||
|
return (void *)-1;
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -27,6 +27,7 @@
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
#include "wine/exception.h"
|
#include "wine/exception.h"
|
||||||
|
#include "wine/library.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
|
||||||
struct fiber_data
|
struct fiber_data
|
||||||
|
@ -190,7 +191,7 @@ void WINAPI SwitchToFiber( LPVOID fiber )
|
||||||
NtCurrentTeb()->Tib.StackLimit = new_fiber->stack_limit;
|
NtCurrentTeb()->Tib.StackLimit = new_fiber->stack_limit;
|
||||||
NtCurrentTeb()->DeallocationStack = new_fiber->stack_allocation;
|
NtCurrentTeb()->DeallocationStack = new_fiber->stack_allocation;
|
||||||
if (new_fiber->start) /* first time */
|
if (new_fiber->start) /* first time */
|
||||||
SYSDEPS_SwitchToThreadStack( start_fiber, new_fiber );
|
wine_switch_to_stack( start_fiber, new_fiber, new_fiber->stack_base );
|
||||||
else
|
else
|
||||||
longjmp( new_fiber->jmpbuf, 1 );
|
longjmp( new_fiber->jmpbuf, 1 );
|
||||||
}
|
}
|
||||||
|
|
|
@ -586,7 +586,7 @@ void __wine_process_init( int argc, char *argv[] )
|
||||||
if (!THREAD_InitStack( NtCurrentTeb(), stack_size )) goto error;
|
if (!THREAD_InitStack( NtCurrentTeb(), stack_size )) goto error;
|
||||||
|
|
||||||
/* switch to the new stack */
|
/* switch to the new stack */
|
||||||
SYSDEPS_SwitchToThreadStack( start_process, NULL );
|
wine_switch_to_stack( start_process, NULL, NtCurrentTeb()->Tib.StackBase );
|
||||||
|
|
||||||
error:
|
error:
|
||||||
ExitProcess( GetLastError() );
|
ExitProcess( GetLastError() );
|
||||||
|
|
Loading…
Reference in New Issue