Release 970112
[wine] / scheduler / thread.c
1 /*
2  * Win32 threads
3  *
4  * Copyright 1996 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include "thread.h"
9 #include "winerror.h"
10 #include "heap.h"
11 #include "selectors.h"
12 #include "winnt.h"
13
14 THDB *pCurrentThread = NULL;
15
16
17 /***********************************************************************
18  *           THREAD_Create
19  */
20 THDB *THREAD_Create( PDB32 *pdb, DWORD stack_size )
21 {
22     THDB *thdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(THDB) );
23     if (!thdb) return NULL;
24     thdb->header.type     = K32OBJ_THREAD;
25     thdb->header.refcount = 1;
26     thdb->process         = pdb;
27     thdb->teb.except      = (void *)-1;
28     thdb->teb.htask16     = 0; /* FIXME */
29     thdb->teb.stack_sel   = 0; /* FIXME */
30     thdb->teb.self        = &thdb->teb;
31     thdb->teb.tls_ptr     = thdb->tls_array;
32     thdb->process2        = pdb;
33     thdb->exit_code       = 0x103; /* STILL_ACTIVE */
34
35     /* Allocate the stack */
36
37     if (!stack_size) stack_size = 1024 * 1024;  /* default size = 1Mb */
38     thdb->stack_base = VirtualAlloc( NULL, stack_size, MEM_COMMIT,
39                                      PAGE_EXECUTE_READWRITE );
40     if (!thdb->stack_base) goto error;
41     /* Un-commit the first page (FIXME: should use PAGE_GUARD instead) */
42     VirtualFree( thdb->stack_base, 1, MEM_DECOMMIT );
43     thdb->teb.stack_top   = (char *)thdb->stack_base + stack_size;
44     thdb->teb.stack_low   = thdb->teb.stack_top;
45     thdb->exit_stack      = thdb->teb.stack_top;
46
47     /* Allocate the TEB selector (%fs register) */
48
49     thdb->teb_sel = SELECTOR_AllocBlock( &thdb->teb, 0x1000, SEGMENT_DATA,
50                                          TRUE, FALSE );
51     if (!thdb->teb_sel) goto error;
52     return thdb;
53
54 error:
55     if (thdb->teb_sel) SELECTOR_FreeBlock( thdb->teb_sel, 1 );
56     if (thdb->stack_base) VirtualFree( thdb->stack_base, 0, MEM_RELEASE );
57     HeapFree( SystemHeap, 0, thdb );
58     return NULL;
59 }
60
61
62 /***********************************************************************
63  *           THREAD_Destroy
64  */
65 void THREAD_Destroy( K32OBJ *ptr )
66 {
67     THDB *thdb = (THDB *)ptr;
68     assert( ptr->type == K32OBJ_THREAD );
69     ptr->type = K32OBJ_UNKNOWN;
70     SELECTOR_FreeBlock( thdb->teb_sel, 1 );
71     HeapFree( SystemHeap, 0, thdb );
72 }
73
74
75 /***********************************************************************
76  *           GetCurrentThread   (KERNEL32.200)
77  */
78 HANDLE32 GetCurrentThread(void)
79 {
80     return 0xFFFFFFFE;
81 }
82
83
84 /***********************************************************************
85  *           GetCurrentThreadId   (KERNEL32.201)
86  * Returns crypted (xor'ed) pointer to THDB in Win95.
87  */
88 DWORD GetCurrentThreadId(void)
89 {
90     /* FIXME: should probably use %fs register here */
91     assert( pCurrentThread );
92     return (DWORD)pCurrentThread;
93 }
94
95
96 /**********************************************************************
97  *           GetLastError   (KERNEL.148) (KERNEL32.227)
98  */
99 DWORD GetLastError(void)
100 {
101     THDB *thread = (THDB *)GetCurrentThreadId();
102     return thread->last_error;
103 }
104
105
106 /**********************************************************************
107  *           SetLastError   (KERNEL.147) (KERNEL32.497)
108  */
109 void SetLastError( DWORD error )
110 {
111     THDB *thread;
112     if (!pCurrentThread) return;  /* FIXME */
113     thread = (THDB *)GetCurrentThreadId();
114     thread->last_error = error;
115 }
116
117
118 /**********************************************************************
119  *           SetLastErrorEx   (USER32.484)
120  */
121 void SetLastErrorEx( DWORD error, DWORD type )
122 {
123     /* FIXME: what about 'type'? */
124     SetLastError( error );
125 }
126
127
128 /**********************************************************************
129  *           TlsAlloc   (KERNEL32.530)
130  */
131 DWORD TlsAlloc(void)
132 {
133     DWORD i, mask, ret = 0;
134     THDB *thread = (THDB *)GetCurrentThreadId();
135     DWORD *bits = thread->process->tls_bits;
136     EnterCriticalSection( &thread->process->crit_section );
137     if (*bits == 0xffffffff)
138     {
139         bits++;
140         ret = 32;
141         if (*bits == 0xffffffff)
142         {
143             LeaveCriticalSection( &thread->process->crit_section );
144             SetLastError( ERROR_NO_MORE_ITEMS );
145             return 0xffffffff;
146         }
147     }
148     for (i = 0, mask = 1; i < 32; i++, mask <<= 1) if (!(*bits & mask)) break;
149     *bits |= mask;
150     LeaveCriticalSection( &thread->process->crit_section );
151     return ret + i;
152 }
153
154
155 /**********************************************************************
156  *           TlsFree   (KERNEL32.531)
157  */
158 BOOL32 TlsFree( DWORD index )
159 {
160     DWORD mask;
161     THDB *thread = (THDB *)GetCurrentThreadId();
162     DWORD *bits = thread->process->tls_bits;
163     if (index >= 64)
164     {
165         SetLastError( ERROR_INVALID_PARAMETER );
166         return FALSE;
167     }
168     EnterCriticalSection( &thread->process->crit_section );
169     if (index >= 32) bits++;
170     mask = (1 << (index & 31));
171     if (!(*bits & mask))  /* already free? */
172     {
173         LeaveCriticalSection( &thread->process->crit_section );
174         SetLastError( ERROR_INVALID_PARAMETER );
175         return FALSE;
176     }
177     *bits &= ~mask;
178     thread->tls_array[index] = 0;
179     /* FIXME: should zero all other thread values */
180     LeaveCriticalSection( &thread->process->crit_section );
181     return TRUE;
182 }
183
184
185 /**********************************************************************
186  *           TlsGetValue   (KERNEL32.532)
187  */
188 LPVOID TlsGetValue( DWORD index )
189 {
190     THDB *thread = (THDB *)GetCurrentThreadId();
191     if (index >= 64)
192     {
193         SetLastError( ERROR_INVALID_PARAMETER );
194         return NULL;
195     }
196     SetLastError( ERROR_SUCCESS );
197     return thread->tls_array[index];
198 }
199
200
201 /**********************************************************************
202  *           TlsSetValue   (KERNEL32.533)
203  */
204 BOOL32 TlsSetValue( DWORD index, LPVOID value )
205 {
206     THDB *thread = (THDB *)GetCurrentThreadId();
207     if (index >= 64)
208     {
209         SetLastError( ERROR_INVALID_PARAMETER );
210         return FALSE;
211     }
212     thread->tls_array[index] = value;
213     return TRUE;
214 }
215
216
217 /***********************************************************************
218  *           GetThreadContext   (KERNEL32.294)
219  */
220 BOOL32 GetThreadContext( HANDLE32 handle, CONTEXT *context )
221 {
222     return FALSE;
223 }
224
225
226 /**********************************************************************
227  *           NtCurrentTeb   (NTDLL.89)
228  */
229 void NtCurrentTeb( CONTEXT *context )
230 {
231     EAX_reg(context) = GetSelectorBase( FS_reg(context) );
232 }
233
234 /**********************************************************************
235  *           GetThreadPriority   (KERNEL32.296)
236  */
237 INT32
238 GetThreadPriority(HANDLE32 hthread) {
239     THDB *thread;
240     INT32 ret;
241     
242     ret = 0;
243     thread = (THDB*)PROCESS_GetObjPtr(hthread,K32OBJ_THREAD);
244     if (thread) {
245         ret = thread->delta_priority;
246         K32OBJ_DecCount((K32OBJ*)thread);
247     }
248     return ret;
249 }
250
251 /**********************************************************************
252  *           SetThreadPriority   (KERNEL32.514)
253  */
254 BOOL32
255 SetThreadPriority(HANDLE32 hthread,INT32 priority) {
256     THDB *thread;
257     
258     thread = (THDB*)PROCESS_GetObjPtr(hthread,K32OBJ_THREAD);
259     if (thread) {
260         thread->delta_priority = priority;
261         K32OBJ_DecCount((K32OBJ*)thread);
262     }
263     return TRUE;
264 }