[hack] Ensure code segment digest is calculated before forking
[hack] Ensure code segment digest is calculated before forking

Summary:
A marshaled closure is represented as an offset into a code segment. The runtime allows multiple separate code segments (dynlink adds new code segments, for example), and these segments are stored in a global by the runtime. When (un-)marshaling a closure, the runtime calculates a digest for the code segment and stores it back in the table. That is, the digest is computed lazily, the first time a closure is (un-)marshaled.

Generally this is fine, as we only pay the cost of computing a digest once and only when it's needed. However, the shared memory architecture used by Hack and Flow can cause us to needlessly compute the digest over and over.

On systems that support fork, we spawn worker processes which in turn fork for each received job. The job is a marshaled closure which is deserialized in the forked process. If the spawned worker has not already calculated the digest, then the forked worker will do it when deserializing the job, but since the forked process's memory is copy-on-write, the work is then thrown away.

To avoid this scenario, this diff forces the spawned worker to deserialize a dummy closure, which populates the digest field in the code segments table.

Reviewed By: gabelevi

Differential Revision: D13206371

fbshipit-source-id: b68f9c8a15716506f8e3b8fb3dea0463bd9290b0

nmote/flow,nmote/flow,nmote/flow,nmote/flow,nmote/flow,nmote/flow,nmote/flow