From 16bed313c6d6a48c0d32e0fddf44ca0825db236c Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Tue, 19 Nov 2024 02:49:41 +0100 Subject: [PATCH] libstore: abort all curl transfers on interrupt give the transfer progress callback a chance to register all transfers as aborted when an interrupt event occurs. checkInterrupt() will throw an Interrupted exception if an interrupt signal was caught, which will immediately break out of the curl loop. it isn't even necessary within the curl main loop as curl guarantees to call progress callbacks about once per second (or more often), and we already abort transfers from a progress update if a signal was caught. this may delay shutdown a bit, but "about one second" as should not be noticeable in most situations. fixes #577 Change-Id: Ida4e72732562bdf6560e4f182ecdcdb663c6dda5 --- src/libstore/filetransfer.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc index c29132d9c..8a566f441 100644 --- a/src/libstore/filetransfer.cc +++ b/src/libstore/filetransfer.cc @@ -506,13 +506,12 @@ struct curlFileTransfer : public FileTransfer // loop with kj. until then curl will handle its timeouts internally. int64_t timeoutMs = INT64_MAX; - while (!quit) { - checkInterrupt(); - + while (true) { { auto cancel = [&] { return std::move(state_.lock()->cancel); }(); for (auto & [item, promise] : cancel) { curl_multi_remove_handle(curlm.get(), item->req.get()); + items.erase(item->req.get()); promise.set_value(); } } @@ -536,6 +535,12 @@ struct curlFileTransfer : public FileTransfer } } + // only exit when all transfers are done (which will happen through the + // progress callback issuing an abort in the case of user interruption) + if (items.empty() && quit) { + break; + } + /* Wait for activity, including wakeup events. */ mc = curl_multi_poll(curlm.get(), nullptr, 0, std::min(timeoutMs, INT_MAX), nullptr); if (mc != CURLM_OK)