PartFileWriteThread: catch CIOFailureException so disk-full doesn't abort the process - #499
Merged
mrjimenez merged 1 commit intoApr 29, 2026
Conversation
mrjimenez
pushed a commit
that referenced
this pull request
Apr 29, 2026
Follow-up to PR #498 (b106e3a PartFile: serialise m_hpartfile access against the hash thread). When a download fills the disk, PartFile.cpp:3083 logs "Not enough free disk-space! Pausing file: …", calls PauseFile(true) (status -> PS_INSUFFICIENT), and returns. PR #498's CDownloadQueue::Process paused-drain branch then drives FlushBuffer for the file every Process tick (~100 ms) because HasPendingHashWork() still returns true for the dirty m_aChangedPart entries that were buffered before the disk filled. Each call re-enters the same disk-space check, re-logs the warning, and re-pauses — producing tens of log lines per second until the file is removed. Manually clicking Stop on the GUI doesn't help: the status flag stays PS_INSUFFICIENT, only m_stopped flips, and the drain branch keys on status. Drop PS_INSUFFICIENT from the drain set. PS_PAUSED (user-clicked pause) keeps its drain — that's the case the branch was added for. Disk-full files have no productive hash work to do anyway: the buffered items can't be written, so Phase 1 would just queue them to the worker, which would catch CIOFailureException (PR #499) and bounce them back as PB_ERROR. Leftover m_aChangedPart entries on a disk-full file are still covered by the destructor sync-hash drain at shutdown.
…bort CFileArea::FlushAt -> CFileAutoClose::WriteAt throws CIOFailureException on a disk-full / EIO / permission-denied write, and CPartFileWriteThread::Entry has no try/catch around it. The exception unwinds out of Entry, through wxThreadInternal::PthreadStart, into wxApp::OnUnhandledException, which std::set_terminate's MuleDebug aborts the process. Reproducer: write enough into the buffered queue that the disk runs out of space before the main-thread CheckFreeDiskSpace path on the next FlushBuffer pauses the file (a slow main thread or a high in-flight write count is enough). The disk-space check at PartFile.cpp:3083 is best-effort: it runs once per FlushBuffer on the main thread and only inspects the buffered total, so a write already queued to the worker thread can still hit the wall. Catch the exception in the worker, log to logPartFile, decrement m_iWrites so main-thread waiters don't deadlock, and mark the buffer PB_ERROR. FlushBuffer's existing Phase 2 PB_ERROR handler resets the item to PB_READY for retry; if the disk is genuinely exhausted the next FlushBuffer's CheckFreeDiskSpace pauses the file before the retry cycles further.
got3nks
force-pushed
the
pr-d-write-thread-iofailure
branch
from
April 29, 2026 13:48
2b514d0 to
6ca91a9
Compare
mrjimenez
pushed a commit
to mrjimenez/amule
that referenced
this pull request
Jul 16, 2026
…mule-project#499) The interface bind added in amule-project#281 (IP_UNICAST_IF / IP_BOUND_IF) pins every socket aMule opens — including the External Connection listener — to a single interface, so ed2k/Kad cannot run over a VPN tunnel while the EC control port stays on the LAN. Decouple the EC listener with a new daemon-side setting, /ExternalConnect/ECNetworkInterface (empty = any), that binds only aMule's EC acceptor, independent of the global P2P interface pin. It sits beside the existing ECAddress IP bind, giving the EC channel both its own IP and its own interface. CLibSocketServer gains a per-server interface override; only CExternalConnListener uses it. ed2k/Kad TCP and UDP, outbound connections and HTTP keep following the global setting untouched. A "Bind to network interface" selector is added to the Remote Controls page (reusing the existing P2P label); like the other EC-listener settings it is daemon-only — hidden in the remote GUI and not carried over EC — and flagged restart-needed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
CPartFileWriteThread::Entryhas no try/catch aroundpBuffer->area.FlushAt(...).CFileArea::FlushAt→CFileAutoClose::WriteAtthrowsCIOFailureExceptionon a disk-full / EIO / permission-denied write. The exception unwinds out ofEntry, throughwxThreadInternal::PthreadStart, intowxApp::OnUnhandledException, andstd::set_terminate'sMuleDebug.cpp:108callsabort()→ SIGABRT, the whole process dies.Reproducer
Saw it in the wild on macOS during a 30 GB download to a near-full target disk. Crash report excerpt — the worker thread that died is the one that should be
CPartFileWriteThread:The disk-space check at
PartFile.cpp:3083is best-effort — it runs once perFlushBufferon the main thread and only inspects the buffered total, so a write already queued to the worker can still hit the wall before the main thread pauses the file. The bug is latent; the conditions that exercise it are a slow main thread, a high in-flight write count, or both.Fix
Catch
CIOFailureExceptionin the worker:logPartFilewith the file name, offset, and length so the failure is diagnosable.m_iWrites(so any main-threadm_iWrites <= 0waits don't deadlock).PB_ERROR.FlushBuffer's existing Phase 2 PB_ERROR handler resets the item toPB_READYfor retry. If the disk is genuinely exhausted the nextFlushBuffer'sCheckFreeDiskSpacepauses the file before the retry cycles further.Backward compatibility
CPartFileWriteThread::Entry. No API or wire changes.#include "CFile.h"and<common/Format.h>in the worker TU.