[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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
M,(8I;(0PA4WY'ROZ)`H"%E(";,-`*#Y/]/S,)V-WB=^4$O'K$_6F4!
MT>[+3@2V_=2LG>)J!GXUM,=MJ`P-:R;].VHZ90P`*K9[.RE:5*>F1_LE;;9>
MW5)"DFY8L'NX9%!-KY_86-W]_8?>*>S$^'^[3.Z12,O+TU'R_NE\/9TZ"?11
M;O2KRCOXA,/Z5L@-H!Y)R>@TZP($!D7(+J<I08Q:'2E)84B4($MA$,J[51"%
M&+MS<"I>+)8?4U#+@:8NSM/)4%P?B7<SJ83GWC=$-^NG$_B"">3@S1#<>RJZ
MLNE(`TGK5DGZ'G,_G<(K@^>D22-QHB]`^K/=T06D=JT^X[D257I=M4V]LBPF
M%E]E1Z*+2:T8C0P?98%J@`!SAH)^#IB.10K)7":W<]6V"IRR>$W_Y>S\9:6G
M6PK/S"_9J`JLK*-I):ZMEGM!/ZQ43M'X*>LV+]OT,E(O90/,RZB.;T>Z*'5)
M$=Q7'O]]/`Y&$22MFH_D[U$H?\$7T\0HTDJ6>`(**]C75ZFL]'$;*P2:T-`\
M99K!-#E:52Z2<28YI$`E-_)GF'-D]=L$.XG,9[*F470X.G[:KQ_V6\$AM%12
M*WN);.1%U+&(:_U(]D26:$&EN)A;^[%L0#T6=J\DK:CU0TG+5=/WWVR>K0`(
MG.="-P3XN$7JL<N[/B>LOE4:2+:P))(2IL3"+1:W7;:-/%L@V<*62$K8$@NW
MV''=91M#7F67+9!L84LD)6R)A5OLI.6R;>;9`LD6MD12PI98N,6B>NCR;>7Y
M(HW-.,^724H8,Q.7<>Q)U7$!XSC>RCC>)%;,Q&7<\N2J7<"XU=[*N+5)L)B)
MR_C$DZR3`L8G]:V,3S:)%C-QUV_DR584YCDCT6;.3%*VA(F+MW,8Z8J!<S?C
M[!&0C#J0VT;(I\N(O@EI]A,2.:BZ"06OP+4Z6LB9P0\7^3L>MC`.N!@4P.`;
M4(S[4W"1T>:LJL=J`VX=]@=3%/8KDHSXAO:#"`X8B.-;#_X#!T`D#P#8ZF\S
MV.HC9T^';?P@L'9VV9;E8HEW\566I"N@5L=#IT+GB$JD#XEG)\HSSI4BQP9Q
MY$.*^<-Q)(^P.AU@V+A[;!R=8,LT6;(R($:#M`_A^S#C@]D$FAU;0TXG'QU!
MUAF$#3:,(F(T&`ZA?+TA^U&?6N<T376H'P@ZA^#Q@:&2C.`QC()4I[Z\=`7Z
M!&,A&V&ZP<./![XR!IF>4*<[[FB%NXP6#=9%73=XX#=X4-3@0;[!H6RPK$DU
3),U6)`2D3DGI^"_TA@R*P8\``&B%
`
end