CK_EPOCH_CALL(3)

πŸ“¦
version 0.7.2 Β· 2 versions
, in alpine 3.24, debian trixie, epel 10, fedora 43, fedora 44, nixos 26.05, nixpkgs unstable, opensuse-leap 16.0, ubuntu questing, ubuntu resolute, ubuntu stonking

πŸ’– CK_EPOCH_CALL(3) β€” the "do it later bestie" manual page πŸ’–

okay so welcome to the ck_epoch_call page from the Concurrency Kit manual, aka libck, and bestie I'm gonna hold your hand through every single line of it, no cap. ✨


🌸 NAME 🌸

ck_epoch_call β€” defer function execution until a grace period πŸ•°οΈ

πŸ“š LIBRARY πŸ“š

Concurrency Kit (link it with libck, so like -lck bestie πŸ’…)

✨ SYNOPSIS ✨

#include <ck_epoch.h>
typedef struct ck_epoch_entry ck_epoch_entry_t;
typedef void ck_epoch_cb_t(ck_epoch_entry_t *);

void
ck_epoch_call(ck_epoch_record_t *record, ck_epoch_entry_t *entry,
    ck_epoch_cb_t *function);

like, that's the whole vibe. three args, no return, we move. 🫢

πŸ’… DESCRIPTION πŸ’…

okay so the tea: ck_epoch_call(3) will defer the execution of the function pointed to by function until a grace period has been detected in epoch. yes literally, it's giving "not right now, later, when it's safe."

the function gets handed the pointer you specified with entry β€” that's its little gift bag πŸŽ€

and when does it actually run? at some time in the future, via calls to ck_epoch_reclaim(3), ck_epoch_barrier(3) or ck_epoch_poll(3). so like, you don't call it, those do. iykyk. πŸ‘‘

πŸ”₯ EXAMPLE πŸ”₯

here's the whole thing, verbatim, because I am NOT about to mess with code that works:

#include <ck_epoch.h>
#include <ck_stack.h>
#include <stdlib.h>

/*
 * epoch was previously initialized with ck_epoch_init.
 */
ck_epoch_t *epoch;

struct object {
        int value;
        ck_epoch_entry_t epoch_entry;
};
static struct object *global;

CK_EPOCH_CONTAINER(struct object, epoch_entry, object_container)

void
destroy_object(ck_epoch_entry_t *e)
{
        struct object *o = object_container(e);

        free(o);
        return;
}

void
function(void)
{
        ck_epoch_record_t *record;
        struct object *n;

        record = malloc(sizeof *record);
        ck_epoch_register(&epoch, record, NULL);

        n = malloc(sizeof *n);
        if (n == NULL)
                return;

        n->value = 1;

        /*
         * We are using an epoch section here because there are multiple
         * writers. It is also an option to use other forms of blocking
         * write-side synchronization such as mutexes.
         */
        ck_epoch_begin(record);
        n = ck_pr_fas_ptr(&global, n);
        ck_epoch_end(record);

        /* Defer destruction of previous object. */
        ck_epoch_call(record, &n->epoch_entry, destroy_object);

        /* Poll epoch sub-system in non-blocking manner. */
        ck_epoch_poll(record);
        return;
}

see how destroy_object is the callback and &n->epoch_entry is the entry? yeah. iconic behaviour fr fr. 🌈

πŸŽ€ RETURN VALUES πŸŽ€

this function has no return value. it returns nothing. void. silent. mysterious. main character energy honestly. πŸ’€

πŸ™ˆ ERRORS πŸ™ˆ

the object pointed to by record must have been previously registered via ck_epoch_register(3). like, if you didn't register it, bestie, that's on you. don't come crying to me. 😭

πŸ¦‹ SEE ALSO πŸ¦‹

more lore available at http://concurrencykit.org/ ⭐


and that's the page bestie!! this one came from the Concurrency Kit manual, and it's dated September 2, 2012 β€” yeah she's vintage, she's an elder, and she still slays. πŸ’œπŸ§šπŸ“

k byeeee, go read your grace periods. periodt. πŸ’–

πŸ“¦ where this page comes from