Skip to content

src/README.md: map the source folder, its threads and its locks - #3875

Draft
mcfnord wants to merge 6 commits into
jamulussoftware:mainfrom
mcfnord:docs-src-readme
Draft

src/README.md: map the source folder, its threads and its locks#3875
mcfnord wants to merge 6 commits into
jamulussoftware:mainfrom
mcfnord:docs-src-readme

Conversation

@mcfnord

@mcfnord mcfnord commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

MY LLM WROTE:

Short description of changes

src/ has no README. This adds one: a map for a reader new to the code — which class lives where, which threads exist at runtime, and which lock protects what. Same shape as the section recently proposed for src/sound/README.md in #3873: it describes how the code behaves today, asserts no intent, and ends with an explicit list of what is still missing.

What it covers:

  • Where things live — one line per major class, split into shared / client-only / server-only, with links to the protocol and JSON-RPC docs.
  • Threads — a table of every thread: the Qt main thread, CSocketThread, the audio driver threads, CHighPrecisionTimer's thread, the CThreadPool workers, the recorder thread, and the connect dialog's use of the global pool. Followed by the three facts easiest to miss: the server's complete frame cycle (CServer::OnTimer) executes on the main thread — the TimeCriticalPriority timer thread only paces a queued emit timeout() (confirmed with a debugger on Linux, and the TODO in util.cpp says the same); CSoundBase inherits QThread but that thread is never started; the client sends audio from inside the driver callback while receiving on CSocketThread.
  • Locks — a table of the five locks taken from more than one thread (MutexSocketBuf, CSocket::Mutex, CServer::Mutex including exactly which part of OnTimer holds it, CChannel::Mutex, MutexConvBuf), each with what it protects and the threads that take it, plus one line each for the smaller ones.
  • Not yet documented — the jitter buffer size algorithm, connection lifecycle, directory registration, the recorder, logging, signal handling, the GUI classes.

The thread table is measured, not read: each identity was confirmed by breaking on the function in a release build under gdb on Linux and recording which thread hit (CServer::OnTimer and CProtocol::ParseMessageBody on the main thread, CServer::PutAudioData and CChannel::PutAudioData on CSocketThread, CClient::ProcessAudioDataIntern on the JACK callback thread, CHighPrecisionTimer::run on its own thread).

Two design choices, offered for discussion since later doc files could follow the pattern:

  • Every cross-reference is a relative link whose link text is the path itself — [channel.cpp](channel.cpp), [../docs/JAMULUS_PROTOCOL.md](../docs/JAMULUS_PROTOCOL.md). Rendered on GitHub, the map becomes browseable: every named file is one click away. Read raw in a terminal or an editor, each link degrades to the path plus punctuation, so the text still works for a reader without a browser.
  • No link carries a line number, because line numbers go stale with the next commit to the file. Functions, classes and members are named in backticks instead, so a plain grep finds them from either the rendered or the raw form.

CHANGELOG: SKIP

Context: Fixes an issue?

No issue. Follows #3873, which starts the sound-layer half of the same documentation; this file links to it rather than repeating it.

Does this change need documentation? What needs to be documented and how?

This is the documentation. Developer-facing, so it belongs next to the code rather than on the website.

Status of this Pull Request

Working implementation. Every statement is checkable against the tree at the commit it was written on, and the thread identities were verified at runtime rather than inferred from the source.

What is missing until this pull request can be merged?

Review. One open question for reviewers: whether the license header on a brand-new documentation file should carry the full historical GPL paragraph or only the AGPL block used here.

Checklist

  • I've verified that this Pull Request follows the general code principles
  • I tested my code and it does what I want
  • My code follows the style guide
  • I waited some time after this Pull Request was opened and all GitHub checks completed without errors.
  • I've filled all the content above

No checks run on this one: autobuild.yml carries paths-ignore: '**README.md' and coding-style-check.yml only triggers on **.cpp/**.h, so the fourth box stays unticked rather than claiming a green run that never happened.

Comment thread src/README.md Outdated

@ann0see ann0see left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd aim this at human contributors for now.

@ann0see

ann0see commented Aug 8, 2026

Copy link
Copy Markdown
Member

Review. One open question for reviewers: whether the license header on a brand-new documentation file should carry the full historical GPL paragraph or only the AGPL block used here.

AGPL. But I think it's weird as is. I'd think that a HTML comment for the full license would be enough and a visible short link to the license file. But @pljones should judge. I really dislike a wall of text first just stating the license. Nobody reads it.

Comment thread src/README.md Outdated
- [protocol.cpp](protocol.cpp) — `CProtocol`: protocol message framing, acknowledgement, and
retransmission of unacknowledged messages from `SendMessQueue`. The wire format itself is
described in [../docs/JAMULUS_PROTOCOL.md](../docs/JAMULUS_PROTOCOL.md).
- [channel.cpp](channel.cpp) — `CChannel`: one connection, holding the receive jitter buffer

@ann0see ann0see Aug 8, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should probably not describe too much of the file content. Rather the brief this file holds class X which does Y. As in anyone can just read the file to get more info. So here: Implements the channel + jitter buffer used for Server and Client.

Comment thread src/README.md Outdated
| recorder thread | server with recording | `CJamController` | `CJamRecorder`, fed by queued `AudioFrame` signals from the frame cycle |
| `QThreadPool` global pool | client GUI | the connect dialog | one task per listed server for the ping/info fan-out (`QtConcurrent::run`) |

Three consequences that are easy to miss:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds way too much AI...

@mcfnord

mcfnord commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

I'd aim this at human contributors for now.

I believe if we write for a human audience, we will dramatically improve LLM outcomes "for free".

Applies @ann0see's review on jamulussoftware#3875:

- Intro cut to two sentences; the paragraph about what the file does and
  does not assert is gone.
- File list back to one line each: the SendMessQueue detail, the SockBuf
  and CProtocol members and the vecChannels name are all readable in the
  file itself. Kept "the client has one; the server an array of
  MAX_NUM_CHANNELS", which is in server.h, not channel.cpp.
- The three-bullet block after the thread table is one paragraph. The
  CSoundBase QThread note moves to src/sound/README.md (jamulussoftware#3873), where a
  reader meets the class; the send/receive clocking bullet is dropped, as
  the table above already carries it. The parenthetical about how the
  thread identities were checked is dropped too: it describes the method,
  not the code, and the util.cpp TODO makes the point on its own.

122 lines to 105. No claim changed.
mcfnord pushed a commit to mcfnord/jamulus that referenced this pull request Aug 8, 2026
CSoundBase derives from QThread, so a reader can reasonably expect a
sound thread. There is none: no override of run() and no call to start()
exists in the sound layer -- the only two run() overrides in src/ are
CHighPrecisionTimer (util.h) and CSocketThread (socket.h). Audio
callbacks always arrive on driver-owned threads.

Moved here from the src/README.md draft (jamulussoftware#3875), where it sat under the
thread table; this is the file that introduces CSoundBase.
Comment thread src/README.md Outdated
Comment thread src/README.md Outdated
Comment thread src/README.md Outdated
Comment thread src/README.md Outdated
Comment thread src/README.md
locks — `MutexAudioProcessCallback`, `MutexDevProperties`, and the per-backend ones — are
covered in [sound/README.md](sound/README.md).

## Not yet documented

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we could drop this section.

@dingodoppelt dingodoppelt added the AI AI generated or potentially AI generated label Aug 9, 2026
Comment thread src/README.md
* mcfnord
* The Jamulus Development Team

As of Jamulus 3.12.1dev (commit eb172d47): All new source code contributions must be licensed

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't need these lines. This only applied to existing files. New files should only have the AGPL header.

Comment thread src/README.md
- [util.h](util.h) / [util.cpp](util.cpp) — `CHighPrecisionTimer`, the server's frame clock, and
assorted helpers.

Client only: [client.cpp](client.cpp) (`CClient`), the sound layer in [sound/](sound/), the GUI

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Section, laid out as bullets like the shared code. Same for the following ones.

Comment thread src/README.md
| `CChannel::Mutex` | per-channel state: the enable flag, gain and pan tables, name | setters in protocol slots on the main thread; getters in the server's frame cycle |
| `CChannel::MutexConvBuf` | the send-side conversion buffer | `PrepAndSendPacket()` on the sending thread; re-init from the main thread |

Smaller ones: `CProtocol::Mutex` (the queue of sent but not yet acknowledged messages),

@pljones pljones Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, bulleted list. Or table.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI AI generated or potentially AI generated

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants