Skip to content

World deadlocks: Loader.viewChunk holds l.mu across addViewer, and a synchronous chunk load re-enters it #1448

Description

@danielpotapo

Deadlock cause
Session.sendChunks calls Loader.Load. The loader’s centre chunk is not resident, so loadChunkAsync sends it to the chunk workers and records the pending request in w.chunkRequests.
The next queued chunk is already resident. Because of that, loadChunkAsync invokes its callback synchronously, entering Loader.viewChunk. viewChunk locks l.mu and continues holding it while calling l.w.addViewer (loader.go#L127, loader.go#L145).

addViewer eventually follows this path:

showEntity -> Session.ViewEntity -> parseEntityMetadata -> Player.Breathing() -> tx.Liquid(eyePos)

The player’s eye position is inside the centre chunk from step 1. That chunk is not resident yet, but its load is pending. The read then follows:

Tx.chunk -> chunkFromAsyncPool -> doImmediate -> signal

signal runs the pending request’s callbacks on the current goroutine. One of those callbacks is the same loader’s viewChunk.

The re-entered viewChunk tries to lock l.mu, which the same goroutine is already holding. Because sync.RWMutex is not reentrant, the world’s transaction goroutine blocks permanently.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions