Since exec() replaces the current process image inline, as long as you serialize in and out externally-perceivable info like which file descriptors are doing what things, you can actually just exec in the new code. It's like restarting, but transparently restarting in-place. (From a mailing list: "With XMonad, you don't lose any windows, layouts, X connections or anything when you persist-and-restart; people have even upgraded several versions and restarted without any problems." [I've never used XMonad.])
Does this really work? I'm trying to think of what other sorts of state you could lose between execs. (An interesting aspect to this is that it's much easier in a language that makes you very explicit when you maintain any in-memory state.)