fork() on windows

Started by
7 comments, last by jumpjumpjump 18 years, 4 months ago
I know fork() isn't available on windows, but does anyone know a library/wrapper that allows me to do this? I'm currently working on a simple httpd that, as of right now, runs on linux, bsd, skyos, and probably BeOS/Zeta. My goal is to only have to change the socket code to work with winsock when I go to compile on Windows, so hence my question. I'm also open to someone telling my how I would write a fork() that would use win32 process system. Thanks, Code
Advertisement
Have you looked at cygwin?

Here's a few references:

A road map to porting shared memory, process management, and semaphore calls from Unix to Windows NT
Port from UNIX to Win32
Win32 Assembly Components (pdf) contains an algorithm for a simply fork under Win32.

"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
There is no easy way of emulating fork() on win32.

I believe that cygwin does it sort of, in a very cludgy way, which is extremely slow.

You probably want to look at refactoring your program to use threads on win32 (could on Unix as well).

But threads are definitely not the same as fork().

A forked process can basically do whatever it wants without problems, including closing file descriptors, which are just copies of the parent's.

But a thread is equivalent to its parent, and if it closes a file, the file will be closed in the original thread too.

Mark
It really depends on how fork is used. If you could describe the idea behind what fork() is doing in your code, it is likely you could rework your code slightly and have a single small file that defines a function or two differently for windows and other operating systems.

If you _really_ needed it, it might be possible to create a function that is virtually identical to fork(), but it would probably require a herculean effort

[Edited by - Extrarius on November 26, 2005 3:51:37 AM]
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk
The simple approach is to use CreateProcess to spawn a new process, but that would only work efficiently for a small number of additional processes. It also might not work as expected because under Windows each process gets it's own address space - and from what I gather - under Unix, forks are able to access the address space of the spawning program. That's more akin to a thread under win32. Since you're talking about using winsock and presumeably may want to use fork to pass off client or server sockets to new processes, CreateProcess probably isn't the best approach to use. In fact, if that is what you want to do then CreateProcess is a very bad way to approach the problem. You'll want to use threads or fibers instead.
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
What fork() does in Unix is not akin to either a Win32 thread or process. It's something which win32 simply doesn't have - that's why it's so tricky.

When you call fork(), one process becomes two. The old process gets the PID of the new process, then continues to do whatever it was doing.

The new process contains a copy of the old process's virtual memory, including the stack and mapped areas. The CPU context is also copied, therefore, the child process returns from the fork() system call just as the parent did - except that it's a new process. fork() returns 0 to the child process (which is how it can tell it's the child process).

The memory is all *copied* (Well, actually probably implemented using copy-on-write) except for shared maps, which are obviously still shared, as they would be between unrelated processes.

The processes can work independently, and don't affect each others' memory.

All file descriptors are copied, and are available to both processes, but they are real independent file descriptors, i.e. both processes can independently close them, seek them etc. This includes all types of socket, IPC etc.

It's normal for a child process to close lots of files immediately after fork() - because you can't stop them from being inherited (unlike exec), so the child needs to close unnecessary ones.

Mark
Quote:Original post by LessBread
The simple approach is to use CreateProcess to spawn a new process, but that would only work efficiently for a small number of additional processes. It also might not work as expected because under Windows each process gets it's own address space - and from what I gather - under Unix, forks are able to access the address space of the spawning program. That's more akin to a thread under win32.


That's wrong.

Calling fork() in unix creates a copy of that process (the whole address space including code, data, stack, file descriptors, threads and so on). The forked process has its own address space. It's an identical copy of the former one, only the return value of fork() decides which one was the parent and which one the child process. It's not like creating a thread.
It's really like CreateProcess() but with a sligth difference. In Windows CreateProcess() starts execution of that process from the beginning, but in unix fork() starts execution after the point fork() was called. Since there is no equivalent function for fork() in windows, thats hard to emulate.

In some cases fork() is followed by exec() to start another program (i.e. a shell does this). This way you can easily replace fork/exec by CreateProcess to get the same effect. Take care of file descriptors in this case.
The underlying API in Windows NT is certainly capable of performing a "fork", the POSIX subsystem uses this functionality to implement a fork() system call. However, this is not exposed by the Win32 API (which merely exposes CreateProcess).

So, you need to bypass Win32 and call the native API ({Nt|Zw}CreateProcess). The book "Windows Nt/2000 Native Api Reference" has an example "Forking a Win32 Process". This may be what you need. Also see this.

[Edited by - bakery2k1 on November 26, 2005 9:43:47 AM]
I think I've changed my design. Instead of forking, I'm going to have a queue of requests. One thread will receive the connections and insert them into the queue, another will send data and close the connect, then remove from the queue.

This way is definately more portable and is better overall, in my oppinion.

Thanks for the help though.

This topic is closed to new replies.

Advertisement