I'm new to multiprocess programming, but I know that if I fork an X program, the X connections "get duplicated", so the forked process shares the same window/etc as its parent... I'm wondering if programs compiled with Gambit can be cleanly forked, with the child and parent being completely separate.
tj
Afficher les réponses par date
At 18:13 Uhr +0800 29.07.2006, TJay wrote:
I'm new to multiprocess programming, but I know that if I fork an X program, the X connections "get duplicated", so the forked process shares the same window/etc as its parent...
There are, on unix, two ways to dispose of file descriptors in children: a) call fcntl with the close-on-exec flag, b) close the file descriptors explicitly using close.
Obviously the former will only help you if you later call exec, not if you want to only fork and have the fd closed in the child.
I'm wondering if programs compiled with Gambit can be cleanly forked, with the child and parent being completely separate.
I remember that Gambit closes filehandles if you call open-process. But that does not only a fork, it also exec's. My question is, how did you want to fork your child in the first place?
If you're using the C interface, you could probably just as well call close on all fd's which are not of your interest. (A way to do that (which some unix programs employ) is to just call close on all numbers from 3 to 1023 or something like that, of course that's not safe if there are more files open.)
I think you could wrap the gambit open functions so that you record their fd (or the port) in a global data structure (a weak table in the case of a port), register a release function which removes the entry again (and a wrapper around close-port doing the same), and upon fork call close on all recorded open fd's.
Maybe you should describe what you want to do in more detail, I can't imagine why you want that functionality from the top of my head except that you might have run into problems with multiple threads continuing to run in the child or with non-written buffers being flushed twice.
Christian.
# Christian 2006-07-30:
At 18:13 Uhr +0800 29.07.2006, TJay wrote:
I'm wondering if programs compiled with Gambit can be cleanly forked, with the child and parent being completely separate.
I remember that Gambit closes filehandles if you call open-process. But that does not only a fork, it also exec's. My question is, how did you want to fork your child in the first place?
If you're using the C interface, you could probably just as well call close on all fd's which are not of your interest. (A way to do that (which some unix programs employ) is to just call close on all numbers from 3 to 1023 or something like that, of course that's not safe if there are more files open.)
fcntl(3, F_CLOSEM) or somesuch will do, on some unices.
-- Jachym
I wasn't thinking about file descriptors in particular. I was wondering whether gambit itself has any internal state that's not friendly with fork(). (I have no idea what these states might include.)
Christian 2006-07-30:
Maybe you should describe what you want to do in more detail, I can't imagine why you want that functionality from the top of my head except that you might have run into problems with multiple threads continuing to run in the child or with non-written buffers being flushed twice.
I want to write a program that loads a bunch of plugins at startup. Each of those plugins can handle one task (from the user's perspective). The programs forks then calls the appropriate plugin's procedure when the user selects a task.
<Task-chooser process> (GUI) | <Parent process>--<data server process> / | \ <Fork> <Fork> <Fork> (GUI)
At startup, the parent process loads everything, plugins, etc. Then it forks and opens a window for the user to choose what he wants to do (<task-chooser process>). The task chooser process will tell the parent process to fork and call the appropriate procedure when the user chooses a task (<fork>). The data server process stores all data and passes them along pipes to the processes that are interested.
The reasons I want to do things this way are: 1) The library I'm using for opening windows does not support multiple windows. (I only open a window after forking, the parent process does not have a window open.) 2) Plugins won't bring the user's data with them when they crash.
tj
At 1:04 Uhr +0800 31.07.2006, TJay wrote:
I wasn't thinking about file descriptors in particular. I was wondering whether gambit itself has any internal state that's not friendly with fork(). (I have no idea what these states might include.)
I think I've already given my non-authoritative answer (just a guess): if you have multiple gambit threads running, then call fork, both processes will continue running all the threads, and if you print some stuff to buffered ports but do not flush nor close (through the POSIX call) them, you'll get output being printed twice. I don't know how I would handle the former problem (I think there's no place where Gambit is doing this already; the only place where Gambit calls fork is in implements ___device_stream_setup_from_process in os_io.c and there is no need to shut down other threads as exec is called immediately).
The reasons I want to do things this way are:
- The library I'm using for opening windows does not support multiple
windows. (I only open a window after forking, the parent process does not have a window open.) 2) Plugins won't bring the user's data with them when they crash.
You probably just need this functionality:
- create bindings to the following POSIX functions: fork, pipe, close. - call pipe the necessary number of times, then fork, then close on those pipe ends you don't need in the children/parents, then turn the fd numbers into Gambit ports using the recipy given by Marc a few days ago. - forget about threads if you don't start any in the parents, and forget about open ports as long as you don't write data to buffered ports without calling force-output before calling fork, and as long as you don't need to close them in all processes so as to make the receiver get an EOF (pipes). Or just remember to call close-port on those which really need to be closed.
BTW using fork as opposed to starting subprocesses using open-process will probably not give you much of an advantage, if you load all code as compiled shared libraries, since almost all shareable memory will then be shared anyway, and you don't seem to want to fork chilren at a high frequency.
Christian.