How to implement a system call fork ()?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
gapry
Posts: 10
Joined: Sat Aug 25, 2012 7:42 pm

How to implement a system call fork ()?

Post by gapry »

As we know, every process will call fork () in Linux. It will return 0 or 1 as normal or -1 to represent error. But, I don't know how to make a variable that can have two values at the same time. Can you give me some hits to help me to implement it?
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: How to implement a system call fork ()?

Post by Combuster »

gapry wrote:It will return 0 or 1
Nope.

If you look up what it really does, it might also give you a clue as to how it did it.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: How to implement a system call fork ()?

Post by pcmattman »

I recommend you read the specification for fork...
  • fork() returns 0 in the 'child' process.
  • fork() returns the PID of the child process in the 'parent' process (NOT simply 1).
  • fork() returns -1 if an error occurs while forking.
There's no need for a variable to have two values at the same time; fork() returns one thing in the parent address space, and another in the other address space.

I think some more reading is necessary, the link I provided should clear things up.
User avatar
sortie
Member
Member
Posts: 931
Joined: Wed Mar 21, 2012 3:01 pm
Libera.chat IRC: sortie

Re: How to implement a system call fork ()?

Post by sortie »

The important part to understand is that fork() creates a copy of the current process, assuming there only is a single thread in the process (the one calling fork). This is how it works:
  • Allocate a new process structure, this is the child process.
  • Allocate a new address space for use by the child process and map the kernel in it, too.
  • Iterate over all the user-space memory mappings of the parent process and map new memory at the same location in the child process and copy the data so each address space is identical.
  • Copy other miscellaneous process attributes into the child process, such as signal handlers. Note that a perfect copy is not made, for instance any pending signals is not pending in the child process.
  • Allocate a new thread structure associated with the child process, this is the child thread.
  • Locate where the system call will return to and set the registers of the child thread so it resumes execution there (making a copy of the original thread) except the register containing the system call result is zero (marking it as the child).
  • Mark the child thread as runnable, the current process has now been forked.
  • Return the pid of the child process (marking the parent thread as such).
If there are multiple threads in the current process, they are not copied as well, only the current thread. You can think of it as a primitive that creates a copy of the current thread (except the return value) in a new thread in a mostly identical process. Of course, you return -1 and undo the current work if this fails at any point.

Naturally, you can speed things up using copy-on-write where the address space contents is not copied until it is written to in any of the two thread. This is somewhat complicated and I recommend against doing it in your first OS until you got a basic fork working, you don't need this optimization for a long while anyway in my experience (I still don't have it). Keep in mind that in many cases, you don't actually do a full copy, such as mmap'd shared files and all that. There's a heap of special cases you'll want to get to eventually.

My kernel doesn't have a fork() system call as such, I have a more general thread_create() system call that creates a thread with the given registers in potentially a new thread. A user-space fork() fills in the registers desired for the new thread (identical, except a single value) and creates that thread in a cloned process, this gives the same result but with a stronger primitive. Linux does the same with the clone() system call, though mine is better designed.

I suspect you don't know paging well, you'll want to do that.
Post Reply