[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Non-blocking fork (never again :-)



Hi folks,

here is a set of patches for FreeMiNT, that will give an end to the
"... until MiNT has a non-blocking fork" story. With these patches
MiNT's Pfork call will now finally work like a standard Un*x fork (well,
mostly :-). You now can write daemons by forking a child process and
exit from the parent, and you may as well run both, parent and child
asychronously. (Using MiNT's threads will be more efficient in the
latter case). You now may even unpack shell archives using the shell
directly (this was one of the cases where MiNT's blocking fork got
always in my ways ...).

The patch is working stable for my setup now for nearly a month (your
mileage may vary :-). It does not require a PMMU and will run on a
vanilla ST. The memory protection stuff should be ok, but
I haven't tested it (sorry, I still have only a good old MegaSTE :-).
The patch is after my signature below. I have gzipped and uuencode the
patch file to save some network bandwidth (the patch file has 1k
lines). To apply is simply uudecode this fail, ungzip the resulting
patch.gz file and run patch on it from your MiNT source directory.


For the technically interested, here is an outline of how it works
(nothing is very new about this; it just a long now technique, which
e.g. Minix ST uses, called shadowing):
- At the time of a Pfork() call, the parents memory is saved into a set
of save regions. (In contrast to the unpatched (Free)MiNT, which creates
only one save region for the forked process, my patch creates a save
region for each memory region. This makes it easier for the parent or
child process to release some of its memory regions after the fork.) 
- At the time of a context switch the kernel will look at each memory
region attached to the process becoming current and check whether its
memory is swapped out into a save region. If this is the case the
contents of the "real" region and the save region are exchanged,
otherwise nothing will be done. Thus there will be not much overhead
for non-forked process.

The changes affect the following files:

- mem.h:
	Added two new fields `save' and `shadow' to the memory region
	descriptor.
	The `shadow' field is 0, except if the region has been
	duplicated due to a fork; in that all regions mapping to the
	same "real" memory region, are linked in a ring using the this
	field.
	The `save' field will point to the memory region into which
	the contents of the memory region has been swapped out (if at
	all). Inside a `shadow' ring, at all times only one region
	will have `save' field which is 0.
	Also added a new flags M_SHARED which is used to mark shared
	memory regions.

- dosmem.c, proto.h:
  	I have split the `do_fork' function into to separate functions
	`p_vfork' and `p_fork'. They do not have much in common any
	longer.
	The `fork_restore' function is not needed any more.

- proc.c:
  	Added a new function `swap_in_curproc', which is called when a
	process returns from a sleep and swaps in all memory regions
	of the process that have been saved.

- mem.c, proto.h:
  	The new function `fork_region' actually duplicates a memory
	region. It is used in `p_fork' to save the parent's memory.
	For its argument it will create a new memory region
	descriptor, which is linked into the shadow ring of the region
	and which will be attached to the child process, and a save
	region into which the contents of the region is duplicated.
	When a region is freed, `free_region' will check for the
	existence of any regions which are attached to the same "real"
	memory as the freed region, and free a save region instead of
	the real region in that case.
	`Exec_region' and `max_rsize' correctly take the save regions
	into account.
	Finally `sanity_check' checks some more invariants which
	should hold on the `shadow' ring and the save regions.

- quickswa.spp, sproto.h, makefile:
  	This is a new file containing only the single function
	`quickswap'. This function, that is derived from `quickmove'
	is used to exchange the contents of a memory region and its
	save region.

- shmfs.c:
  	Memory regions that are advertised in the shared memory
	filesystem are not duplicated during a fork, i.e., the child
	automatically inherits the parent's memory in that case. To
	distinguish these shared memory regions from memory regions
	which have more than one link and which must be saved (e.g. if
	a process vforks and the child executes a fork) they are now
	explicitly flagged as M_SHARED.
	The shared memory filesystem also refrains to advertise memory
	regions which have a non-zero shadow ring. This was introduced
	to avoid the case where a process, which has already forked,
	exports a memory region via the shared memory filesystem and
	the other process of the fork trying to import this region
	then (which would lead to two different regions using the same
	memory in the same process). A less restrictive solution would
	be to avoid the import in the above case instead of the
	export, but the chosen solution was easier to implement (and
	actually I expect such a situation to be to rare to really
	bother :-).

- procfs.c:
  	This is the only part of the patch, which I still consider
	experimental: The `proc_read' and `proc_write' functions have
	been rewritten, so that they read from or write to the save
	region if a region has been swapped out. However this is more
	restrictive than the original code, as it will work only on
	memory regions that are attached to the process. You can no
	longer read/write memory from the process' address space,
	which is not attached to the process, e.g., memory regions
	marked with global memory protection. I'm not sure whether
	the new behaviour should be considered as a bug or a feature,
	so I left the old code in (you can get it back by defining the
	preprocessor symbol OLD_PROC_RW), but remember this code
	really buggy: it will always work on the "real" memory region,
	even if the process actual image has been swapped out.
	So, has anybody a better solution to this?


Happy forking,
Wolfgang

----
Wolfgang Lux			        #include <stddisclaimer>
WZH Heidelberg, IBM Germany             Internet: lux@heidelbg.ibm.com
+49-6221-59-4546                        VNET:     LUX at HEIDELBG
+49-6221-59-3200 (fax)	                EARN:     LUX at DHDIBMIP


begin 644 patch.gz
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
3),U6)`2D3DGI^"_TA@R*P8\``&B%
`
end