Merged DDBitmap and physBitmap into the generic bitmap structure
[wine] / scheduler / sysdeps.c
1 /*
2  * System-dependent scheduler support
3  *
4  * Copyright 1998 Alexandre Julliard
5  */
6
7 #include "config.h"
8
9 /* Get pointers to the static errno and h_errno variables used by Xlib. This
10    must be done before including <errno.h> makes the variables invisible.  */
11 extern int errno;
12 static int *perrno = &errno;
13 extern int h_errno;
14 static int *ph_errno = &h_errno;
15
16 #include <signal.h>
17 #include <stdio.h>
18 #include <unistd.h>
19 #ifdef HAVE_SYS_SYSCALL_H
20 # include <sys/syscall.h>
21 #endif
22 #ifdef HAVE_SYS_LWP_H
23 # include <sys/lwp.h>
24 #endif
25 #ifdef HAVE_UCONTEXT_H
26 # include <ucontext.h>
27 #endif
28 #include "wine/port.h"
29 #include "thread.h"
30 #include "selectors.h"
31 #include "server.h"
32 #include "winbase.h"
33 #include "wine/exception.h"
34 #include "debugtools.h"
35
36 DEFAULT_DEBUG_CHANNEL(thread)
37
38 /* Xlib critical section (FIXME: does not belong here) */
39 CRITICAL_SECTION X11DRV_CritSection = { 0, };
40
41 #ifdef linux
42 # ifdef HAVE_SCHED_H
43 #  include <sched.h>
44 # endif
45 # ifndef CLONE_VM
46 #  define CLONE_VM      0x00000100
47 #  define CLONE_FS      0x00000200
48 #  define CLONE_FILES   0x00000400
49 #  define CLONE_SIGHAND 0x00000800
50 #  define CLONE_PID     0x00001000
51 # endif  /* CLONE_VM */
52 # define PER_THREAD_FILE_HANDLES
53 #endif  /* linux */
54
55 #ifdef HAVE_RFORK
56 # define PER_THREAD_FILE_HANDLES
57 #endif
58
59 static int init_done;
60
61 #ifndef NO_REENTRANT_LIBC
62
63 /***********************************************************************
64  *           __errno_location/__error/___errno
65  *
66  * Get the per-thread errno location.
67  */
68 #ifdef HAVE__ERRNO_LOCATION
69 int *__errno_location()
70 #endif
71 #ifdef HAVE__ERROR
72 int *__error()
73 #endif
74 #ifdef HAVE___ERRNO
75 int *___errno()
76 #endif
77 #ifdef HAVE__THR_ERRNO
78 int *__thr_errno()
79 #endif
80 {
81     if (!init_done) return perrno;
82 #ifdef NO_REENTRANT_X11
83     /* Use static libc errno while running in Xlib. */
84     if (X11DRV_CritSection.OwningThread == GetCurrentThreadId())
85         return perrno;
86 #endif
87     return &NtCurrentTeb()->thread_errno;
88 }
89
90 /***********************************************************************
91  *           __h_errno_location
92  *
93  * Get the per-thread h_errno location.
94  */
95 int *__h_errno_location()
96 {
97     if (!init_done) return ph_errno;
98 #ifdef NO_REENTRANT_X11
99     /* Use static libc h_errno while running in Xlib. */
100     if (X11DRV_CritSection.OwningThread == GetCurrentThreadId())
101         return ph_errno;
102 #endif
103     return &NtCurrentTeb()->thread_h_errno;
104 }
105
106 #endif /* NO_REENTRANT_LIBC */
107
108 /***********************************************************************
109  *           SYSDEPS_SetCurThread
110  *
111  * Make 'thread' the current thread.
112  */
113 void SYSDEPS_SetCurThread( TEB *teb )
114 {
115 #if defined(__i386__)
116     /* On the i386, the current thread is in the %fs register */
117     __set_fs( teb->teb_sel );
118 #elif defined(HAVE__LWP_CREATE)
119     /* On non-i386 Solaris, we use the LWP private pointer */
120     _lwp_setprivate( teb );
121 #endif
122
123     init_done = 1;  /* now we can use threading routines */
124 }
125
126 /***********************************************************************
127  *           SYSDEPS_StartThread
128  *
129  * Startup routine for a new thread.
130  */
131 static void SYSDEPS_StartThread( TEB *teb )
132 {
133     int parent_socket = -1;
134 #ifdef PER_THREAD_FILE_HANDLES
135     parent_socket = NtCurrentTeb()->socket;
136 #endif
137     SYSDEPS_SetCurThread( teb );
138     if (parent_socket != -1) close( parent_socket );
139     CLIENT_InitThread();
140     SIGNAL_Init();
141     __TRY
142     {
143         teb->startup();
144     }
145     __EXCEPT(UnhandledExceptionFilter)
146     {
147         TerminateThread( GetCurrentThread(), GetExceptionCode() );
148     }
149     __ENDTRY
150     SYSDEPS_ExitThread(0);  /* should never get here */
151 }
152
153
154 /***********************************************************************
155  *           SYSDEPS_SpawnThread
156  *
157  * Start running a new thread.
158  * Return -1 on error, 0 if OK.
159  */
160 int SYSDEPS_SpawnThread( TEB *teb )
161 {
162 #ifndef NO_REENTRANT_LIBC
163
164 #ifdef linux
165     if (clone( (int (*)(void *))SYSDEPS_StartThread, teb->stack_top,
166                CLONE_VM | CLONE_FS | SIGCHLD, teb ) < 0)
167         return -1;
168     close( teb->socket );  /* close the child socket in the parent */
169     return 0;
170 #endif
171
172 #ifdef HAVE_RFORK
173     void **sp = (void **)teb->stack_top;
174     *--sp = teb;
175     *--sp = 0;
176     *--sp = SYSDEPS_StartThread;
177     __asm__ __volatile__(
178     "pushl %2;\n\t"             /* RFPROC|RFMEM|RFFDG */
179     "pushl $0;\n\t"             /* 0 ? */
180     "movl %1,%%eax;\n\t"        /* SYS_rfork */
181     ".byte 0x9a; .long 0; .word 7;\n\t" /* lcall 7:0... FreeBSD syscall */
182     "cmpl $0, %%edx;\n\t"
183     "je 1f;\n\t"
184     "movl %0,%%esp;\n\t"        /* child -> new thread */
185     "ret;\n"
186     "1:\n\t"            /* parent -> caller thread */
187     "addl $8,%%esp" :
188     : "r" (sp), "g" (SYS_rfork), "g" (RFPROC|RFMEM|RFFDG)
189     : "eax", "edx");
190     close( teb->socket );  /* close the child socket in the parent */
191     return 0;
192 #endif
193
194 #ifdef HAVE__LWP_CREATE
195     ucontext_t context;
196     _lwp_makecontext( &context, (void(*)(void *))SYSDEPS_StartThread, teb,
197                       NULL, teb->stack_base, (char *)teb->stack_top - (char *)teb->stack_base );
198     if ( _lwp_create( &context, 0, NULL ) )
199         return -1;
200     return 0;
201 #endif
202
203 #endif /* NO_REENTRANT_LIBC */
204
205     FIXME("CreateThread: stub\n" );
206     return 0;
207 }
208
209
210
211 /***********************************************************************
212  *           SYSDEPS_ExitThread
213  *
214  * Exit a running thread; must not return.
215  */
216 void SYSDEPS_ExitThread( int status )
217 {
218 #ifndef PER_THREAD_FILE_HANDLES
219     /* otherwise it will be closed automagically by _exit */
220     close( NtCurrentTeb()->socket );
221 #endif
222 #ifdef HAVE__LWP_CREATE
223     _lwp_exit();
224 #endif
225     _exit( status );
226     /*
227      * It is of course impossible to come here,
228      * but it eliminates a compiler warning.
229      */
230     exit( status );
231 }
232
233
234 /**********************************************************************
235  *           NtCurrentTeb   (NTDLL.89)
236  *
237  * This will crash and burn if called before threading is initialized
238  */
239 #ifdef __i386__
240 __ASM_GLOBAL_FUNC( NtCurrentTeb, ".byte 0x64\n\tmovl 0x18,%eax\n\tret" );
241 #elif defined(HAVE__LWP_CREATE)
242 struct _TEB * WINAPI NtCurrentTeb(void)
243 {
244     extern void *_lwp_getprivate(void);
245     return (struct _TEB *)_lwp_getprivate();
246 }
247 #else
248 # error NtCurrentTeb not defined for this architecture
249 #endif  /* __i386__ */