Remove easy handles before curl_multi_cleanup
Summary:
Before destroying a curl multi handle, we must detach all easy handles attached to it: https://curl.se/libcurl/c/curl_multi_cleanup.html
Today, we don't respect this constraint at all. Let's fix that.
We destroy curl multi handles in two cases: during the request, when its refcount goes to 0, and at the end of the request, on a call to sweep. In both of these cases, we don't place any ordering invariant between destroying multi handles and their attached easy handles today - we can destroy the multi handles with easy handles attached, or worse, destroy the easy handle, then destroy the multi handle with a dangling reference!
We fix these cases by tracking a bidirectional mapping between multi handles and their attached easy handle. Whenever we destroy either handle, we first detach all edges incident to it. We need to be a little bit careful on sweep, because it happens after we start to tear down request memory. To handle that case, I added a "leak" param to CurlMultiResource::remove that lets us detach the edge without allocating memory or calling destructors. I also tied the add/remove metadata operations to the underlying curl operations, so that we don't add/remove an edge when the curl operation fails.
Reviewed By: ricklavoie
Differential Revision:
D30344219
fbshipit-source-id:
553a7dae54a96737f82180d3b9abec317e81e8a4