Subject: fork2
From: [email-masked] (root)

14 Nov 1997 03:30:16 -0800
Message-ID: <[email-masked]>
Content-Type: text
To: [email-masked]

Chris Faylor wrote:

Here's my start at a new fork implementation:

    static _USERENTRY fork2(void *);
    int fork()
    {
        _beginthread(fork2, 4096, NULL);
        return 0;
    }
    static _USERENTRY fork2(void *nada)
    {
        copy_stack_from_parent();
        set_new_process_id();
        reset_process_start_time();
        copy_heap();
        reset_heap_pointer();
        copy_globals();
        copy_statics();
        set_new_data_segment_ptr();
        copy_fds();
        isolate_scheduling_from_parent();
        isolate_signals_from_parent();
        clear_pending_alarms();
        isolate_interval_timers_from_parent();        
        clear_interval_timers();
        set_stack_pointer_from_parent();        // never returns
    }

There are still a few trivial functions left unimplemented, but, as I'm
very busy right now, I'll leave them to the other CYGWIN gurus to write.
------------------------------------------------------------------------
Well, I think Chris has done a fairly good description of what needs to be
done. Here is a list of further trivial details:

1) Copy stack.
   If the new thread is started with the 'suspended attribute', we could get
   the size of the stack using the MemoryBasicInformation call,using a stack
   page from the parent. Usig that information, it would be easy to first
   extend the stack from 4096 to whatever size it has, if necessary, and then
   memcpy from the source to the destination. Then we could use the Context
   structure to set the stack of the suspended new thread to point to TOS.
   Trivial.
2) SetNewProcessId() and resetProcessStartTime() are not very difficult either.

3) CopyHeap should do the same thing as CopyStack. Using the VirtualQuery
   function, we should get a list of all heap pages allocated by the program 
   so far. Then, using VirtualAlloc, we should copy them to the new thread.

   Then, and this is one of the easiest parts of all this, we should read the
   .reloc information from the executable, to modify ALL POINTERS in the new
   process, so that they point to the new copied pages instead of the old ones.

   The same would have to be done for all local variables in the copied stack.
   When we find a reference to the old stack, we should  translate it to the
   new one. Since there is no .reloc info for the stack, we should write
   a little device driver that changes the virtual attributes of the stack
   pages to point to the new ones, in the context of the new process, instead
   of pointing to the old addresses. A fairly trivial undertaking, since
   gurus surely have the source code of windows NT available to them. (If not, 
   they wouldn't be gurus... -:)

4) CopyStatics() is done automatically by CopyHeap above.

5) ResetHeapPointer is just a matter of making the new heap pointer in the
   suspended thread point to the end of the pages copied by CopyHeap. If there
   is no debug info (symbol table etc), we could still see in which page of the
   heap the old heap pointer is. Since we have just copied it, we could determine
   which page/offset the new heap pointer has, and modify that piece of data
   using using the debug help primitives. Debuggers do this routinely to set
   the value of a variable when the debuggee is suspended.

6) SetNewDataSegmentPtr() is kind of redundant. Whatis the difference between
   the heap pointer and the data segment pointer? If this pointer just points
   to the base of the heap, it would be easy to set it up to point to the base
   of the pages just allocated by CopyHeap.

7) Copyfds(). I suppose that this means copy file descriptors. This is not
   really necessary since they reside either in the stack or the heap, so
   they are already copied.

8) Isolate scheduling from parent. This is impossible with this implementation, 
   since we have started a new thread, and NOT a new process.
   The best thing to do, is to make the new thread launch a new process,
   stop that process as it starts, make the copying, and letting it loose.
   This doesn't change the procedures above, but would allow that the child
   traps without stopping the parent, and the opposite: the parent could trap
   without stopping the child.

9) Isolate signals from parent. This would be done automatically if we start a
   new process. If not, we would have to setup a fairly elaborate trap handling
   mechanism...

All this is very easy, as everybody in this list can see. Debugging it wouldn't
be necessary, since gurus do not make mistakes. But since there could be some
low level people that do make mistakes, they could use mtgdb (the new multi
threading gdb), that has to be written prior to doing anything like this...:-)

But I have a better solution:
Why run Unix under a non-Unix system?
Why re-invent Unix's wheels so that other OSes that lack those wheels can run?

I have used Unix since a long time, and the attempts to make other systems
'Unix like' are fairly pointless. There will be always something that will not
work right. Windows is not Unix. If you want all the above already up and
running, spend US$30, get the latest Slackware and run the *real* thing.

There isn't a better Unix emulator than Unix itself.

-- 
Jacob Navia	Logiciels/Informatique
41 rue Maurice Ravel			Tel 01 48.23.51.44
93430 Villetaneuse 			Fax 01 48.23.95.39
France
-
For help on using this list (especially unsubscribing), send a message to
"[email-masked]" with one line of text: "help".