PMEMOBJ_LIST_INSERT(3)
π pmemobj_list_insert(3) β PMDK Programmer's Manual π
okay bestie, sit down, hydrate, and let me tell you about the absolute icon of persistent lists. this is pmemobj_list_insert(3) and its whole friend group from the PMDK Programmer's Manual. they're giving non-transactional persistent atomic lists, and honestly? we're obsessed. β¨
β¨ NAME β¨
pmemobj_list_insert(), pmemobj_list_insert_new(), pmemobj_list_move(), pmemobj_list_remove() β non-transactional persistent atomic lists functions π¦
πΈ SYNOPSIS πΈ
#include <libpmemobj.h>
int pmemobj_list_insert(PMEMobjpool *pop, size_t pe_offset, void *head,
PMEMoid dest, int before, PMEMoid oid);
PMEMoid pmemobj_list_insert_new(PMEMobjpool *pop, size_t pe_offset,
void *head, PMEMoid dest, int before, size_t size,
uint64_t type_num, pmemobj_constr constructor, void arg);
int pmemobj_list_move(PMEMobjpool *pop,
size_t pe_old_offset, void *head_old,
size_t pe_new_offset, void *head_new,
PMEMoid dest, int before, PMEMoid oid);
int pmemobj_list_remove(PMEMobjpool *pop, size_t pe_offset,
void *head, PMEMoid oid, int free);
π DESCRIPTION π
so, in addition to the container operations on internal object collections that we already talked about in pmemobj_first(3), libpmemobj(7) also hands you a whole mechanism for organizing persistent objects into user-defined, persistent, atomic, circular, doubly-linked lists. yeah. that's a lot of adjectives. they earned every one of them. π
every routine and macro that operates on these persistent lists gives you atomicity with respect to any power-fail interruptions. translation: if an operation gets torn apart by a program failure or a system crash, on recovery it is guaranteed to be either entirely completed or entirely discarded β no in-between, no messy half-state. the lists, the persistent memory heap, and the internal object containers all stay in a consistent state. it's giving main character energy for crash safety. π
the persistent atomic circular doubly linked lists support this whole feature set, bestie:
- Insertion of an object at the head of the list, or at the end of the list.
- Insertion of an object before or after any element in the list.
- Atomic allocation and insertion of a new object at the head of the list, or at the end of the list.
- Atomic allocation and insertion of a new object before or after any element in the list.
- Atomic moving of an element from one list to the specific location on another list.
- Removal of any object in the list.
- Atomic removal and freeing of any object in the list.
- Forward or backward traversal through the list.
a list is headed by a list_head structure that holds the object handle of the first element on the list. the elements are doubly linked, so any arbitrary element can be removed without needing to traverse the list first (so efficient, so thoughtful π). new elements can be added before or after an existing element, at the head of the list, or at the tail of the list. and a list can be traversed in either direction. forward, backward, whatever, it's versatile.
the user-defined structure of each element must contain a field of type list_entry β that field holds the object handles to the previous and next element on the list. both the list_head and the list_entry structures are declared in <libpmemobj.h>. π
the functions below are intended to be used outside transactions β the transactional variants live in the manpages for the functions mentioned at TRANSACTIONAL OBJECT MANIPULATION in libpmemobj(7). heads up: operations performed using this non-transactional API are independent from their transactional counterparts. so if any non-transactional allocations or list manipulations happen inside an open transaction, the changes will not be rolled back if that transaction gets aborted or interrupted.
π¨ bestie this is the important one: non-transactional stuff inside a transaction does NOT get rolled back. do not expect it to. it will simply not.
π¦ the shared arguments (dest + before) π¦
the list insertion and move functions use a common set of arguments to define where an object will be inserted into the list.
dest identifies the element before or after which the object will be inserted β or, if dest is OID_NULL, it indicates that the object should be inserted at the head or tail of the list.
before determines where the object will be inserted:
POBJ_LIST_DEST_BEFOREβ insert the element before the existing elementdestPOBJ_LIST_DEST_AFTERβ insert the element after the existing elementdestPOBJ_LIST_DEST_HEADβ whendestisOID_NULL, insert the element at the head of the listPOBJ_LIST_DEST_TAILβ whendestisOID_NULL, insert the element at the tail of the list
NOTE: Earlier versions oflibpmemobj(7)do not definePOBJ_LIST_DEST_BEFOREandPOBJ_LIST_DEST_AFTER. Use1for before, and0for after.
π the functions themselves π
β pmemobj_list_insert()
inserts the element represented by object handle oid into the list referenced by head, at the location specified by dest and before as described above. pe_offset specifies the offset of the structure that connects the elements in the list.
all the handles head, dest and oid must point to objects allocated from memory pool pop. and head and oid cannot be OID_NULL. π«Ά
β pmemobj_list_insert_new()
atomically allocates a new object of given size and type type_num, then inserts it into the list referenced by head at the location specified by dest and before as described above. pe_offset specifies the offset of the structure that connects the elements in the list.
the handles head and dest must point to objects allocated from memory pool pop.
before returning, pmemobj_list_insert_new() calls the constructor function, passing the pool handle pop, the pointer to the newly allocated object ptr, and the arg argument. and it's guaranteed that the allocated object is either properly initialized, or β if the allocation is interrupted before the constructor completes β the memory space reserved for the object is reclaimed. no leaks, no crumbs, we clean up after ourselves. β¨
head cannot be OID_NULL.
the allocated object is also added to the internal container associated with type_num, as described in POBJ_FOREACH(3). π
β pmemobj_list_move()
moves the object represented by object handle oid from the list referenced by head_old to the list referenced by head_new, inserting it at the location specified by dest and before as described above. pe_old_offset and pe_new_offset specify the offsets of the structures that connect the elements in the old and new lists, respectively.
all the handles head_old, head_new, dest and oid must point to objects allocated from memory pool pop. and head_old, head_new and oid cannot be OID_NULL. π«
β pmemobj_list_remove()
removes the object represented by object handle oid from the list referenced by head. if free is set, it also removes the object from the internal object container and frees the associated memory space. pe_offset specifies the offset of the structure that connects the elements in the list.
both head and oid must point to objects allocated from memory pool pop and cannot be OID_NULL. π«
π₯ RETURN VALUE π₯
on success, pmemobj_list_insert(), pmemobj_list_remove() and pmemobj_list_move() return 0. π
on error, they return -1 and set errno appropriately. π
on success, pmemobj_list_insert_new() returns a handle to the newly allocated object. if the constructor returns a non-zero value, the allocation is canceled, -1 is returned, and errno is set to ECANCELED. on other errors, OID_NULL is returned and errno is set appropriately. π
π SEE ALSO π
pmemobj_first(3), POBJ_FOREACH(3), libpmemobj(7) and https://pmem.io π
and that's the whole page, bestie!! this was PMDK's finest β dated 2025-07-24, straight out of the PMDK Programmer's Manual. now go forth and build your doubly-linked lists, but like... non-transactionally. iykyk. πβ¨π
π¦ where this page comes from
- fedora 43: libpmemobj-devel 2.1.0-4.fc43 Β· BSD-3-Clause
- π the page's license: BSD-3-Clause
- Copyright 2017-2018, Intel Corporation
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms