Skip to content

fix(amuled): construct partFile write/hash threads after InitGui fork (#849) - #850

Merged
mrjimenez merged 1 commit into
amule-project:masterfrom
got3nks:fix/amuled-partfile-write-thread-fork
Jun 4, 2026
Merged

fix(amuled): construct partFile write/hash threads after InitGui fork (#849)#850
mrjimenez merged 1 commit into
amule-project:masterfrom
got3nks:fix/amuled-partfile-write-thread-fork

Conversation

@got3nks

@got3nks got3nks commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Closes #849.

Why

amuled -f (full-daemon mode) fails to write any downloaded bytes to the .part file. Files reach 99 % on the network side (peer state knows it has all the chunks), but ~/.aMule/Temp/NNN.part stays at 0 bytes and CPU climbs. Monolithic amule and amuled without -f work fine.

Root cause

CPartFileWriteThread and CPartFileHashThread (both wxThread-backed, both spawn the OS thread inside the ctor) are constructed at amule.cpp:652-653, which is before InitGui() (line 672) — and InitGui() is where amuled forks. POSIX fork() only carries the calling thread to the child, so in the daemonized child the two thread objects are alive in memory but their OS threads are gone.

Three immediately-adjacent thread constructions (uploadBandwidthThrottler, uploadDiskIOThread, m_AsioService) are correctly placed AFTER InitGui() and have an explicit comment about the fork constraint. The partfile-* pair was added later by the #454 throughput rewrite and missed that constraint.

The synchronous-fallback path at PartFile.cpp:3252-3270 doesn't rescue this either: wxThread::IsRunning() reads an internal state flag that still reports "running" after the fork, so items get queued (marked PB_PENDING) onto a dead thread instead of falling through to the inline write branch.

Fix

Move lines 652-653 to right after uploadDiskIOThread, in the same post-fork group. No code between the old and new sites touches either pointer (verified by grep partFile{WriteThread,HashThread} in src/amule.cpp).

Test plan

  • macOS local build: clean.
  • @danim7 — could you reproduce on your Raspberry Pi 400 setup? Pull this branch, rebuild, restart amuled -f, and trigger the same ~3 GB download. Expected: the .part file should start receiving data within seconds and grow as the download progresses, CPU usage should stay normal. No config changes required.
  • Cross-check with amuled without -f (no fork): still works (regression-free for that mode).
  • Cross-check with monolithic amule: still works (no fork, unaffected).

amuled's --full-daemon (-f) mode forks from inside InitGui() at
amule.cpp:672. On POSIX, fork() only carries the calling thread to
the child — any thread spawned before the fork has its OS-level
pthread torn off, leaving the C++ object in memory with no thread
actually running behind it.

CPartFileWriteThread and CPartFileHashThread (both wxThread-backed,
both spawned in their ctor) were constructed at amule.cpp:652-653,
which is BEFORE the InitGui() fork. The comment at amule.cpp:682
explicitly flags this constraint for the same-shaped
UploadBandwidthThrottler / CUploadDiskIOThread / CAsioService trio
right next door — but the partfile-* threads, added later (amule-project#454),
skipped it.

User-visible symptom (amule-project#849): amuled -f reaches 99% on the network
side, but the .part file stays at 0 bytes and CPU is pegged. The
write-thread's PB_PENDING queue keeps filling because nothing is
draining it on the child. Monolithic amule and amuled without
-f both work because neither forks.

The synchronous FlushBuffer fallback at PartFile.cpp:3252 doesn't
save us either, because wxThread::IsRunning() reads an internal
state flag that still says "running" post-fork — items get marked
PB_PENDING and routed at the dead thread instead of being written
inline.

Fix: move the two constructions past InitGui(), into the same
post-fork group as uploadDiskIOThread. No other code between the
old and new construction sites touches either pointer (verified by
grep in src/amule.cpp).
@mrjimenez
mrjimenez merged commit 3c4dea3 into amule-project:master Jun 4, 2026
7 checks passed
@got3nks
got3nks deleted the fix/amuled-partfile-write-thread-fork branch June 5, 2026 22:35
got3nks added a commit to got3nks/amule that referenced this pull request Jun 7, 2026
…ule-project#912)

Extends existing categories (preferring extensions over new lines):
- Performance/Upload: amule-project#898 SlotAllocation default raised.
- Networking & Discovery: wire-parser hardening list extended with
  amule-project#879/amule-project#882/amule-project#890/amule-project#886; new amuleweb security hardening bullet
  consolidating ngosang's amule-project#869-amule-project#874 triage (all landed in amule-project#875);
  amulegui list extended with amule-project#857; shared-folder watcher extended
  with amule-project#858.
- Packaging: Windows installer i18n line extended with amule-project#899.
- Internals & Refactoring: new docs-polish + code-quality bullets
  covering amule-project#851/amule-project#855/amule-project#862/amule-project#888/amule-project#900/amule-project#866/amule-project#867/amule-project#895 and amule-project#909/amule-project#910/amule-project#912.
- Translations: new pre-release final-wave bullet covering amule-project#847/amule-project#856/
  amule-project#891/amule-project#908/amule-project#860/amule-project#904/amule-project#859/amule-project#863/amule-project#861/amule-project#880/amule-project#911/amule-project#901/amule-project#902/amule-project#889/amule-project#868/amule-project#853.
- Bug Fixes & Stability: amule-project#850/amule-project#854/amule-project#878/amule-project#906.
- CI: ccache wiring (amule-project#892, amule-project#903) + CodeQL binutils-dev (amule-project#907).

Contributors footer gains mifritscher and nguyenhoangminhhieu2004-gif
(both first-time contributors).

PR index extended through amule-project#912.
mrjimenez pushed a commit that referenced this pull request Jun 8, 2026
Extends existing categories (preferring extensions over new lines):
- Performance/Upload: #898 SlotAllocation default raised.
- Networking & Discovery: wire-parser hardening list extended with
  #879/#882/#890/#886; new amuleweb security hardening bullet
  consolidating ngosang's #869-#874 triage (all landed in #875);
  amulegui list extended with #857; shared-folder watcher extended
  with #858.
- Packaging: Windows installer i18n line extended with #899.
- Internals & Refactoring: new docs-polish + code-quality bullets
  covering #851/#855/#862/#888/#900/#866/#867/#895 and #909/#910/#912.
- Translations: new pre-release final-wave bullet covering #847/#856/
  #891/#908/#860/#904/#859/#863/#861/#880/#911/#901/#902/#889/#868/#853.
- Bug Fixes & Stability: #850/#854/#878/#906.
- CI: ccache wiring (#892, #903) + CodeQL binutils-dev (#907).

Contributors footer gains mifritscher and nguyenhoangminhhieu2004-gif
(both first-time contributors).

PR index extended through #912.
got3nks added a commit to got3nks/amule that referenced this pull request Aug 7, 2026
Every ported list appended a 1px trailing spacer on macOS. The reasoning
was that macOS hands leftover width to the last *resizable* column and
collapses it to nothing once the columns are wider than the control, so
a throwaway column should absorb that instead of one the user cares
about.

CGenericClientListCtrl (amule-project#850) shipped without a spacer and does not
collapse, which is what prompted checking the rest. The spacer dates
from the first base commit, when every list was still constructed with
the legacy wxLC_REPORT|wxSUNKEN_BORDER flags -- and wxLC_REPORT is the
same bit as wxDV_VARIABLE_LINE_HEIGHT, so those lists were silently
running with variable line height. Those flags came off in 71bdb1a and
amule-project#849, and with them gone a spacer-less build shows no collapse.

So the spacer appears to have been treating a symptom of the flags
rather than a macOS sizing rule. Removing it takes the whole mechanism
with it: the six call sites, AppendSpacerColumn(), m_hasSpacer,
RealColumnCount()'s adjustment and five COLUMN_*_SPACER ids plus
CSearchListModel::COL_SPACER, which each model had to answer for.

RealColumnCount() stays as the accessor -- now simply GetColumnCount() --
rather than inlining it across its call sites, which is a separate
change.
mrjimenez pushed a commit to mrjimenez/amule that referenced this pull request Aug 8, 2026
…ct#850)

Last remaining piece of amule-project#801's wxListCtrl -> wxDataViewCtrl migration: the shared base behind CSourceListCtrl and CSharedFilePeersListCtrl.

ClientCtrlItem_Struct survives rather than being deleted, unlike the previous ports: one client can be a source or peer of more than one file at a time, so row identity is the (client, owner, type) tuple. Its cached wxBitmap fields are dropped, matching the no-cache precedent from the Shared Files and Downloads ports.

Two bar columns, two renderers: CSourceBarRenderer draws the 5-state chunk bar and substitutes a bordered A4AF text badge for those rows, while the peers' availability column needs only the base renderer and ships without SORTABLE, since no comparison exists for it and none did pre-port. The User Name column is a composite icon cluster plus optional country flag plus text, so it goes through CClientNameRenderer, reaching the row via the identity-carrying CBarFillSpec extension point; GetItemColumnText() still answers plain text there, so type-ahead and the accessible row label work off real text rather than the pre-port empty string.

CompareItemData() keeps the original SortProc's type precedence, sorting A4AF sources last regardless of direction, before dispatching per column. muuli_wdr.cpp drops the legacy wxLC_REPORT|wxSUNKEN_BORDER flags for both lists.
mrjimenez pushed a commit to mrjimenez/amule that referenced this pull request Aug 8, 2026
…endored wxGenericListCtrl (amule-project#855)

Follow-up to amule-project#801/amule-project#180: with the client-list port done in amule-project#850, CCommentDialogLst was the only remaining instantiator of CMuleListCtrl and CMuleVirtualListCtrl had no derivers left.

CCommentDialogLst drops to a plain wxListCtrl -- a small read-only modal list that does not warrant the CMuleDataViewCtrl treatment -- with click-to-sort reimplemented by hand. amuleDlg's exit-time SaveListControlSettings() widget walk goes too: it existed because CMuleListCtrl only saved lazily from its destructor, which the tray-Exit path could skip, whereas CMuleDataViewCtrl writes column widths and sort orders eagerly on every resize, sort and show/hide, and SaveGUIPrefs() still flushes on every close path.

That leaves CMuleVirtualListCtrl, CMuleListCtrl and the vendored wxGenericListCtrl with no consumers, so all four files are deleted. IsListBackgroundDark() moves to MuleColour.h. CListColumnStore's legacy config-migration path is untouched -- it still reads pre-dataview TableWidths* entries.

One known simplification: the comments dialog loses its header sort-arrow glyph, which plain wxListCtrl does not draw. A follow-up restores it via ShowSortIndicator().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

amuled not allocating downloads on raspberry pi, files never written to disk

2 participants