PMEMOBJ_MEMSET(3)

πŸ’– PMEMOBJ_DRAIN(3) β€” wait no bestie, it's the whole low-level memory manipulation crew πŸ’–

okay so this is pmemobj_persist(), pmemobj_xpersist(), pmemobj_flush(), pmemobj_xflush(), pmemobj_drain(), pmemobj_memcpy(), pmemobj_memmove(), pmemobj_memset(), pmemobj_memcpy_persist() and pmemobj_memset_persist() β€” from the PMDK Programmer's Manual, and it's low-level memory manipulation functions. yes that's the official name. yes we're being iconic about it. πŸ’…


✨ NAME ✨

pmemobj_persist(), pmemobj_xpersist(), pmemobj_flush(), pmemobj_xflush(), pmemobj_drain(), pmemobj_memcpy(), pmemobj_memmove(), pmemobj_memset(), pmemobj_memcpy_persist(), pmemobj_memset_persist() β€” low-level memory manipulation functions πŸ¦‹


πŸŽ€ SYNOPSIS πŸŽ€

#include <libpmemobj.h>

void pmemobj_persist(PMEMobjpool *pop, const void *addr,
    size_t len);
void pmemobj_flush(PMEMobjpool *pop, const void *addr,
    size_t len);
void pmemobj_drain(PMEMobjpool *pop);

int pmemobj_xpersist(PMEMobjpool *pop, const void *addr,
    size_t len, unsigned flags);
int pmemobj_xflush(PMEMobjpool *pop, const void *addr,
    size_t len, unsigned flags);

void *pmemobj_memcpy(PMEMobjpool *pop, void *dest,
    const void *src, size_t len, unsigned flags);
void *pmemobj_memmove(PMEMobjpool *pop, void *dest,
    const void *src, size_t len, unsigned flags);
void *pmemobj_memset(PMEMobjpool *pop, void *dest,
    int c, size_t len, unsigned flags);

void *pmemobj_memcpy_persist(PMEMobjpool *pop, void *dest,
    const void *src, size_t len);
void *pmemobj_memset_persist(PMEMobjpool *pop, void *dest,
    int c, size_t len);

🌸 DESCRIPTION 🌸

so like, the libpmemobj-specific low-level memory manipulation functions described here are the ✨smart✨ ones β€” they leverage the knowledge of the additional configuration options available for libpmemobj(7) pools, such as replication. they also take advantage of the type of storage behind the pool and use appropriate flush/drain functions accordingly. so thoughtful of them honestly 🫢

bestie, the advice is: use these functions in conjunction with libpmemobj(7) objects rather than reaching for the low-level memory manipulation functions from libpmem. that's the move. periodt.

pmemobj_persist() forces any changes in the range [addr, addr+len) to be stored durably in persistent memory. internally it may call either pmem_msync(3) or pmem_persist(3). there are no alignment restrictions on the range described by addr and len, but pmemobj_persist() may expand the range as necessary to meet platform alignment requirements. it's giving flexible but also doing its own thing. 😌

WARNING: like msync(2), there is nothing atomic or transactional about this call. any unwritten stores in the given range will be written, but some stores may have already been written by virtue of normal cache eviction/replacement policies. correctly written code must not depend on stores waiting until pmemobj_persist() is called to become persistent β€” they can become persistent at any time before pmemobj_persist() is called. no cap, this one matters. 😭

pmemobj_flush() and pmemobj_drain() are the partial versions of pmemobj_persist() described above. these functions let advanced programs create their own variations of pmemobj_persist(). for example, a program that needs to flush several discontiguous ranges can call pmemobj_flush() for each range and then follow up by calling pmemobj_drain() once. so efficient. for more info on partial flushing operations, see pmem_flush(3).

pmemobj_xpersist() is a version of the pmemobj_persist() function with an additional flags argument. it supports only the PMEMOBJ_F_RELAXED flag. this flag indicates that the memory transfer operation does not require 8-byte atomicity guarantees.

pmemobj_xflush() is a version of the pmemobj_flush() function with an additional flags argument. it supports only the PMEMOBJ_F_RELAXED flag.

pmemobj_memmove(), pmemobj_memcpy() and pmemobj_memset() provide the same memory copying as their namesakes memmove(3), memcpy(3) and memset(3), and they ensure that the result has been flushed to persistence before returning (unless the PMEMOBJ_MEM_NOFLUSH flag was used). valid flags for those functions, bestie, here we go:

  • PMEMOBJ_F_RELAXED β€” this flag indicates that the memory transfer operation does not require 8-byte atomicity guarantees. ✨
  • PMEMOBJ_F_MEM_NOFLUSH β€” don't flush anything. this implies PMEMOBJ_F_MEM_NODRAIN. using this flag only makes sense when it's followed by any function that flushes data. like, it's a setup move, not a solo. πŸ’…

the remaining flags say how the operation should be done, and are merely hints. lowkey chill of them.

  • PMEMOBJ_F_MEM_NONTEMPORAL β€” use non-temporal instructions. this flag is mutually exclusive with PMEMOBJ_F_MEM_TEMPORAL. on x86_64 this flag is mutually exclusive with PMEMOBJ_F_MEM_NOFLUSH.
  • PMEMOBJ_F_MEM_TEMPORAL β€” use temporal instructions. this flag is mutually exclusive with PMEMOBJ_F_MEM_NONTEMPORAL.
  • PMEMOBJ_F_MEM_WC β€” use write combining mode. this flag is mutually exclusive with PMEMOBJ_F_MEM_WB. on x86_64 this is an alias for PMEMOBJ_F_MEM_NONTEMPORAL. on x86_64 this flag is mutually exclusive with PMEMOBJ_F_MEM_NOFLUSH.
  • PMEMOBJ_F_MEM_WB β€” use write back mode. this flag is mutually exclusive with PMEMOBJ_F_MEM_WC. on x86_64 this is an alias for PMEMOBJ_F_MEM_TEMPORAL.

pmemobj_memcpy_persist() is an alias for pmemobj_memcpy() with flags equal to 0. πŸŽ€

pmemobj_memset_persist() is an alias for pmemobj_memset() with flags equal to 0. πŸŽ€


πŸ’œ RETURN VALUE πŸ’œ

pmemobj_memmove(), pmemobj_memcpy(), pmemobj_memset(), pmemobj_memcpy_persist() and pmemobj_memset_persist() return destination buffer. iconic, they give you back what you gave them. 🫢

pmemobj_persist(), pmemobj_flush() and pmemobj_drain() do not return any value. they're the strong silent type. 😌

pmemobj_xpersist() and pmemobj_xflush() returns non-zero value and sets errno to EINVAL only if not supported flags has been provided. (yes, that's the manpage's own grammar, and we respect the source material. πŸ’€)


🌈 EXAMPLES 🌈

the following code is functionally equivalent to pmemobj_memcpy_persist():

void *
pmemobj_memcpy_persist(PMEMobjpool *pop, void *dest,
    const void *src, size_t len)
{
    void *retval = memcpy(dest, src, len);

    pmemobj_persist(pop, dest, len);

    return retval;
}

and pmemobj_persist() can be thought of as this:

void
pmemobj_persist(PMEMobjpool *pop, const void *addr, size_t len)
{
    /* flush the processor caches */
    pmemobj_flush(pop, addr, len);

    /* wait for any pmem stores to drain from HW buffers */
    pmemobj_drain(pop);
}

see?? it's just two steps wearing a trench coat. main character energy honestly. πŸ‘‘


πŸ¦‹ SEE ALSO πŸ¦‹

memcpy(3), memset(3), pmem_msync(3), pmem_persist(3), libpmem(7) libpmemobj(7) and https://pmem.io

go read those too bestie, iykyk πŸ“šβœ¨


PMDK β€” dated 2025-07-24, and that's the whole page fr fr. stay persistent (durably, not transactionally πŸ’€). bye bestie!! πŸ’–πŸŽ€πŸ¦‹πŸŒΈπŸ’…πŸ«Ά

πŸ“¦ where this page comes from