Unix: Make `OsIpcReceiver.fd` nullable to avoid unnecessary FD cloning
Unix: Make `OsIpcReceiver.fd` nullable to avoid unnecessary FD cloning

In line with the other back-ends, add interior mutability for the
receiver handle (by wrapping it in a `Cell<>`), to enable truly
"consuming" the receiver, even when all we have is just a shared
reference to the original receiver. (I.e. allow actually unsetting the
field in the original object, so we get proper move semantics.)

This is necessary, since `consume()` is called from our `serialize()`
implementation (for Serde), which only gets passed a shared reference to
the source data as well. Without being able to properly move it out, we
had to resort to temporarily cloning the FD (i.e. calling `libc::dup()`
on it), just for the original instance to be dropped a moment later at
the end of the `send()` method -- since otherwise we would get shared
ownership of the FD, thus making the handling fragile against leaking or
premature dropping.

Now that we can actually unset the original handle, we just transfer
full responsibility for the FD to the new owner -- i.e. the new owner
can safely `close()` the FD while dropping the data structure when it is
done with it; whereas dropping the original receiver instance won't do
anything, as it doesn't have access to the FD anymore.

Another place this affects is `OsIpcReceiverSet.add()`, where the FD was
being cloned temporarily as well -- though strictly speaking this one
could have been fixed even without interior mutability, as this method
actually gets the receiver by value...

These changes improve performance of passing many receivers by almost a
third. (Abount 350 ns each, which is fairly significant even in the
more likely case of passing only a single receiver.)

test ipc::transfer_empty                                    ... bench:       2,434 ns/iter (+/- 56)
test ipc::transfer_receivers_00                             ... bench:       2,645 ns/iter (+/- 49)
test ipc::transfer_receivers_01                             ... bench:       5,013 ns/iter (+/- 113)
test ipc::transfer_receivers_08                             ... bench:      13,234 ns/iter (+/- 192)
test ipc::transfer_receivers_64                             ... bench:      76,912 ns/iter (+/- 2,048)
test ipc::transfer_senders_00                               ... bench:       2,705 ns/iter (+/- 48)
test ipc::transfer_senders_01                               ... bench:       5,137 ns/iter (+/- 98)
test ipc::transfer_senders_08                               ... bench:      13,919 ns/iter (+/- 294)
test ipc::transfer_senders_64                               ... bench:      83,491 ns/iter (+/- 1,805)

Performance of adding receivers to a set is also affected significantly,
improving by some 8% or so -- though it's hard to say exactly, with the strong
fluctuations these tests are seeing...

test ipc::receiver_set::add_and_remove_100_closed_receivers ... bench:     641,313 ns/iter (+/- 97,666)
test ipc::receiver_set::add_and_remove_10_closed_receivers  ... bench:      63,397 ns/iter (+/- 9,943)
test ipc::receiver_set::add_and_remove_1_closed_receivers   ... bench:       7,905 ns/iter (+/- 491)
test ipc::receiver_set::create_and_destroy_empty_set        ... bench:          27 ns/iter (+/- 0)
test ipc::receiver_set::create_and_destroy_set_of_1         ... bench:       4,733 ns/iter (+/- 1,119)
test ipc::receiver_set::create_and_destroy_set_of_10        ... bench:      47,696 ns/iter (+/- 16,627)
test ipc::receiver_set::create_and_destroy_set_of_100       ... bench:     470,423 ns/iter (+/- 110,249)

servo/ipc-channel