Serene Runtime 1.0.0-dev
C runtime for the Serene programming language
Loading...
Searching...
No Matches
spsc_ring.h
Go to the documentation of this file.
1/* -*- C -*-
2 * Serene programming language
3 * Copyright (C) 2019-2026 Sameer Rahmani <[email protected]>
4 *
5 * This library is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19/** @file
20 A mutable single producer, single consumer ring of fixed size elements.
21
22 One side pushes, the other pops, with no lock between them. The producer owns
23 `tail` and the consumer owns `head`; both are monotonic counters, so the live
24 slot for an index is `index & mask` and the capacity is a power of two. The
25 acquire/release pairing makes it correct on weakly ordered processors, not only
26 x86. A push releases the written element through `tail`, which the consumer
27 reads with acquire; a pop releases the freed slot through `head`, which the
28 producer reads with acquire.
29*/
30
31#pragma once
32
33#include <stdbool.h>
34#include <stddef.h>
35#include <stdint.h>
36#include <string.h>
37
38#include "serene/rt/errors.h"
39
40// IMPORTANT: This type should be UNSIGNED
41#define SRN_SPSC_RING_CAP_TYPE uint32_t
42
43typedef struct srn_context_t srn_context_t;
44
45typedef struct srn_spsc_ring_t {
47
48 /// Consumer index. Only the consumer advances it.
49 _Atomic size_t head;
50
51 /// Producer index. Only the producer advances it.
52 _Atomic size_t tail;
53
56 size_t elem_size;
57
58 /// `cap * elem_size` bytes. Typically owned by who ever owns
59 /// the ring itself.
60 unsigned char *buf;
62
63/**
64 * Set up a ring by allocating the `buf` to be the size of `cap * elem_size`.
65 * And it will choose the `cap` to be `2 ^ magnitude`.
66 */
67srn_spsc_ring_t *srn_spsc_ring_make(srn_context_t *ctx, size_t magnitude, size_t elem_size);
68
69/**
70 * Producer side. Copy `*elem` into the ring. Returns false when the ring is
71 * full, leaving it unchanged.
72 */
73bool srn_spsc_ring_push(srn_spsc_ring_t *r, const void *elem);
74
75/**
76 * Consumer side. Copy one element into `*out`. Returns false when the ring is
77 * empty, leaving `*out` untouched.
78 */
79bool srn_spsc_ring_pop(srn_spsc_ring_t *r, void *out);
80
81/**
82 * Whether the ring currently holds no elements. For the consumer this is
83 * exact; for any other observer it is a hint.
84 */
Error handling for the runtime.
bool srn_spsc_ring_push(srn_spsc_ring_t *r, const void *elem)
Producer side.
Definition spsc_ring.c:61
bool srn_spsc_ring_empty(const srn_spsc_ring_t *r)
Whether the ring currently holds no elements.
Definition spsc_ring.c:103
#define SRN_SPSC_RING_CAP_TYPE
Definition spsc_ring.h:41
srn_spsc_ring_t * srn_spsc_ring_make(srn_context_t *ctx, size_t magnitude, size_t elem_size)
Set up a ring by allocating the buf to be the size of cap * elem_size.
Definition spsc_ring.c:27
bool srn_spsc_ring_pop(srn_spsc_ring_t *r, void *out)
Consumer side.
Definition spsc_ring.c:83
size_t elem_size
Definition spsc_ring.h:56
SRN_SPSC_RING_CAP_TYPE cap
Definition spsc_ring.h:54
SRN_SPSC_RING_CAP_TYPE mask
Definition spsc_ring.h:55
_Atomic size_t tail
Producer index. Only the producer advances it.
Definition spsc_ring.h:52
_Atomic size_t head
Consumer index. Only the consumer advances it.
Definition spsc_ring.h:49
unsigned char * buf
cap * elem_size bytes.
Definition spsc_ring.h:60