Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*$Header: /p/tcsh/cvsroot/tcsh/win32/fork.c,v 1.11 2008/08/31 14:09:01 amold Exp $*/
- /*-
- * Copyright (c) 1980, 1991 The Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
- /*
- * The fork() here is based on the ideas used by cygwin
- * -amol
- *
- */
- /*
- * _M_ALPHA changes by Mark Tucker
- */
- #ifdef BUFSIZE
- # if BUFSIZE < 4096
- # undef BUFSIZE
- # define BUFSIZE 4096 /* buffer size should be no less than this */
- # endif
- #else
- # define BUFSIZE 4096
- #endif /* BUFSIZE */
- #define FORKSLEEP 10 /* delay loop on non-interactive fork failure */
- #define MAILINTVL 600 /* 10 minutes */
- #ifndef INBUFSIZE
- # define INBUFSIZE 2*BUFSIZE /* Num input characters on the command line */
- #endif /* INBUFSIZE */
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #include <fcntl.h>
- #include <io.h>
- #include <stdlib.h>
- #include <setjmp.h>
- #include <ntport.h>
- #include "forkdata.h"
- //#include "sh.h"
- #pragma intrinsic("memcpy", "memset","memcmp")
- #pragma warning(push,3) // forget about W4 here
- typedef unsigned long u_long;
- typedef void *ptr_t;
- typedef unsigned char U_char;
- typedef unsigned int U_int;
- typedef unsigned short U_short;
- typedef unsigned long U_long;
- static void stack_probe(void *ptr) ;
- /*static void heap_init(void);*/
- BOOL CreateWow64Events(DWORD , HANDLE *, HANDLE *, BOOL);
- //
- // This is exported from the user program.
- // It must return 0 for no error !!!!
- extern int fork_copy_user_mem(HANDLE );
- /*
- * Apparently , visual c++ on the alpha does not place the
- * fork data contiguously. To work around that, Mark created
- * this structure (see forkdata.h)
- * -amol
- */
- ForkData gForkData = {0,0,0,0,0,{0},0,0,0};
- #ifdef _M_IX86
- u_long _old_exr = 0; // Saved exception registration for longjmp
- #endif // _M_ALPHA
- /*
- * This hack is an attempt at getting to the exception registration
- * in an architecture-independent way. It's critical for longjmp in a
- * code using __try/__except blocks. Microsoft Visual C++ does a global
- * unwind during a longjmp, and that can cause havoc if the exception
- * registration stored in longjmp is lower(address wise, indicating a jump
- * from below of the stack upward.) in the stack than the current
- * registration (returned by NtCurrentTeb).
- *
- * This works with VC++, because that's all I have. With other compilers,
- * there might be minimal changes required, depending on where the
- * exception registration record is stored in the longjmp structure.
- *
- * -amol 2/6/97
- */
- NT_TIB * (* myNtCurrentTeb)(void);
- #define GETEXCEPTIONREGIST() (((NT_TIB*)get_teb())->ExceptionList)
- #define GETSTACKBASE() (((NT_TIB*)get_teb())->StackBase)
- static NT_TIB *the_tib;
- #if !defined(_M_IA64) && !defined(_M_AMD64)
- void *get_teb(void) {
- if (the_tib)
- return the_tib;
- myNtCurrentTeb = (void*)GetProcAddress(LoadLibrary("ntdll.dll"),
- "NtCurrentTeb");
- if (!myNtCurrentTeb)
- return NULL;
- the_tib = myNtCurrentTeb();
- if (the_tib == NULL)
- abort();
- return the_tib;
- }
- #else
- #define get_teb NtCurrentTeb
- #endif _M_IA64
- void set_stackbase(void*ptr){
- GETSTACKBASE() = ptr;
- }
- /*
- * This must be called by the application as the first thing it does.
- * -amol 2/6/97
- *
- * Well, maybe not the FIRST..
- * -amol 11/10/97
- */
- extern BOOL bIsWow64Process;
- int fork_init(void) {
- //heap_init(); Now called as the very first thing in silly_entry().
- if (__forked) {
- // stack_probe probes out a decent-sized stack for the child,
- // since initially it has a very small stack (1 page).
- //
- /* not needed since default commit is set to 0.5MB in
- * makefile.win32
- *
- * stack_probe((char *)__fork_stack_end - 64);
- */
- //
- // Save the old Exception registration record and jump
- // off the cliff.
- //
- #ifdef _M_IX86
- _old_exr = __fork_context[6];
- __fork_context[6] =(int)GETEXCEPTIONREGIST();//tmp;
- #endif _M_ALPHA
- //
- // Whee !
- longjmp(__fork_context,1);
- }
- return 0;
- }
- int fork(void) {
- size_t rc;
- size_t stacksize;
- char modname[512];/*FIXBUF*/
- HANDLE hProc,hThread, hArray[2];
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
- SECURITY_ATTRIBUTES sa;
- DWORD dwCreationflags;
- unsigned int priority;
- HANDLE h64Parent,h64Child;
- #ifndef _M_ALPHA
- unsigned long fork_stack_end;
- #endif _M_ALPHA
- __fork_stack_begin =GETSTACKBASE();
- #ifndef _M_ALPHA
- __fork_stack_end = &fork_stack_end;
- #else
- __fork_stack_end = (unsigned long *)__asm("mov $sp, $0");
- #endif /*_M_ALPHA*/
- h64Parent = h64Child = NULL;
- //
- // Create two inheritable events
- //
- sa.nLength = sizeof(sa);
- sa.lpSecurityDescriptor =0;
- sa.bInheritHandle = TRUE;
- if (!__hforkchild)
- __hforkchild = CreateEvent(&sa,TRUE,FALSE,NULL);
- if (!__hforkparent)
- __hforkparent = CreateEvent(&sa,TRUE,FALSE,NULL);
- rc = setjmp(__fork_context);
- if (rc) { // child
- #ifdef _M_IX86
- //
- // Restore old registration
- // -amol 2/2/97
- GETEXCEPTIONREGIST() = (struct _EXCEPTION_REGISTRATION_RECORD*)_old_exr;
- #endif // _M_ALPHA
- SetEvent(__hforkchild);
- dprintf("Child ready to rumble\n");
- if(WaitForSingleObject(__hforkparent,FORK_TIMEOUT) != WAIT_OBJECT_0)
- ExitProcess(0xFFFF);
- CloseHandle(__hforkchild);
- CloseHandle(__hforkparent);
- __hforkchild = __hforkparent=0;
- //__asm { int 3};
- restore_fds();
- STR_environ = blk2short(environ);
- environ = short2blk(STR_environ); /* So that we can free it */
- return 0;
- }
- copy_fds();
- memset(&si,0,sizeof(si));
- si.cb= sizeof(si);
- /*
- * This f!@#!@% function returns the old value even if the std handles
- * have been closed.
- * Skip this step, since we know tcsh will do the right thing later.
- *
- si.hStdInput= GetStdHandle(STD_INPUT_HANDLE);
- si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
- si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
- */
- if (!GetModuleFileName(GetModuleHandle(NULL),modname,512) ) {
- rc = GetLastError();
- return -1;
- }
- dwCreationflags = GetPriorityClass(GetCurrentProcess());
- priority = GetThreadPriority(GetCurrentThread());
- rc = CreateProcess(NULL,
- modname,
- NULL,
- NULL,
- TRUE,
- CREATE_SUSPENDED | dwCreationflags,
- NULL,
- NULL,
- &si,
- &pi);
- if (!rc) {
- rc = GetLastError();
- return -1;
- }
- ResetEvent(__hforkchild);
- ResetEvent(__hforkparent);
- hProc = pi.hProcess;
- hThread = pi.hThread;
- __forked=1;
- /*
- * Usage of events in the wow64 case:
- *
- * h64Parent : initially non-signalled
- * h64Child : initially non-signalled
- *
- * 1. Create the events, resume the child thread.
- * 2. Child opens h64Parent to see if it is a child process in wow64
- * 3. Child opens and sets h64Child to tell parent it's running. (This
- * step is needed because we can't copy to a process created in the
- * suspended state on wow64.)
- * 4. Copy gForkData and then set h64Parent. This tells the child
- * that the parameters in the structure are trustworthy.
- * 5. Wait for h64Child so that we know the child has created the stack
- * in dynamic memory.
- *
- * The rest of the fork hack should now proceed as in x86
- *
- */
- if (bIsWow64Process) {
- // allocate the heap for the child. this can be done even when
- // the child is suspended.
- // avoids inexplicable allocation failures in the child.
- if (VirtualAllocEx(hProc,
- __heap_base,
- __heap_size,
- MEM_RESERVE,
- PAGE_READWRITE) == NULL) {
- dprintf("virtual allocex failed %d\n",GetLastError());
- goto error;
- }
- if (VirtualAllocEx(hProc,
- __heap_base,
- __heap_size,
- MEM_COMMIT,
- PAGE_READWRITE) == NULL) {
- dprintf("virtual allocex2 failed %d\n",GetLastError());
- goto error;
- }
- // Do NOT expect existing events
- if (!CreateWow64Events(pi.dwProcessId,&h64Parent,&h64Child,FALSE)) {
- goto error;
- }
- ResumeThread(hThread);
- // wait for the child to tell us it is running
- //if (WaitForSingleObject(h64Child,FORK_TIMEOUT) != WAIT_OBJECT_0) {
- // rc = GetLastError();
- // goto error;
- //}
- hArray[0] = h64Child;
- hArray[1] = hProc;
- if (WaitForMultipleObjects(2,hArray,FALSE,FORK_TIMEOUT) !=
- WAIT_OBJECT_0){
- rc = GetLastError();
- goto error;
- }
- }
- //
- // Copy all the shared data
- //
- if (!WriteProcessMemory(hProc,&gForkData,&gForkData,
- sizeof(ForkData),&rc)) {
- goto error;
- }
- if (rc != sizeof(ForkData))
- goto error;
- if (!bIsWow64Process) {
- rc = ResumeThread(hThread);
- }
- // in the wow64 case, the child will be waiting on h64parent again.
- // set it, and then wait for h64child. This will mean the child has
- // a stack set up at the right location.
- else {
- SetEvent(h64Parent);
- hArray[0] = h64Child;
- hArray[1] = hProc;
- if (WaitForMultipleObjects(2,hArray,FALSE,FORK_TIMEOUT) !=
- WAIT_OBJECT_0){
- rc = GetLastError();
- goto error;
- }
- CloseHandle(h64Parent);
- CloseHandle(h64Child);
- h64Parent = h64Child = NULL;
- }
- //
- // Wait for the child to start and init itself.
- // The timeout is so that we don't wait too long
- //
- hArray[0] = __hforkchild;
- hArray[1] = hProc;
- if (WaitForMultipleObjects(2,hArray,FALSE,FORK_TIMEOUT) != WAIT_OBJECT_0){
- int err = GetLastError(); // For debugging purposes
- dprintf("wait failed err %d\n",err);
- goto error;
- }
- // Stop the child again and copy the stack and heap
- //
- SuspendThread(hThread);
- if (!SetThreadPriority(hThread,priority) ) {
- priority =GetLastError();
- }
- // stack
- stacksize = (char*)__fork_stack_begin - (char*)__fork_stack_end;
- if (!WriteProcessMemory(hProc,(char *)__fork_stack_end,
- (char *)__fork_stack_end,
- (u_long)stacksize,
- &rc)){
- goto error;
- }
- //
- // copy heap itself
- if (!WriteProcessMemory(hProc, (void*)__heap_base,(void*)__heap_base,
- (DWORD)((char*)__heap_top-(char*)__heap_base),
- &rc)){
- goto error;
- }
- rc = fork_copy_user_mem(hProc);
- if(rc) {
- goto error;
- }
- // Release the child.
- SetEvent(__hforkparent);
- rc = ResumeThread(hThread);
- __forked=0;
- dprintf("forked process %d\n",pi.dwProcessId);
- start_sigchild_thread(hProc,pi.dwProcessId);
- close_copied_fds();
- CloseHandle(hThread);
- //
- // return process id to parent.
- return pi.dwProcessId;
- error:
- __forked=0;
- SetEvent(__hforkparent);
- ResumeThread(hThread);
- CloseHandle(hProc);
- CloseHandle(hThread);
- if (h64Parent) {
- SetEvent(h64Parent); // don't let child block forever
- CloseHandle(h64Parent);
- }
- if (h64Child)
- CloseHandle(h64Child);
- return -1;
- }
- #pragma optimize("",off)
- // The damn optimizer will remove the recursion, resulting in an infinite
- // loop. -amol 4/17/97
- void stack_probe (void *ptr) {
- char buf[1000];
- int x;
- if (&x > (int *)ptr)
- stack_probe(ptr);
- (void)buf;
- }
- #pragma optimize("",on)
- //
- // This function basically reserves some heap space.
- // In the child it also commits the size committed in the parent.
- void heap_init(void) {
- char * temp;
- int err;
- if (__forked) {
- temp = (char *)VirtualAlloc((void*)__heap_base,__heap_size, MEM_RESERVE,
- PAGE_READWRITE);
- if (temp != (char*)__heap_base) {
- if (!temp){
- err = GetLastError();
- if (bIsWow64Process)
- ExitProcess(0);
- abort();
- }
- else
- __heap_base = temp;
- }
- if (!VirtualAlloc(__heap_base,(char*)__heap_top -(char*)__heap_base,
- MEM_COMMIT,PAGE_READWRITE)){
- err = GetLastError();
- if (bIsWow64Process)
- ExitProcess(0);
- abort();
- }
- temp = (char*)__heap_base;
- }
- else {
- SYSTEM_INFO sysinfo;
- GetSystemInfo(&sysinfo);
- __heap_size = sysinfo.dwPageSize * 1024;
- __heap_base = VirtualAlloc(0 , __heap_size,MEM_RESERVE|MEM_TOP_DOWN,
- PAGE_READWRITE);
- if (__heap_base == 0) {
- abort();
- }
- __heap_top = __heap_base;
- }
- }
- //
- // Implementation of sbrk() for the fmalloc family
- //
- void * sbrk(int delta) {
- void *retval;
- void *old_top=__heap_top;
- char *b = (char*)__heap_top;
- if (delta == 0)
- return __heap_top;
- if (delta > 0) {
- retval =VirtualAlloc((void*)__heap_top,delta,MEM_COMMIT,PAGE_READWRITE);
- if (retval == 0 )
- abort();
- b += delta;
- __heap_top = (void*)b;
- }
- else {
- retval = VirtualAlloc((void*)((char*)__heap_top - delta),
- delta,MEM_DECOMMIT, PAGE_READWRITE);
- if (retval == 0)
- abort();
- b -= delta;
- __heap_top = (void*)b;
- }
- return (void*) old_top;
- }
- /*
- * Semantics of CreateWow64Events
- *
- * Try to open the events even if bOpenExisting is FALSE. This will help
- * us detect name duplication.
- *
- * 1. If OpenEvent succeeds,and bOpenExisting is FALSE, fail.
- *
- * 2. If OpenEvent failed,and bOpenExisting is TRUE fail
- *
- * 3. else create the events anew
- *
- */
- #define TCSH_WOW64_PARENT_EVENT_NAME "tcsh-wow64-parent-event"
- #define TCSH_WOW64_CHILD_EVENT_NAME "tcsh-wow64-child-event"
- BOOL CreateWow64Events(DWORD pid, HANDLE *hParent, HANDLE *hChild,
- BOOL bOpenExisting) {
- SECURITY_ATTRIBUTES sa;
- char parentname[256],childname[256];
- *hParent = *hChild = NULL;
- // make darn sure they're not inherited
- sa.nLength = sizeof(sa);
- sa.lpSecurityDescriptor =0;
- sa.bInheritHandle = FALSE;
- //
- #pragma warning(disable:4995)
- // This event tells the child to hold for gForkData to be copied
- wsprintfA(parentname, "Local\\%d-%s",pid, TCSH_WOW64_PARENT_EVENT_NAME);
- wsprintfA(childname, "Local\\%d-%s",pid, TCSH_WOW64_CHILD_EVENT_NAME );
- #pragma warning(default:4995)
- *hParent = OpenEvent(EVENT_ALL_ACCESS,FALSE, parentname);
- if(*hParent) {
- if (bOpenExisting == FALSE) { // didn't expect to be a child process
- CloseHandle(*hParent);
- *hParent = NULL;
- return FALSE;
- }
- *hChild = OpenEvent(EVENT_ALL_ACCESS,FALSE, childname);
- if (!*hChild) {
- CloseHandle(*hParent);
- *hParent = NULL;
- return FALSE;
- }
- return TRUE;
- }
- else { //event does not exist
- if (bOpenExisting == TRUE)
- return FALSE;
- }
- *hParent = CreateEvent(&sa,FALSE,FALSE,parentname);
- if (!*hParent)
- return FALSE;
- *hChild = CreateEvent(&sa,FALSE,FALSE,childname);
- if (!*hChild){
- CloseHandle(*hParent);
- *hParent = NULL;
- return FALSE;
- }
- return TRUE;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement