sysdeps.c 6.55 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4 5 6
/*
 * System-dependent scheduler support
 *
 * Copyright 1998 Alexandre Julliard
 */

7 8
#include "config.h"

Alexandre Julliard's avatar
Alexandre Julliard committed
9 10 11
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
12
#include <sys/time.h>
13
#include <sys/resource.h>
14 15 16
#ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
#endif
17 18 19 20 21 22
#ifdef HAVE_SYS_LWP_H
# include <sys/lwp.h>
#endif
#ifdef HAVE_UCONTEXT_H
# include <ucontext.h>
#endif
23
#include "wine/port.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
24
#include "thread.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
25
#include "server.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
26
#include "winbase.h"
27
#include "wine/exception.h"
28
#include "debugtools.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
29

30
DEFAULT_DEBUG_CHANNEL(thread);
31

32
#ifdef linux
Alexandre Julliard's avatar
Alexandre Julliard committed
33 34 35 36 37 38 39 40 41 42
# ifdef HAVE_SCHED_H
#  include <sched.h>
# endif
# ifndef CLONE_VM
#  define CLONE_VM      0x00000100
#  define CLONE_FS      0x00000200
#  define CLONE_FILES   0x00000400
#  define CLONE_SIGHAND 0x00000800
#  define CLONE_PID     0x00001000
# endif  /* CLONE_VM */
43
#endif  /* linux */
Alexandre Julliard's avatar
Alexandre Julliard committed
44

45 46 47 48 49
/***********************************************************************
 *           SYSDEPS_SetCurThread
 *
 * Make 'thread' the current thread.
 */
50
void SYSDEPS_SetCurThread( TEB *teb )
51
{
52
#if defined(__i386__)
53
    /* On the i386, the current thread is in the %fs register */
54
    __set_fs( teb->teb_sel );
55 56 57 58
#elif defined(HAVE__LWP_CREATE)
    /* On non-i386 Solaris, we use the LWP private pointer */
    _lwp_setprivate( teb );
#endif
59 60
}

Alexandre Julliard's avatar
Alexandre Julliard committed
61 62 63 64 65
/***********************************************************************
 *           SYSDEPS_StartThread
 *
 * Startup routine for a new thread.
 */
66
static void SYSDEPS_StartThread( TEB *teb )
Alexandre Julliard's avatar
Alexandre Julliard committed
67
{
68
    SYSDEPS_SetCurThread( teb );
69
    CLIENT_InitThread();
70 71 72 73 74 75 76 77 78 79
    SIGNAL_Init();
    __TRY
    {
        teb->startup();
    }
    __EXCEPT(UnhandledExceptionFilter)
    {
        TerminateThread( GetCurrentThread(), GetExceptionCode() );
    }
    __ENDTRY
80
    SYSDEPS_ExitThread(0);  /* should never get here */
Alexandre Julliard's avatar
Alexandre Julliard committed
81 82 83 84 85 86 87 88 89
}


/***********************************************************************
 *           SYSDEPS_SpawnThread
 *
 * Start running a new thread.
 * Return -1 on error, 0 if OK.
 */
90
int SYSDEPS_SpawnThread( TEB *teb )
Alexandre Julliard's avatar
Alexandre Julliard committed
91
{
92
#ifdef ERRNO_LOCATION
Alexandre Julliard's avatar
Alexandre Julliard committed
93

94
#ifdef linux
95 96
    const int flags = CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD;
    if (clone( (int (*)(void *))SYSDEPS_StartThread, teb->stack_top, flags, teb ) < 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
97
        return -1;
98
    if (!(flags & CLONE_FILES)) close( teb->socket );  /* close the child socket in the parent */
99
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
100 101 102
#endif

#ifdef HAVE_RFORK
103
    const int flags = RFPROC | RFMEM; /*|RFFDG*/
104 105
    void **sp = (void **)teb->stack_top;
    *--sp = teb;
106
    *--sp = 0;
107 108
    *--sp = SYSDEPS_StartThread;
    __asm__ __volatile__(
109
    "pushl %2;\n\t"		/* flags */
110 111 112 113 114
    "pushl $0;\n\t"		/* 0 ? */
    "movl %1,%%eax;\n\t"	/* SYS_rfork */
    ".byte 0x9a; .long 0; .word 7;\n\t"	/* lcall 7:0... FreeBSD syscall */
    "cmpl $0, %%edx;\n\t"
    "je 1f;\n\t"
115
    "movl %0,%%esp;\n\t"	/* child -> new thread */
116
    "ret;\n"
117
    "1:\n\t"		/* parent -> caller thread */
118
    "addl $8,%%esp" :
119
    : "r" (sp), "g" (SYS_rfork), "g" (flags)
120
    : "eax", "edx");
121
    if (flags & RFFDG) close( teb->socket );  /* close the child socket in the parent */
122
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
123 124
#endif

125 126
#ifdef HAVE__LWP_CREATE
    ucontext_t context;
127 128
    _lwp_makecontext( &context, (void(*)(void *))SYSDEPS_StartThread, teb,
                      NULL, teb->stack_base, (char *)teb->stack_top - (char *)teb->stack_base );
129 130 131 132 133
    if ( _lwp_create( &context, 0, NULL ) )
        return -1;
    return 0;
#endif

134
#endif /* ERRNO_LOCATION */
135

136
    FIXME("CreateThread: stub\n" );
Alexandre Julliard's avatar
Alexandre Julliard committed
137 138 139 140
    return 0;
}


141

Alexandre Julliard's avatar
Alexandre Julliard committed
142 143 144 145 146
/***********************************************************************
 *           SYSDEPS_ExitThread
 *
 * Exit a running thread; must not return.
 */
147
void SYSDEPS_ExitThread( int status )
Alexandre Julliard's avatar
Alexandre Julliard committed
148
{
149 150 151
    int socket = NtCurrentTeb()->socket;
    NtCurrentTeb()->socket = -1;
    close( socket );
152
#ifdef HAVE__LWP_CREATE
153 154
    _lwp_exit();
#endif
155
    _exit( status );
Patrik Stridvall's avatar
Patrik Stridvall committed
156 157 158 159 160
    /*
     * It is of course impossible to come here,
     * but it eliminates a compiler warning.
     */
    exit( status );
Alexandre Julliard's avatar
Alexandre Julliard committed
161 162 163
}


164 165 166
/***********************************************************************
 *           SYSDEPS_CallOnStack
 */
167
int SYSDEPS_DoCallOnStack( int (*func)(LPVOID), LPVOID arg )
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
{
    int retv = 0;

    __TRY
    {
        retv = func( arg );
    }
    __EXCEPT(UnhandledExceptionFilter)
    {
        TerminateThread( GetCurrentThread(), GetExceptionCode() );
        return 0;
    }
    __ENDTRY

    return retv;
}

#ifdef __i386__
int SYSDEPS_CallOnStack( LPVOID stackTop, LPVOID stackLow,
                         int (*func)(LPVOID), LPVOID arg );
__ASM_GLOBAL_FUNC( SYSDEPS_CallOnStack,
                   "pushl %ebp\n\t"
                   "movl %esp, %ebp\n\t"
                   ".byte 0x64; pushl 0x04\n\t"
                   ".byte 0x64; pushl 0x08\n\t"
                   "movl 8(%ebp), %esp\n\t"
                   "movl 12(%ebp), %eax\n\t"
                   ".byte 0x64; movl %esp, 0x04\n\t"
                   ".byte 0x64; movl %eax, 0x08\n\t"
                   "pushl 20(%ebp)\n\t"
                   "pushl 16(%ebp)\n\t"
                   "call " __ASM_NAME("SYSDEPS_DoCallOnStack") "\n\t"
                   "leal -8(%ebp), %esp\n\t"
                   ".byte 0x64; popl 0x08\n\t"
                   ".byte 0x64; popl 0x04\n\t"
                   "popl %ebp\n\t"
                   "ret" );
#else
int SYSDEPS_CallOnStack( LPVOID stackTop, LPVOID stackLow,
                         int (*func)(LPVOID), LPVOID arg )
{
    return SYSDEPS_DoCallOnStack( func, arg );
}
#endif

/***********************************************************************
 *           SYSDEPS_SwitchToThreadStack
 */
void SYSDEPS_SwitchToThreadStack( void (*func)(void) )
{
218
    DWORD page_size = getpagesize();
219 220
    DWORD cur_stack = (((DWORD)&func) + (page_size-1)) & ~(page_size-1);

221 222 223 224 225 226 227 228 229 230 231 232
    TEB *teb = NtCurrentTeb();
    LPVOID stackTop = teb->stack_top;
    LPVOID stackLow = teb->stack_low;

    struct rlimit rl;

    if ( getrlimit(RLIMIT_STACK, &rl) < 0 ) 
    {
        WARN("Can't get rlimit\n");
        rl.rlim_cur = 8*1024*1024;
    }

233 234 235
    teb->stack_top = (LPVOID) cur_stack;
    teb->stack_low = (LPVOID)(cur_stack - rl.rlim_cur);

236 237 238 239
    SYSDEPS_CallOnStack( stackTop, stackLow, 
                         (int (*)(void *))func, NULL );
}

Alexandre Julliard's avatar
Alexandre Julliard committed
240 241
/**********************************************************************
 *           NtCurrentTeb   (NTDLL.89)
Alexandre Julliard's avatar
Alexandre Julliard committed
242 243
 *
 * This will crash and burn if called before threading is initialized
Alexandre Julliard's avatar
Alexandre Julliard committed
244
 */
245 246 247
#ifdef __i386__
__ASM_GLOBAL_FUNC( NtCurrentTeb, ".byte 0x64\n\tmovl 0x18,%eax\n\tret" );
#elif defined(HAVE__LWP_CREATE)
248 249
struct _TEB * WINAPI NtCurrentTeb(void)
{
250 251
    extern void *_lwp_getprivate(void);
    return (struct _TEB *)_lwp_getprivate();
252
}
253 254 255
#else
# error NtCurrentTeb not defined for this architecture
#endif  /* __i386__ */