Skip to content

Copy bytes from BufferSource in parallelΒ #165

Open

Description

@reillyeon

The write algorithm copies the contents of the chunk before entering the "in parallel" steps. This doesn't match the behavior in Chromium which copies the chunk piecewise into an internal ring buffer as space becomes available. This means that if script modifies the contents of the BufferSource before the Promise returned by write() resolves the data written to the port will change. I think this behavior is correct but should be explicitly specified. The simplest change would be to move the invocation of the "get a copy of the buffer source" algorithm to after the steps go "in parallel". A more accurate description would be to acknowledge that a write may partially complete and so the steps must retry with unwritten pieces of the chunk. WebIDL doesn't seem to define an algorithm for converting a range within a BufferSource to a byte sequence.

CC @domenic

Activity

  1. domenic commented on Jul 8, 2022

    @domenic
    Member

    Hmm. This is generally something we try to avoid in web API design, by either making copies or taking ownership of the entire buffer via transferring. See https://w3ctag.github.io/design-principles/#js-rtc . (At least, I assume what you're describing would violate run to completion, since within a single event loop task, the other thread might first read one version of the buffer, then read another after the JS has updated it.)

    Since we don't yet have writable byte streams with ownership taking/returning semantics, we've been assuming people would make copies...

  2. reillyeon commented on Jul 8, 2022

    @reillyeon
    CollaboratorAuthor

    Outside the web platform it is a pretty common contract for asynchronous I/O functions to receive a buffer and expect the caller not to mutate that buffer until the operation is complete. I agree that copying or transferring the buffer on write() is safer but has the disadvantage of either performing extra copies or not allowing the caller to reuse the buffer. The current design of the write algorithm sounds like it is implementing a version what you are intending to explicitly support with ownership taking/returning semantics.

    The documentation of the underlying sink API should probably include a note about the expectation that the chunk is copied if write() cannot complete synchronously.

  3. reillyeon commented on Jul 27, 2022

    @reillyeon
    CollaboratorAuthor

    Following up here because I want to make sure to provide the right guidance on this for other UnderlyingSink implementers. I'm okay with changing the behavior of the Web Serial API in Chromium if the intention is for Streams to eventually support explicitly transfering the buffer to the UnderlyingSink and later returning it to the caller. It looks like this is being discussed in whatwg/streams#495 and the summary mentions the current ambiguities.

  4. kvnloo commented on Oct 1, 2026

    @kvnloo

    Current Chromium still appears to have the behavior described here.

    SerialPortUnderlyingSink::write() stores the original V8BufferSource, while WriteData() repeatedly creates a DOMArrayPiece over it and writes the remaining ByteSpan() into the Mojo pipe as capacity becomes available.

    So bytes can still be observed incrementally rather than copied atomically when write() is called.

    That seems worth either specifying explicitly or changing; right now implementation behavior and the safer copy-at-call-time model remain observably different.

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