Skip to content

[csp] Bug with concurrent select()s using the same channel #547

@azerum

Description

@azerum

The issue is that when Promise.race() inside select() completes, select() removes the first race of each participating channel. However, that race might have been added by another select(), called earlier. Here, s1 does not unblock as its race was removed by s2:

import { channel, select } from '@thi.ng/csp'

void main()

async function main() {
    const a = channel(1) // chan-0
    const b = channel(1) // chan-1
    const c = channel(1) // chan-2

    const s1 = select(a, b)
    const s2 = select(a, c)

    c.write(1)
    console.log(await s2)

    a.write(1)
    console.log(await s1)
}

Expected output:

[1, <channel id: chan-2>]
[1, <channel id: chan-0>]

Actual output:

[1, <channel id: chan-2>]
<s1 remains blocked>

This can happen in a quite usual async code if two routines concurrently do such selects, and then c.write() happens somewhere

Suggested fix:

One approach is to provide a way to cancel a particular race, so selects cancel only their races. E.g. race() can return a cancel function along the promise, or accept AbortSignal, and store callbacks in a set

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