OverviewFilesCommitsIssuesDocsReleasesPeers

mirall-cli / node_modules / bare-broadcast-channel / binding.c

1310 lines · c ref:
#include <assert.h>
#include <bare.h>
#include <js.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <uv.h>

// Ports are organised into a two-level directory. The channel holds a fixed
// table of segment pointers; each segment owns one 64-bit claim/active word
// pair and up to 64 lazily allocated ports. Growth only ever appends a new
// segment, so existing segments, ports, and their synchronisation primitives
// never move for the lifetime of the channel. This keeps the peer list
// resizable without the reclamation hazards of copying a live directory. The
// segments and ports are reclaimed in one pass when the channel handle's
// finalizer runs, once the last holder of the handle has been collected.
#define BARE_BROADCAST_CHANNEL_SEGMENT_SIZE 64
#define BARE_BROADCAST_CHANNEL_SEGMENT_MASK (BARE_BROADCAST_CHANNEL_SEGMENT_SIZE - 1)
#define BARE_BROADCAST_CHANNEL_MAX_SEGMENTS 1024

#define BARE_BROADCAST_CHANNEL_MAX_PORTS \
  (BARE_BROADCAST_CHANNEL_SEGMENT_SIZE * BARE_BROADCAST_CHANNEL_MAX_SEGMENTS)

// The per-port message ring depth is chosen when the channel is created and
// rounded up to a power of two so the cursor arithmetic can mask rather than
// divide.
#define BARE_BROADCAST_CHANNEL_DEFAULT_CAPACITY 1024
#define BARE_BROADCAST_CHANNEL_MIN_CAPACITY     2

typedef struct bare_broadcast_channel_s bare_broadcast_channel_t;
typedef struct bare_broadcast_channel_segment_s bare_broadcast_channel_segment_t;
typedef struct bare_broadcast_channel_port_s bare_broadcast_channel_port_t;
typedef struct bare_broadcast_channel_message_s bare_broadcast_channel_message_t;
typedef struct bare_broadcast_channel_payload_s bare_broadcast_channel_payload_t;
typedef struct bare_broadcast_channel_peers_s bare_broadcast_channel_peers_t;

struct bare_broadcast_channel_payload_s {
  atomic_int refcount;
  js_arraybuffer_backing_store_t *backing_store;
};

struct bare_broadcast_channel_message_s {
  bare_broadcast_channel_payload_t *payload;
};

struct bare_broadcast_channel_port_s {
  bare_broadcast_channel_t *channel;

  // The segment this port lives in and the single bit identifying its slot
  // within that segment. Both are fixed once the port is allocated and survive
  // slot reuse, so they are cached here to avoid recomputing them.
  bare_broadcast_channel_segment_t *segment;
  uint64_t bit;

  uint32_t id;

  // The ring depth minus one, used to mask the read and write cursors.
  uint32_t capacity_mask;

  struct {
    atomic_bool active;
    bool ending;
    bool ended;
    uint8_t closing;
    bool exiting;
  } state;

  struct {
    atomic_int read;
    atomic_int write;
  } cursors;

  struct {
    uv_mutex_t drain;
    uv_mutex_t flush;
    uv_mutex_t producer;
  } locks;

  struct {
    uv_cond_t drain;
    uv_cond_t flush;
  } conditions;

  struct {
    uv_async_t drain;
    uv_async_t flush;
    uv_async_t end;
  } signals;

  js_env_t *env;
  js_ref_t *ctx;
  js_ref_t *on_drain;
  js_ref_t *on_flush;
  js_ref_t *on_end;
  js_ref_t *on_close;

  js_deferred_teardown_t *teardown;

  // The message ring is a flexible array member sized to the channel's port
  // capacity so each port is a single allocation.
  bare_broadcast_channel_message_t messages[];
};

struct bare_broadcast_channel_segment_s {
  atomic_uint_least64_t claimed;
  atomic_uint_least64_t active;

  bare_broadcast_channel_port_t *slots[BARE_BROADCAST_CHANNEL_SEGMENT_SIZE];
};

struct bare_broadcast_channel_s {
  uint32_t port_capacity;

  // The number of segments currently published in the table. It only ever
  // grows, always under the growth mutex, and is read with acquire elsewhere.
  atomic_uint segment_count;

  // Serialises segment allocation so two connecting ports never publish a
  // segment into the same table slot.
  uv_mutex_t grow;

  _Atomic(bare_broadcast_channel_segment_t *) segments[BARE_BROADCAST_CHANNEL_MAX_SEGMENTS];
};

struct bare_broadcast_channel_peers_s {
  bare_broadcast_channel_t *channel;
  bare_broadcast_channel_segment_t *segment;
  uint32_t segments;
  uint32_t self_segment;
  uint64_t self_bit;
  uint32_t index;
  uint64_t bits;
};

static inline uint32_t
bare_broadcast_channel__round_capacity(uint32_t capacity) {
  if (capacity < BARE_BROADCAST_CHANNEL_MIN_CAPACITY) {
    capacity = BARE_BROADCAST_CHANNEL_MIN_CAPACITY;
  }

  capacity--;
  capacity |= capacity >> 1;
  capacity |= capacity >> 2;
  capacity |= capacity >> 4;
  capacity |= capacity >> 8;
  capacity |= capacity >> 16;
  capacity++;

  return capacity;
}

static inline bare_broadcast_channel_segment_t *
bare_broadcast_channel__segment(bare_broadcast_channel_t *channel, uint32_t index) {
  return atomic_load_explicit(&channel->segments[index], memory_order_acquire);
}

static inline bare_broadcast_channel_port_t *
bare_broadcast_channel__port(bare_broadcast_channel_t *channel, uint32_t id) {
  bare_broadcast_channel_segment_t *segment = bare_broadcast_channel__segment(channel, id / BARE_BROADCAST_CHANNEL_SEGMENT_SIZE);

  return segment->slots[id & BARE_BROADCAST_CHANNEL_SEGMENT_MASK];
}

static inline bare_broadcast_channel_peers_t
bare_broadcast_channel__peers(bare_broadcast_channel_t *channel, uint32_t id) {
  return (bare_broadcast_channel_peers_t){
    .channel = channel,
    .segment = NULL,
    .segments = atomic_load_explicit(&channel->segment_count, memory_order_acquire),
    .self_segment = id / BARE_BROADCAST_CHANNEL_SEGMENT_SIZE,
    .self_bit = 1ull << (id & BARE_BROADCAST_CHANNEL_SEGMENT_MASK),
    .index = 0,
    .bits = 0,
  };
}

static inline bare_broadcast_channel_port_t *
bare_broadcast_channel__peers_next(bare_broadcast_channel_peers_t *peers) {
  while (peers->bits == 0) {
    if (peers->index >= peers->segments) return NULL;

    peers->segment = bare_broadcast_channel__segment(peers->channel, peers->index);

    uint64_t active = atomic_load_explicit(&peers->segment->active, memory_order_acquire);

    if (peers->index == peers->self_segment) active &= ~peers->self_bit;

    peers->bits = active;
    peers->index++;
  }

  int bit = __builtin_ctzll(peers->bits);

  peers->bits &= peers->bits - 1;

  return peers->segment->slots[bit];
}

static inline void
bare_broadcast_channel__signal(uv_mutex_t *lock, uv_cond_t *cond, uv_async_t *async) {
  int err;

  uv_mutex_lock(lock);
  uv_cond_signal(cond);
  uv_mutex_unlock(lock);

  err = uv_async_send(async);
  assert(err == 0);
}

static inline void
bare_broadcast_channel__wake_peer(bare_broadcast_channel_port_t *peer, bool flush, bool drain) {
  uv_mutex_lock(&peer->locks.producer);

  if (atomic_load_explicit(&peer->state.active, memory_order_acquire)) {
    if (flush) bare_broadcast_channel__signal(&peer->locks.flush, &peer->conditions.flush, &peer->signals.flush);
    if (drain) bare_broadcast_channel__signal(&peer->locks.drain, &peer->conditions.drain, &peer->signals.drain);
  }

  uv_mutex_unlock(&peer->locks.producer);
}

// Counts the active peers of a port, excluding the port itself, by summing the
// population of every published segment's active word.
static inline uint32_t
bare_broadcast_channel__count_peers(bare_broadcast_channel_t *channel, uint32_t id) {
  uint32_t self_segment = id / BARE_BROADCAST_CHANNEL_SEGMENT_SIZE;
  uint64_t self_bit = 1ull << (id & BARE_BROADCAST_CHANNEL_SEGMENT_MASK);

  uint32_t count = 0;

  uint32_t segments = atomic_load_explicit(&channel->segment_count, memory_order_acquire);

  for (uint32_t s = 0; s < segments; s++) {
    bare_broadcast_channel_segment_t *segment = bare_broadcast_channel__segment(channel, s);

    uint64_t active = atomic_load_explicit(&segment->active, memory_order_acquire);

    if (s == self_segment) active &= ~self_bit;

    count += __builtin_popcountll(active);
  }

  return count;
}

static inline bare_broadcast_channel_message_t *
bare_broadcast_channel__peek_read(bare_broadcast_channel_port_t *port) {
  int read = atomic_load_explicit(&port->cursors.read, memory_order_relaxed);

  int write = atomic_load_explicit(&port->cursors.write, memory_order_acquire);

  if (read == write) return NULL;

  return &port->messages[read];
}

static inline void
bare_broadcast_channel__push_read(bare_broadcast_channel_port_t *port) {
  int read = atomic_load_explicit(&port->cursors.read, memory_order_relaxed);

  int next = (read + 1) & port->capacity_mask;

  atomic_store_explicit(&port->cursors.read, next, memory_order_release);

  // Reading freed a slot in this port's ring, so wake any peer that may be
  // blocked writing to us. We do not know which peers are producers, so we
  // signal every active peer's drain condition.
  bare_broadcast_channel_peers_t peers = bare_broadcast_channel__peers(port->channel, port->id);

  for (bare_broadcast_channel_port_t *peer; (peer = bare_broadcast_channel__peers_next(&peers));) {
    bare_broadcast_channel__wake_peer(peer, false, true);
  }
}

static inline bare_broadcast_channel_message_t *
bare_broadcast_channel__peek_write(bare_broadcast_channel_port_t *port) {
  int write = atomic_load_explicit(&port->cursors.write, memory_order_relaxed);

  int read = atomic_load_explicit(&port->cursors.read, memory_order_acquire);

  int next = (write + 1) & port->capacity_mask;

  if (next == read) return NULL;

  return &port->messages[write];
}

static inline void
bare_broadcast_channel__push_write(bare_broadcast_channel_port_t *port) {
  int write = atomic_load_explicit(&port->cursors.write, memory_order_relaxed);

  int next = (write + 1) & port->capacity_mask;

  atomic_store_explicit(&port->cursors.write, next, memory_order_release);

  if (atomic_load_explicit(&port->state.active, memory_order_acquire)) {
    bare_broadcast_channel__signal(&port->locks.flush, &port->conditions.flush, &port->signals.flush);
  }
}

static inline void
bare_broadcast_channel__release_payload(js_env_t *env, bare_broadcast_channel_payload_t *payload) {
  int err;

  if (atomic_fetch_sub_explicit(&payload->refcount, 1, memory_order_acq_rel) == 1) {
    err = js_release_arraybuffer_backing_store(env, payload->backing_store);
    assert(err == 0);

    free(payload);
  }
}

// Wakes every active peer of a port, flushing and draining each, so they
// re-evaluate the peer set. Used when a port joins or leaves.
static inline void
bare_broadcast_channel__wake_peers(bare_broadcast_channel_port_t *port) {
  bare_broadcast_channel_peers_t peers = bare_broadcast_channel__peers(port->channel, port->id);

  for (bare_broadcast_channel_port_t *peer; (peer = bare_broadcast_channel__peers_next(&peers));) {
    bare_broadcast_channel__wake_peer(peer, true, true);
  }
}

static inline void
bare_broadcast_channel__port_close(bare_broadcast_channel_port_t *port);

static void
bare_broadcast_channel__on_drain(uv_async_t *handle) {
  int err;

  bare_broadcast_channel_port_t *port = handle->data;

  if (port->state.ending && !port->state.exiting) return;

  if (port->state.exiting) {
    if (!port->state.ending) {
      atomic_fetch_and_explicit(&port->segment->active, ~port->bit, memory_order_acq_rel);

      bare_broadcast_channel__wake_peers(port);

      port->state.ending = true;

      err = uv_async_send(&port->signals.end);
      assert(err == 0);
    }
  } else {
    js_env_t *env = port->env;

    js_handle_scope_t *scope;
    err = js_open_handle_scope(env, &scope);
    assert(err == 0);

    js_value_t *ctx;
    err = js_get_reference_value(env, port->ctx, &ctx);
    assert(err == 0);

    js_value_t *on_drain;
    err = js_get_reference_value(env, port->on_drain, &on_drain);
    assert(err == 0);

    js_call_function(env, ctx, on_drain, 0, NULL, NULL);

    err = js_close_handle_scope(env, scope);
    assert(err == 0);
  }
}

static void
bare_broadcast_channel__on_flush(uv_async_t *handle) {
  int err;

  bare_broadcast_channel_port_t *port = handle->data;

  if (port->state.exiting) {
    while (true) {
      bare_broadcast_channel_message_t *message = bare_broadcast_channel__peek_read(port);

      if (message == NULL) break;

      bare_broadcast_channel__release_payload(port->env, message->payload);

      bare_broadcast_channel__push_read(port);
    }
  } else {
    js_env_t *env = port->env;

    js_handle_scope_t *scope;
    err = js_open_handle_scope(env, &scope);
    assert(err == 0);

    js_value_t *ctx;
    err = js_get_reference_value(env, port->ctx, &ctx);
    assert(err == 0);

    js_value_t *on_flush;
    err = js_get_reference_value(env, port->on_flush, &on_flush);
    assert(err == 0);

    js_call_function(env, ctx, on_flush, 0, NULL, NULL);

    err = js_close_handle_scope(env, scope);
    assert(err == 0);
  }
}

static void
bare_broadcast_channel__on_end(uv_async_t *handle) {
  int err;

  bare_broadcast_channel_port_t *port = handle->data;

  port->state.ended = true;

  if (!port->state.exiting) {
    js_env_t *env = port->env;

    js_handle_scope_t *scope;
    err = js_open_handle_scope(env, &scope);
    assert(err == 0);

    js_value_t *ctx;
    err = js_get_reference_value(env, port->ctx, &ctx);
    assert(err == 0);

    js_value_t *on_end;
    err = js_get_reference_value(env, port->on_end, &on_end);
    assert(err == 0);

    js_call_function(env, ctx, on_end, 0, NULL, NULL);

    err = js_close_handle_scope(env, scope);
    assert(err == 0);
  }

  bare_broadcast_channel__port_close(port);
}

static void
bare_broadcast_channel__on_close(uv_handle_t *handle) {
  int err;

  bare_broadcast_channel_port_t *port = handle->data;

  if (--port->state.closing != 0) return;

  js_deferred_teardown_t *teardown = port->teardown;

  js_env_t *env = port->env;

  js_handle_scope_t *scope;
  err = js_open_handle_scope(env, &scope);
  assert(err == 0);

  js_value_t *ctx;
  err = js_get_reference_value(env, port->ctx, &ctx);
  assert(err == 0);

  js_value_t *on_destroy;
  err = js_get_reference_value(env, port->on_close, &on_destroy);
  assert(err == 0);

  err = js_delete_reference(env, port->on_drain);
  assert(err == 0);

  err = js_delete_reference(env, port->on_flush);
  assert(err == 0);

  err = js_delete_reference(env, port->on_end);
  assert(err == 0);

  err = js_delete_reference(env, port->on_close);
  assert(err == 0);

  err = js_delete_reference(env, port->ctx);
  assert(err == 0);

  if (!port->state.exiting) js_call_function(env, ctx, on_destroy, 0, NULL, NULL);

  err = js_close_handle_scope(env, scope);
  assert(err == 0);

  err = js_finish_deferred_teardown_callback(teardown);
  assert(err == 0);

  // Release the slot so a later connection can reuse it. This must happen only
  // once the port has fully torn down: its active bit is long cleared, its
  // queue drained, and the libuv handles backing it closed, so no other thread
  // can still observe or signal this incarnation. The port allocation itself is
  // kept so the reused slot starts from the same backing memory.
  atomic_fetch_and_explicit(&port->segment->claimed, ~port->bit, memory_order_release);
}

static void
bare_broadcast_channel__on_teardown(js_deferred_teardown_t *handle, void *data) {
  int err;

  bare_broadcast_channel_port_t *port = data;

  port->state.exiting = true;

  if (port->state.closing) return;

  err = uv_async_send(&port->signals.drain);
  assert(err == 0);

  err = uv_async_send(&port->signals.flush);
  assert(err == 0);
}

static void
bare_broadcast_channel__finalize(js_env_t *env, void *data, void *finalize_hint) {
  bare_broadcast_channel_t *channel = data;

  uint32_t segments = atomic_load_explicit(&channel->segment_count, memory_order_acquire);

  for (uint32_t s = 0; s < segments; s++) {
    bare_broadcast_channel_segment_t *segment = bare_broadcast_channel__segment(channel, s);

    for (uint32_t i = 0; i < BARE_BROADCAST_CHANNEL_SEGMENT_SIZE; i++) {
      bare_broadcast_channel_port_t *port = segment->slots[i];

      if (port == NULL) continue;

      uv_mutex_destroy(&port->locks.drain);
      uv_mutex_destroy(&port->locks.flush);
      uv_mutex_destroy(&port->locks.producer);

      uv_cond_destroy(&port->conditions.drain);
      uv_cond_destroy(&port->conditions.flush);

      free(port);
    }

    free(segment);
  }

  uv_mutex_destroy(&channel->grow);

  free(channel);
}

static js_value_t *
bare_broadcast_channel_init(js_env_t *env, js_callback_info_t *info) {
  int err;

  size_t argc = 1;
  js_value_t *argv[1];

  err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
  assert(err == 0);

  uint32_t capacity = BARE_BROADCAST_CHANNEL_DEFAULT_CAPACITY;

  if (argc >= 1) {
    err = js_get_value_uint32(env, argv[0], &capacity);
    assert(err == 0);
  }

  // The channel backs an externally managed shared array buffer rather than an
  // engine-owned one so that its finalizer can reclaim the lazily allocated
  // segments and ports. They live in process heap referenced from the channel,
  // so they remain valid across every environment sharing the handle.
  bare_broadcast_channel_t *channel = malloc(sizeof(bare_broadcast_channel_t));

  channel->port_capacity = bare_broadcast_channel__round_capacity(capacity);

  atomic_init(&channel->segment_count, 0);

  err = uv_mutex_init(&channel->grow);
  assert(err == 0);

  // The channel is not yet shared, so a plain clear of the table is sufficient
  // to initialise every segment pointer to NULL.
  memset(channel->segments, 0, sizeof(channel->segments));

  js_value_t *handle;
  err = js_create_external_sharedarraybuffer(env, (void *) channel, sizeof(bare_broadcast_channel_t), bare_broadcast_channel__finalize, NULL, &handle);
  assert(err == 0);

  return handle;
}

// Attempts to claim a free slot in a segment, returning the claimed bit index
// or -1 if the segment is full.
static inline int
bare_broadcast_channel__try_claim(bare_broadcast_channel_segment_t *segment) {
  uint64_t claimed = atomic_load_explicit(&segment->claimed, memory_order_acquire);

  while (true) {
    uint64_t available = ~claimed;

    if (available == 0) return -1;

    int bit = __builtin_ctzll(available);

    if (atomic_compare_exchange_weak_explicit(&segment->claimed, &claimed, claimed | (1ull << bit), memory_order_acq_rel, memory_order_acquire)) {
      return bit;
    }
  }
}

static js_value_t *
bare_broadcast_channel_port_init(js_env_t *env, js_callback_info_t *info) {
  int err;

  size_t argc = 6;
  js_value_t *argv[6];

  err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
  assert(err == 0);

  assert(argc == 6);

  bare_broadcast_channel_t *channel;
  err = js_get_sharedarraybuffer_info(env, argv[0], (void **) &channel, NULL);
  assert(err == 0);

  // Claim the lowest free slot in an existing segment, growing the directory by
  // a segment if every published segment is full. Slots are released once a
  // port has fully torn down (see bare_broadcast_channel__on_close), so they
  // are reused by later connections rather than exhausted.
  bare_broadcast_channel_segment_t *segment = NULL;
  int bit = -1;
  uint32_t id = 0;

  uint32_t segments = atomic_load_explicit(&channel->segment_count, memory_order_acquire);

  for (uint32_t s = 0; s < segments; s++) {
    segment = bare_broadcast_channel__segment(channel, s);

    bit = bare_broadcast_channel__try_claim(segment);

    if (bit >= 0) {
      id = s * BARE_BROADCAST_CHANNEL_SEGMENT_SIZE + bit;
      break;
    }
  }

  if (bit < 0) {
    uv_mutex_lock(&channel->grow);

    // Re-scan under the growth mutex in case a peer freed a slot or published a
    // new segment while we waited.
    segments = atomic_load_explicit(&channel->segment_count, memory_order_acquire);

    for (uint32_t s = 0; s < segments; s++) {
      segment = bare_broadcast_channel__segment(channel, s);

      bit = bare_broadcast_channel__try_claim(segment);

      if (bit >= 0) {
        id = s * BARE_BROADCAST_CHANNEL_SEGMENT_SIZE + bit;
        break;
      }
    }

    if (bit < 0) {
      if (segments >= BARE_BROADCAST_CHANNEL_MAX_SEGMENTS) {
        uv_mutex_unlock(&channel->grow);

        err = js_throw_error(env, NULL, "Channel has reached the maximum number of connected ports");
        assert(err == 0);

        return NULL;
      }

      segment = malloc(sizeof(bare_broadcast_channel_segment_t));

      atomic_init(&segment->claimed, 1ull);
      atomic_init(&segment->active, 0);

      memset(segment->slots, 0, sizeof(segment->slots));

      // Publish the segment pointer before bumping the count so a reader that
      // observes the higher count is guaranteed to see the pointer.
      atomic_store_explicit(&channel->segments[segments], segment, memory_order_release);
      atomic_store_explicit(&channel->segment_count, segments + 1, memory_order_release);

      bit = 0;
      id = segments * BARE_BROADCAST_CHANNEL_SEGMENT_SIZE;
    }

    uv_mutex_unlock(&channel->grow);
  }

  uv_loop_t *loop;
  err = js_get_env_loop(env, &loop);
  assert(err == 0);

  bare_broadcast_channel_port_t *port = segment->slots[bit];

  if (port == NULL) {
    // First use of this slot: allocate the port together with its message ring
    // and initialise the synchronisation primitives that live for the lifetime
    // of the slot. Peers lock a port's producer mutex whenever they write to or
    // signal it, including while it is closing or being reused by a later
    // connection, so this backing memory must remain valid and must never be
    // reinitialised underneath them.
    uint32_t capacity = channel->port_capacity;

    port = malloc(sizeof(bare_broadcast_channel_port_t) + capacity * sizeof(bare_broadcast_channel_message_t));

    port->channel = channel;
    port->segment = segment;
    port->bit = 1ull << bit;
    port->id = id;
    port->capacity_mask = capacity - 1;

#define V(lock) \
  err = uv_mutex_init(&port->locks.lock); \
  assert(err == 0);
    V(drain)
    V(flush)
    V(producer)
#undef V

#define V(condition) \
  err = uv_cond_init(&port->conditions.condition); \
  assert(err == 0);
    V(drain)
    V(flush)
#undef V

    // We hold this slot exclusively via its claimed bit, and no peer reads the
    // slot pointer until the active bit below is published, so a plain store is
    // safe here.
    segment->slots[bit] = port;
  }

  port->env = env;

  // Reset the per-incarnation state in case this slot previously backed a now
  // closed port.
  port->state.ending = false;
  port->state.ended = false;
  port->state.closing = 0;
  port->state.exiting = false;

  atomic_store_explicit(&port->state.active, false, memory_order_relaxed);

  atomic_store_explicit(&port->cursors.read, 0, memory_order_relaxed);
  atomic_store_explicit(&port->cursors.write, 0, memory_order_relaxed);

  err = js_create_reference(env, argv[1], 1, &port->ctx);
  assert(err == 0);

  err = js_create_reference(env, argv[2], 1, &port->on_drain);
  assert(err == 0);

  err = js_create_reference(env, argv[3], 1, &port->on_flush);
  assert(err == 0);

  err = js_create_reference(env, argv[4], 1, &port->on_end);
  assert(err == 0);

  err = js_create_reference(env, argv[5], 1, &port->on_close);
  assert(err == 0);

  err = js_add_deferred_teardown_callback(env, bare_broadcast_channel__on_teardown, (void *) port, &port->teardown);
  assert(err == 0);

#define V(signal) \
  err = uv_async_init(loop, &port->signals.signal, bare_broadcast_channel__on_##signal); \
  assert(err == 0); \
  port->signals.signal.data = (void *) port;
  V(drain)
  V(flush)
  V(end)
#undef V

  atomic_store_explicit(&port->state.active, true, memory_order_release);

  // Publishing the active bit makes this port discoverable to peers. The
  // release pairs with the acquire loads peers use to read the active words,
  // ensuring the slot pointer and initialisation above are visible.
  atomic_fetch_or_explicit(&segment->active, port->bit, memory_order_acq_rel);

  // Nudge every existing peer so it observes the new peer and emits its count.
  bare_broadcast_channel__wake_peers(port);

  err = uv_async_send(&port->signals.flush);
  assert(err == 0);

  js_value_t *result;
  err = js_create_uint32(env, id, &result);
  assert(err == 0);

  return result;
}

static js_value_t *
bare_broadcast_channel_port_wait_drain(js_env_t *env, js_callback_info_t *info) {
  int err;

  size_t argc = 2;
  js_value_t *argv[2];

  err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
  assert(err == 0);

  assert(argc == 2);

  bare_broadcast_channel_t *channel;
  err = js_get_sharedarraybuffer_info(env, argv[0], (void **) &channel, NULL);
  assert(err == 0);

  unsigned int id;
  err = js_get_value_uint32(env, argv[1], &id);
  assert(err == 0);

  bare_broadcast_channel_port_t *port = bare_broadcast_channel__port(channel, id);

  uv_mutex_lock(&port->locks.drain);

  while (true) {
    bool any_peers = false;
    bool any_full = false;

    bare_broadcast_channel_peers_t peers = bare_broadcast_channel__peers(channel, id);

    for (bare_broadcast_channel_port_t *peer; (peer = bare_broadcast_channel__peers_next(&peers));) {
      any_peers = true;

      if (bare_broadcast_channel__peek_write(peer) == NULL) {
        any_full = true;
        break;
      }
    }

    if (!any_peers) break;
    if (!any_full) break;

    uv_cond_wait(&port->conditions.drain, &port->locks.drain);
  }

  uv_mutex_unlock(&port->locks.drain);

  return NULL;
}

static js_value_t *
bare_broadcast_channel_port_wait_flush(js_env_t *env, js_callback_info_t *info) {
  int err;

  size_t argc = 3;
  js_value_t *argv[3];

  err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
  assert(err == 0);

  assert(argc == 3);

  bare_broadcast_channel_t *channel;
  err = js_get_sharedarraybuffer_info(env, argv[0], (void **) &channel, NULL);
  assert(err == 0);

  unsigned int id;
  err = js_get_value_uint32(env, argv[1], &id);
  assert(err == 0);

  bool had_peers;
  err = js_get_value_bool(env, argv[2], &had_peers);
  assert(err == 0);

  bare_broadcast_channel_port_t *port = bare_broadcast_channel__port(channel, id);

  uv_mutex_lock(&port->locks.flush);

  while (bare_broadcast_channel__peek_read(port) == NULL) {
    if (port->state.ending) break;

    uint32_t peers = bare_broadcast_channel__count_peers(channel, id);

    if (peers > 0) had_peers = true;
    else if (had_peers) break;

    uv_cond_wait(&port->conditions.flush, &port->locks.flush);
  }

  uv_mutex_unlock(&port->locks.flush);

  return NULL;
}

static js_value_t *
bare_broadcast_channel_port_read(js_env_t *env, js_callback_info_t *info) {
  int err;

  size_t argc = 2;
  js_value_t *argv[2];

  err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
  assert(err == 0);

  assert(argc == 2);

  bare_broadcast_channel_t *channel;
  err = js_get_sharedarraybuffer_info(env, argv[0], (void **) &channel, NULL);
  assert(err == 0);

  unsigned int id;
  err = js_get_value_uint32(env, argv[1], &id);
  assert(err == 0);

  bare_broadcast_channel_port_t *port = bare_broadcast_channel__port(channel, id);

  bare_broadcast_channel_message_t *message = bare_broadcast_channel__peek_read(port);

  js_value_t *result;

  if (message) {
    bare_broadcast_channel_payload_t *payload = message->payload;

    err = js_create_sharedarraybuffer_with_backing_store(env, payload->backing_store, NULL, NULL, &result);
    assert(err == 0);

    bare_broadcast_channel__release_payload(env, payload);

    bare_broadcast_channel__push_read(port);
  } else {
    err = js_get_null(env, &result);
    assert(err == 0);
  }

  return result;
}

static js_value_t *
bare_broadcast_channel_port_write(js_env_t *env, js_callback_info_t *info) {
  int err;

  size_t argc = 3;
  js_value_t *argv[3];

  err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
  assert(err == 0);

  assert(argc == 3);

  bare_broadcast_channel_t *channel;
  err = js_get_sharedarraybuffer_info(env, argv[0], (void **) &channel, NULL);
  assert(err == 0);

  unsigned int id;
  err = js_get_value_uint32(env, argv[1], &id);
  assert(err == 0);

  uint32_t self_segment = id / BARE_BROADCAST_CHANNEL_SEGMENT_SIZE;
  uint64_t self_bit = 1ull << (id & BARE_BROADCAST_CHANNEL_SEGMENT_MASK);

  js_value_t *result;

  // Snapshot the active word of every published segment. The snapshot freezes
  // the set of peers we will operate on so the lock, recheck, and unlock phases
  // below all agree on membership even as ports join or leave concurrently.
  uint32_t segments = atomic_load_explicit(&channel->segment_count, memory_order_acquire);

  uint64_t snapshot[BARE_BROADCAST_CHANNEL_MAX_SEGMENTS];
  uint32_t peers = 0;

  for (uint32_t s = 0; s < segments; s++) {
    bare_broadcast_channel_segment_t *segment = bare_broadcast_channel__segment(channel, s);

    uint64_t active = atomic_load_explicit(&segment->active, memory_order_acquire);

    if (s == self_segment) active &= ~self_bit;

    snapshot[s] = active;
    peers += __builtin_popcountll(active);
  }

  if (peers == 0) {
    err = js_get_boolean(env, true, &result);
    assert(err == 0);

    return result;
  }

  // Phase 1: lock every candidate peer's producer mutex in ascending id order.
  // The consistent order across all writers prevents deadlock.
  for (uint32_t s = 0; s < segments; s++) {
    uint64_t bits = snapshot[s];

    if (bits == 0) continue;

    bare_broadcast_channel_segment_t *segment = bare_broadcast_channel__segment(channel, s);

    while (bits) {
      int b = __builtin_ctzll(bits);
      bits &= bits - 1;

      uv_mutex_lock(&segment->slots[b]->locks.producer);
    }
  }

  // Phase 2: recheck liveness now that we hold the locks and drop any peer that
  // ended after the snapshot.
  for (uint32_t s = 0; s < segments; s++) {
    uint64_t bits = snapshot[s];

    if (bits == 0) continue;

    bare_broadcast_channel_segment_t *segment = bare_broadcast_channel__segment(channel, s);

    uint64_t live = bits;

    while (bits) {
      int b = __builtin_ctzll(bits);
      bits &= bits - 1;

      bare_broadcast_channel_port_t *peer = segment->slots[b];

      if (!atomic_load_explicit(&peer->state.active, memory_order_acquire)) {
        uv_mutex_unlock(&peer->locks.producer);
        live &= ~(1ull << b);
        peers--;
      }
    }

    snapshot[s] = live;
  }

  if (peers == 0) {
    err = js_get_boolean(env, true, &result);
    assert(err == 0);

    return result;
  }

  // Phase 3: only commit if every live peer has room, so a message reaches all
  // peers or none and the caller can apply uniform backpressure.
  bool all_have_room = true;

  for (uint32_t s = 0; s < segments && all_have_room; s++) {
    uint64_t bits = snapshot[s];

    if (bits == 0) continue;

    bare_broadcast_channel_segment_t *segment = bare_broadcast_channel__segment(channel, s);

    while (bits) {
      int b = __builtin_ctzll(bits);
      bits &= bits - 1;

      if (bare_broadcast_channel__peek_write(segment->slots[b]) == NULL) {
        all_have_room = false;
        break;
      }
    }
  }

  if (!all_have_room) {
    for (uint32_t s = 0; s < segments; s++) {
      uint64_t bits = snapshot[s];

      if (bits == 0) continue;

      bare_broadcast_channel_segment_t *segment = bare_broadcast_channel__segment(channel, s);

      while (bits) {
        int b = __builtin_ctzll(bits);
        bits &= bits - 1;

        uv_mutex_unlock(&segment->slots[b]->locks.producer);
      }
    }

    err = js_get_boolean(env, false, &result);
    assert(err == 0);

    return result;
  }

  // Phase 4: publish the payload to every live peer and release its lock.
  bare_broadcast_channel_payload_t *payload = malloc(sizeof(bare_broadcast_channel_payload_t));
  atomic_init(&payload->refcount, peers);

  err = js_get_sharedarraybuffer_backing_store(env, argv[2], &payload->backing_store);
  assert(err == 0);

  for (uint32_t s = 0; s < segments; s++) {
    uint64_t bits = snapshot[s];

    if (bits == 0) continue;

    bare_broadcast_channel_segment_t *segment = bare_broadcast_channel__segment(channel, s);

    while (bits) {
      int b = __builtin_ctzll(bits);
      bits &= bits - 1;

      bare_broadcast_channel_port_t *peer = segment->slots[b];

      bare_broadcast_channel_message_t *message = bare_broadcast_channel__peek_write(peer);

      message->payload = payload;

      bare_broadcast_channel__push_write(peer);

      uv_mutex_unlock(&peer->locks.producer);
    }
  }

  err = js_get_boolean(env, true, &result);
  assert(err == 0);

  return result;
}

static js_value_t *
bare_broadcast_channel_port_end(js_env_t *env, js_callback_info_t *info) {
  int err;

  size_t argc = 2;
  js_value_t *argv[2];

  err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
  assert(err == 0);

  assert(argc == 2);

  bare_broadcast_channel_t *channel;
  err = js_get_sharedarraybuffer_info(env, argv[0], (void **) &channel, NULL);
  assert(err == 0);

  unsigned int id;
  err = js_get_value_uint32(env, argv[1], &id);
  assert(err == 0);

  bare_broadcast_channel_port_t *port = bare_broadcast_channel__port(channel, id);

  atomic_fetch_and_explicit(&port->segment->active, ~port->bit, memory_order_acq_rel);

  bare_broadcast_channel__wake_peers(port);

  port->state.ending = true;

  err = uv_async_send(&port->signals.end);
  assert(err == 0);

  return NULL;
}

static js_value_t *
bare_broadcast_channel_port_ref(js_env_t *env, js_callback_info_t *info) {
  int err;

  size_t argc = 2;
  js_value_t *argv[2];

  err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
  assert(err == 0);

  assert(argc == 2);

  bare_broadcast_channel_t *channel;
  err = js_get_sharedarraybuffer_info(env, argv[0], (void **) &channel, NULL);
  assert(err == 0);

  unsigned int id;
  err = js_get_value_uint32(env, argv[1], &id);
  assert(err == 0);

  bare_broadcast_channel_port_t *port = bare_broadcast_channel__port(channel, id);

#define V(signal) \
  uv_ref((uv_handle_t *) &port->signals.signal);
  V(drain)
  V(flush)
  V(end)
#undef V

  return NULL;
}

static js_value_t *
bare_broadcast_channel_port_unref(js_env_t *env, js_callback_info_t *info) {
  int err;

  size_t argc = 2;
  js_value_t *argv[2];

  err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
  assert(err == 0);

  assert(argc == 2);

  bare_broadcast_channel_t *channel;
  err = js_get_sharedarraybuffer_info(env, argv[0], (void **) &channel, NULL);
  assert(err == 0);

  unsigned int id;
  err = js_get_value_uint32(env, argv[1], &id);
  assert(err == 0);

  bare_broadcast_channel_port_t *port = bare_broadcast_channel__port(channel, id);

#define V(signal) \
  uv_unref((uv_handle_t *) &port->signals.signal);
  V(drain)
  V(flush)
  V(end)
#undef V

  return NULL;
}

static inline void
bare_broadcast_channel__port_close(bare_broadcast_channel_port_t *port) {
  if (port->state.closing) return;

  atomic_fetch_and_explicit(&port->segment->active, ~port->bit, memory_order_acq_rel);

  atomic_store_explicit(&port->state.active, false, memory_order_release);

  uv_mutex_lock(&port->locks.producer);

  while (true) {
    int read = atomic_load_explicit(&port->cursors.read, memory_order_relaxed);
    int write = atomic_load_explicit(&port->cursors.write, memory_order_acquire);

    if (read == write) break;

    bare_broadcast_channel__release_payload(port->env, port->messages[read].payload);

    int next = (read + 1) & port->capacity_mask;
    atomic_store_explicit(&port->cursors.read, next, memory_order_release);
  }

  uv_mutex_unlock(&port->locks.producer);

  port->state.closing = 3;

#define V(signal) \
  uv_close((uv_handle_t *) &port->signals.signal, bare_broadcast_channel__on_close);
  V(drain)
  V(flush)
  V(end)
#undef V
}

static js_value_t *
bare_broadcast_channel_port_peers(js_env_t *env, js_callback_info_t *info) {
  int err;

  size_t argc = 2;
  js_value_t *argv[2];

  err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
  assert(err == 0);

  assert(argc == 2);

  bare_broadcast_channel_t *channel;
  err = js_get_sharedarraybuffer_info(env, argv[0], (void **) &channel, NULL);
  assert(err == 0);

  unsigned int id;
  err = js_get_value_uint32(env, argv[1], &id);
  assert(err == 0);

  uint32_t peers = bare_broadcast_channel__count_peers(channel, id);

  js_value_t *result;
  err = js_create_uint32(env, peers, &result);
  assert(err == 0);

  return result;
}

static js_value_t *
bare_broadcast_channel_exports(js_env_t *env, js_value_t *exports) {
  int err;

#define V(name, fn) \
  { \
    js_value_t *val; \
    err = js_create_function(env, name, -1, fn, NULL, &val); \
    assert(err == 0); \
    err = js_set_named_property(env, exports, name, val); \
    assert(err == 0); \
  }

  V("channelInit", bare_broadcast_channel_init)

  V("portInit", bare_broadcast_channel_port_init)
  V("portWaitDrain", bare_broadcast_channel_port_wait_drain)
  V("portWaitFlush", bare_broadcast_channel_port_wait_flush)
  V("portRead", bare_broadcast_channel_port_read)
  V("portWrite", bare_broadcast_channel_port_write)
  V("portEnd", bare_broadcast_channel_port_end)
  V("portRef", bare_broadcast_channel_port_ref)
  V("portUnref", bare_broadcast_channel_port_unref)
  V("portPeers", bare_broadcast_channel_port_peers)
#undef V

  js_value_t *max_ports;
  err = js_create_uint32(env, BARE_BROADCAST_CHANNEL_MAX_PORTS, &max_ports);
  assert(err == 0);
  err = js_set_named_property(env, exports, "maxPorts", max_ports);
  assert(err == 0);

  return exports;
}

BARE_MODULE(bare_broadcast_channel, bare_broadcast_channel_exports)