Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Triple buffering primitive #67

Open
sbahra opened this issue Sep 19, 2015 · 1 comment
Open

Triple buffering primitive #67

sbahra opened this issue Sep 19, 2015 · 1 comment
Assignees

Comments

@sbahra
Copy link
Member

sbahra commented Sep 19, 2015

Taking epoch reclamation principles, SPSC use-case can be made efficient. @pkhuong dumped the following, which is a good starting point for the facility. This is a "concept" below from Paul.

#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <ck_pr.h>

struct buffer_index {
    uint8_t byte;
};

/* We can obv. offset everything for 0 init, but let's keep things clear. */
#define BUFFER_INDEX_INIT = { 1 }

/* Not clear on the fencing; check ck_epoch... */
static inline size_t
buffer_index_read_index(const struct buffer_index *index)
{
    uint8_t byte = ck_pr_load_8(&index->byte);

    return byte >> 4;
}

static inline void
buffer_index_read_done(struct buffer_index *index)
{
    size_t next_read_index, read_index, write_index;
    uint8_t byte = ck_pr_load_8(&index->byte);

    read_index = byte >> 4;
    write_index = byte & 0xF;

    next_read_index = read_index + 1;
    if (next_read_index == 3) {
        next_read_index = 0;
    }

    if (next_read_index != write_index) {
        size_t prev_write_index = (write_index + 2) % 3;
        assert(prev_write_index == next_read_index);

        ck_pr_fence_load_store();
        ck_pr_store_8(&index->byte, (next_read_index << 4) | write_index);
    }

    return;
}

static inline size_t
buffer_index_write_index(const struct buffer_index *index)
{
    uint8_t byte = ck_pr_load_8(&index->byte);

    return byte & 0xF;
}

static inline size_t
buffer_index_write_start(struct buffer_index *index)
{
    size_t next_write_index, read_index, write_index;
    uint8_t byte = ck_pr_load_8(&index->byte);

    read_index = byte >> 4;
    write_index = byte & 0xF;

    next_write_index = write_index + 1;
    if (next_write_index == 3) {
        next_write_index = 0;
    }

    if (next_write_index == read_index) {
        return write_index;
    }

    assert(((read_index + 2) % 3) == next_write_index);
    ck_pr_store_8(&index->byte, (read_index << 4) | next_write_index);
    ck_pr_fence_store();
    return next_write_index;
}
@pkhuong
Copy link
Contributor

pkhuong commented Sep 19, 2015

I used a single byte for compatibility with an earlier prototype, but I'm not convinced that's better than two counters, especially if we expect long, multi-function read or write sections.

@sbahra sbahra assigned sbahra and mhaberler and unassigned sbahra Sep 19, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants