Using Process.spawn as a replacement for Process.fork

EDIT: There is one common use case of fork() that can be replaced with spawn() — the fork()exec() combo. A lot of older (and modern) UNIX applications, when they want to spawn another process, will first fork, and then make an exec call (exec replaces the current process with another). This doesn’t actually need fork(), which is why it can be replaced with spawn(). So, this:

if(!fork())
  exec("dir")
end

can be replaced with:

Process.spawn("dir")

If any of the gems are using fork() like this, the fix is easy. Otherwise, it is almost impossible.


EDIT: The reason why win32-process’ implementation of fork() doesn’t work is that (as far as I can tell from the docs), it basically is spawn(), which isn’t fork() at all.


No, I don’t think it can be done. You see, Process.spawn creates a new process with the default blank state and native code. So, while I can do something like Process.spawn('dir') will start a new, blank process running dir, it won’t clone any of the current process’ state. It’s only connection to your program is the parent – child connection.

You see, fork() is a very low level call. For example, on Linux, what fork() basically does is this: first, a new process is created with exactly cloned register state. Then, Linux does a copy-on-write reference to all of the parent process’ pages. Linux then clones some other process flags. Obviously, all of these operations can only be done by the kernel, and the Windows kernel doesn’t have the facilities to do that (and can’t be patched to either).

Technically, only native programs need the OS for some sort of fork()-like support. Any layer of code needs the cooperation of the layer above it to do something like fork(). So while native C code needs the cooperation of the kernel to fork, Ruby theoretically only needs the cooperation of the interpreter to do a fork. However, the Ruby interpreter does not have a snapshot/restore feature, which would be necessarily to implement a fork. Because of this, normal Ruby fork is achieved by forking the interpreter itself, not the Ruby program.

So, while if you could patch the Ruby interpreter to add a stop/start and snapshot/restore feature, you could do it, but otherwise? I don’t think so.

So what are your options? This is what I can think of:

  • Patch the Ruby interpreter
  • Patch the code that uses fork() to maybe use threads or spawn
  • Get a UNIX (I suggest this one)
  • Use Cygwin

Edit 1:
I wouldn’t suggest using Cygwin’s fork, as it involves special Cygwin process tables, there is no copy-on-write, which makes it very inefficient. Also, it involves a lot of jumping back and forth and a lot of copying. Avoid it if possible. Also, because Windows provides no facilities to copy address spaces, forks are very likely to fail, and will quite a lot of the time (see here).

Leave a Comment