1 /* $Id: fork.c,v 1.3 2002/10/29 04:45:46 rex Exp $
4 * COPYRIGHT: See COPYING in the top level directory
5 * PROJECT: ReactOS POSIX+ Subsystem
6 * FILE: subsys/psx/lib/psxdll/unistd/fork.c
7 * PURPOSE: create a new process
8 * PROGRAMMER: KJK::Hyperion <noog@libero.it>
13 #include <ddk/ntddk.h>
15 #include <sys/types.h>
19 #include <psx/debug.h>
20 #include <psx/errno.h>
24 typedef struct _PORT_MESSAGE
{
28 USHORT VirtualRangesOffset
;
33 } PORT_MESSAGE
, *PPORT_MESSAGE
;
35 struct CSRSS_MESSAGE
{
42 NTSTATUS STDCALL
CsrClientCallServer(
52 CONTEXT ctxThreadContext
;
55 INITIAL_TEB itInitialTeb
;
57 MEMORY_BASIC_INFORMATION mbiStackInfo
;
58 THREAD_BASIC_INFORMATION tbiThreadInfo
;
61 PORT_MESSAGE PortMessage
;
62 struct CSRSS_MESSAGE CsrssMessage
;
63 PROCESS_INFORMATION ProcessInformation
;
69 /* STEP 1: Duplicate current process */
70 nErrCode
= NtCreateProcess
83 if(!NT_SUCCESS(nErrCode
))
85 ERR("NtCreateProcess() failed with status 0x%08X\n", nErrCode
);
89 /* STEP 2: Duplicate current thread */
90 /* 2.1: duplicate registers */
91 ctxThreadContext
.ContextFlags
=
92 CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
| CONTEXT_FLOATING_POINT
;
94 /* get the current thread's registers */
95 nErrCode
= NtGetContextThread(NtCurrentThread(), &ctxThreadContext
);
98 if(!NT_SUCCESS(nErrCode
))
100 ERR("NtGetContextThread() failed with status 0x%08X\n", nErrCode
);
101 goto cleanup_and_fail
;
104 /* redirect the child process to the child_branch label (see 4.3 below) */
105 ctxThreadContext
.Eip
= (ULONG
)&&child_branch
;
107 /* 2.2: duplicate stack */
108 /* get stack base and size */
109 nErrCode
= NtQueryVirtualMemory
112 (PVOID
)ctxThreadContext
.Esp
,
113 MemoryBasicInformation
,
115 sizeof(mbiStackInfo
),
120 if(!NT_SUCCESS(nErrCode
))
122 ERR("NtQueryVirtualMemory() failed with status 0x%08X\n", nErrCode
);
123 goto cleanup_and_fail
;
126 itInitialTeb
.StackCommit
= 0;
127 itInitialTeb
.StackReserve
= 0;
128 itInitialTeb
.StackBase
= (PVOID
)((ULONG
)(mbiStackInfo
.BaseAddress
) + mbiStackInfo
.RegionSize
);
129 itInitialTeb
.StackLimit
= mbiStackInfo
.BaseAddress
;
130 itInitialTeb
.StackAllocate
= mbiStackInfo
.AllocationBase
;
132 /* 2.3: create duplicate thread */
133 nErrCode
= NtCreateThread
139 (CLIENT_ID
*)&ciClientId
,
146 if(!NT_SUCCESS(nErrCode
))
148 ERR("NtCreateThread() failed with status 0x%08X\n", nErrCode
);
149 goto cleanup_and_fail
;
152 /* 2.4: duplicate the TEB */
153 /* store the client id in the child thread's stack (see 4.3b) */
154 nErrCode
= NtWriteVirtualMemory
164 if(!NT_SUCCESS(nErrCode
))
166 ERR("NtWriteVirtualMemory() failed with status 0x%08X\n", nErrCode
);
167 goto cleanup_and_fail
;
170 /* get the child thread's TEB base */
171 nErrCode
= NtQueryInformationThread
174 ThreadBasicInformation
,
176 sizeof(tbiThreadInfo
),
181 if(!NT_SUCCESS(nErrCode
))
183 ERR("NtQueryInformationThread() failed with status 0x%08X\n", nErrCode
);
184 goto cleanup_and_fail
;
188 nErrCode
= NtWriteVirtualMemory
191 tbiThreadInfo
.TebBaseAddress
,
198 if(!NT_SUCCESS(nErrCode
))
200 ERR("NtWriteVirtualMemory() failed with status 0x%08X\n", nErrCode
);
201 goto cleanup_and_fail
;
204 /* STEP 3: Call Win32 subsystem */
205 memset(&csrmsg
, 0, sizeof(csrmsg
));
207 csrmsg
.ProcessInformation
.hProcess
= hProcess
;
208 csrmsg
.ProcessInformation
.hThread
= hThread
;
209 csrmsg
.ProcessInformation
.dwProcessId
= (DWORD
)ciClientId
.UniqueProcess
;
210 csrmsg
.ProcessInformation
.dwThreadId
= (DWORD
)ciClientId
.UniqueThread
;
212 nErrCode
= CsrClientCallServer(&csrmsg
, 0, 0x10000, 0x24);
215 if(!NT_SUCCESS(nErrCode
))
217 ERR("CsrClientCallServer() failed with status 0x%08X\n", nErrCode
);
218 goto cleanup_and_fail
;
221 /* STEP 4: Finalization */
222 /* 4.1: resume thread */
223 nErrCode
= NtResumeThread(hThread
, 0);
225 /* 4.2: close superfluous handles */
229 /* 4.3: (parent) return the child process id */
230 return ((pid_t
)(ciClientId
.UniqueProcess
));
232 /* 4.3b: (child) cleanup and return 0 */
234 /* restore the thread and process id in the TEB */
235 memcpy(&NtCurrentTeb()->Cid
, &ciClientId
, sizeof(ciClientId
));
241 NtTerminateProcess(hProcess
, nErrCode
);
244 errno
= __status_to_errno(nErrCode
);