192173e017d1d1b21590f6f65e422ceacce8fc92
[reactos.git] / posix / lib / psxdll / pthread / create.c
1 /* $Id: create.c,v 1.2 2002/02/20 09:17:57 hyperion Exp $
2 */
3 /*
4 * COPYRIGHT: See COPYING in the top level directory
5 * PROJECT: ReactOS POSIX+ Subsystem
6 * FILE: subsys/psx/lib/psxdll/pthread/create.c
7 * PURPOSE: Thread creation
8 * PROGRAMMER: KJK::Hyperion <noog@libero.it>
9 * UPDATE HISTORY:
10 * 19/12/2001: Created
11 */
12
13 #include <ddk/ntddk.h>
14 #include <string.h>
15 #include <sys/types.h>
16 #include <pthread.h>
17 #include <psx/debug.h>
18 #include <psx/errno.h>
19 #include <napi/i386/segment.h>
20
21 /* thread creation code adapted from kernel32's CreateRemoteThread() function */
22
23 static void __threadentry (void *(*start_routine)(void*), void *arg)
24 {
25 INFO("hello world! thread successfully created");
26
27 TODO("initialize thread data");
28 TODO("notify DLLs");
29 TODO("notify psxss");
30
31 INFO("about to call start routine at %#x with argument %#x", start_routine, arg);
32
33 pthread_exit(start_routine(arg));
34 }
35
36 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
37 void *(*start_routine)(void*), void *arg)
38 {
39 HANDLE hThread;
40 OBJECT_ATTRIBUTES oaThreadAttrs;
41 CLIENT_ID ciId;
42 CONTEXT cxThreadContext;
43 INITIAL_TEB itInitialTeb;
44 BOOLEAN fSuspended;
45 ULONG nOldPageProtection;
46 NTSTATUS nErrCode;
47
48 /* initialize generic object attributes */
49 oaThreadAttrs.Length = sizeof(OBJECT_ATTRIBUTES);
50 oaThreadAttrs.RootDirectory = NULL;
51 oaThreadAttrs.ObjectName = NULL;
52 oaThreadAttrs.Attributes = 0;
53 oaThreadAttrs.SecurityDescriptor = NULL;
54 oaThreadAttrs.SecurityQualityOfService = NULL;
55
56 /* initialize thread attributes */
57 fSuspended = FALSE; /* FIXME? really needed? can we hardcode this to FALSE? */
58
59 /* stack attributes */
60 FIXME("stack size defaulted to 0x100000 - thread attributes ignored");
61
62 /* stack reserve size */
63 itInitialTeb.StackReserve = 0x100000;
64
65 /* stack commit size */
66 itInitialTeb.StackCommit = itInitialTeb.StackReserve - PAGESIZE;
67
68 /* guard page */
69 itInitialTeb.StackCommit += PAGESIZE;
70
71 /* reserve stack */
72 itInitialTeb.StackAllocate = NULL;
73
74 nErrCode = NtAllocateVirtualMemory
75 (
76 NtCurrentProcess(),
77 &itInitialTeb.StackAllocate,
78 0,
79 &itInitialTeb.StackReserve,
80 MEM_RESERVE,
81 PAGE_READWRITE
82 );
83
84 if(!NT_SUCCESS(nErrCode))
85 {
86 return (__status_to_errno(nErrCode)); /* FIXME? TODO? pthread specific error codes? */
87 }
88
89 itInitialTeb.StackBase = (PVOID)((ULONG)itInitialTeb.StackAllocate + itInitialTeb.StackReserve);
90 itInitialTeb.StackLimit = (PVOID)((ULONG)itInitialTeb.StackBase - itInitialTeb.StackCommit);
91
92 /* commit stack */
93 nErrCode = NtAllocateVirtualMemory
94 (
95 NtCurrentProcess(),
96 &itInitialTeb.StackLimit,
97 0,
98 &itInitialTeb.StackCommit,
99 MEM_COMMIT,
100 PAGE_READWRITE
101 );
102
103 if(!NT_SUCCESS(nErrCode))
104 {
105 NtFreeVirtualMemory
106 (
107 NtCurrentProcess(),
108 itInitialTeb.StackAllocate,
109 &itInitialTeb.StackReserve,
110 MEM_RELEASE
111 );
112
113 return (__status_to_errno(nErrCode));
114 }
115
116 /* protect guard page */
117 nErrCode = NtProtectVirtualMemory
118 (
119 NtCurrentProcess(),
120 itInitialTeb.StackLimit,
121 PAGESIZE,
122 PAGE_GUARD | PAGE_READWRITE,
123 &nOldPageProtection
124 );
125
126 if(!NT_SUCCESS(nErrCode))
127 {
128 NtFreeVirtualMemory
129 (
130 NtCurrentProcess(),
131 itInitialTeb.StackAllocate,
132 &itInitialTeb.StackReserve,
133 MEM_RELEASE
134 );
135
136 return (__status_to_errno(nErrCode));
137 }
138
139 /* initialize thread registers */
140
141 //#ifdef __i386__
142 memset(&cxThreadContext, 0, sizeof(CONTEXT));
143 cxThreadContext.Eip = (LONG)__threadentry;
144 cxThreadContext.SegGs = USER_DS;
145 cxThreadContext.SegFs = TEB_SELECTOR;
146 cxThreadContext.SegEs = USER_DS;
147 cxThreadContext.SegDs = USER_DS;
148 cxThreadContext.SegCs = USER_CS;
149 cxThreadContext.SegSs = USER_DS;
150 cxThreadContext.Esp = (ULONG)itInitialTeb.StackBase - 12;
151 cxThreadContext.EFlags = (1<<1) + (1<<9);
152
153 /* initialize call stack */
154 *((PULONG)((ULONG)itInitialTeb.StackBase - 4)) = (ULONG)arg; /* thread argument */
155 *((PULONG)((ULONG)itInitialTeb.StackBase - 8)) = (ULONG)start_routine; /* thread start routine */
156 *((PULONG)((ULONG)itInitialTeb.StackBase - 12)) = 0xDEADBEEF; /* "shouldn't see me" */
157 //#else
158 //#error Unsupported architecture
159 //#endif
160
161 INFO("about to create new thread - start routine at %#x, argument %#x", start_routine, arg);
162
163 /* create thread */
164 nErrCode = NtCreateThread
165 (
166 &hThread,
167 THREAD_ALL_ACCESS,
168 &oaThreadAttrs,
169 NtCurrentProcess(),
170 &ciId,
171 &cxThreadContext,
172 &itInitialTeb,
173 fSuspended
174 );
175
176 if(!NT_SUCCESS(nErrCode))
177 {
178 NtFreeVirtualMemory
179 (
180 NtCurrentProcess(),
181 itInitialTeb.StackAllocate,
182 &itInitialTeb.StackReserve,
183 MEM_RELEASE
184 );
185
186 return (__status_to_errno(nErrCode));
187 }
188
189 /* FIXME? should we return the thread handle or the thread id? */
190 if(thread != 0)
191 *thread = (pthread_t)&ciId.UniqueThread; /* for the moment, we return the id */
192
193 return (0);
194
195 }
196
197 /* EOF */
198