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

Implement freelist class #783

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/internal_modules/roc_core/atomic.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ template <class T> class Atomic : public NonCopyable<> {
return AtomicOps::fetch_add_seq_cst(var_, val) + val;
}

//! Atomic addition (postfix).
inline T postfix_add(T val) {
return AtomicOps::fetch_add_seq_cst(var_, val);
}

//! Atomic subtraction.
inline T operator-=(T val) {
return AtomicOps::fetch_sub_seq_cst(var_, val) - val;
Expand Down
71 changes: 71 additions & 0 deletions src/internal_modules/roc_core/free_list_impl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2015 Roc Streaming authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include "roc_core/free_list_impl.h"
#include "roc_core/free_list_node.h"
#include "roc_core/panic.h"

namespace roc {
namespace core {

FreeListImpl::FreeListImpl() {
head_->next = NULL;
}

FreeListImpl::~FreeListImpl() {
}

FreeListData* FreeListImpl::pop_front() {
FreeListData* current_head = head_;
if (current_head == NULL) {
roc_panic("list: is empty");
}
while (current_head != NULL) {
FreeListData* prev_head = current_head;
uint32_t refs = current_head->free_list_refs;
if ((refs & REFS_MASK) == 0
|| !current_head->free_list_refs.compare_exchange(refs, refs + 1)) {
current_head = head_;
continue;
}
FreeListData* next = current_head->next;
if (head_.compare_exchange(current_head, next)) {
if (!((current_head->free_list_refs & SHOULD_BE_ON_FREELIST) == 0)) {
roc_panic("ABA problem");
}
current_head->free_list_refs += SUB_2;
return current_head;
}
refs = prev_head->free_list_refs.postfix_add(SUB_1);
if (refs == SHOULD_BE_ON_FREELIST + 1) {
add_knowing_refcount_is_zero(prev_head);
}
}
return NULL;
}

void FreeListImpl::push_front(FreeListData* node) {
if (node->free_list_refs.postfix_add(SHOULD_BE_ON_FREELIST) == 0) {
add_knowing_refcount_is_zero(node);
}
}

void FreeListImpl::add_knowing_refcount_is_zero(FreeListData* node) {
FreeListData* current_head = head_;
while (true) {
node->next = current_head;
node->free_list_refs = 1;
if (!head_.compare_exchange(current_head, node)) {
if ((node->free_list_refs.postfix_add(SHOULD_BE_ON_FREELIST - 1)) == 1)
continue;
}
return;
}
}
} // namespace core
} // namespace roc
56 changes: 56 additions & 0 deletions src/internal_modules/roc_core/free_list_impl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2015 Roc Streaming authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

//! @file roc_core/free_list_impl.h
//! @brief Intrusive doubly-linked list implementation.

#ifndef ROC_CORE_FREE_LIST_IMPL_H_
#define ROC_CORE_FREE_LIST_IMPL_H_

#include "roc_core/atomic.h"
#include "roc_core/free_list_node.h"
#include "roc_core/noncopyable.h"
#include "roc_core/stddefs.h"

namespace roc {
namespace core {

//! Intrusive singly-linked list implementation class.
//! Handles FreeList infrastructure independent of templated type for FreeList.
//! Ownership handling is left to the main FreeList class.
class FreeListImpl : public NonCopyable<> {
public:
FreeListImpl();
~FreeListImpl();

//! Get first list node.
FreeListData* front() const;

//! Remove first node and return.
FreeListData* pop_front();

//! Insert node into list.
void push_front(FreeListData* node);

private:
static void check_is_member_(const FreeListData* node, const FreeListImpl* list);

//! Add node knowing that it is not part of a free list.
void add_knowing_refcount_is_zero(FreeListData* node);

Atomic<FreeListData*> head_;
static const uint32_t SHOULD_BE_ON_FREELIST = 0x80000000;
static const uint32_t REFS_MASK = 0x7FFFFFFF;
static const uint32_t SUB_1 = 0xFFFFFFFF;
static const uint32_t SUB_2 = 0xFFFFFFFE;
};

} // namespace core
} // namespace roc

#endif // ROC_CORE_FREE_LIST_IMPL_H_
62 changes: 62 additions & 0 deletions src/internal_modules/roc_core/free_list_node.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2015 Roc Streaming authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

//! @file roc_core/free_list_node.h
//! @brief Linked list node.

#ifndef ROC_CORE_FREE_LIST_NODE_H_
#define ROC_CORE_FREE_LIST_NODE_H_

#include "roc_core/atomic.h"
#include "roc_core/macro_helpers.h"
#include "roc_core/noncopyable.h"
#include "roc_core/panic.h"
#include "roc_core/stddefs.h"

namespace roc {
namespace core {

//! Free list node internal data.
struct FreeListData {
//! Next free list element.
Atomic<FreeListData*> next;

//! Reference counter for free list.
Atomic<uint32_t> free_list_refs;

FreeListData()
: next(NULL)
, free_list_refs(0) {
}
};

//! Base class for Free List element.
//! @remarks
//! Object should inherit this class to be able to be a member of List.
//! Tag allows to inherit multiple copies of FreeListNode and include same
//! object into multiple lists.
template <class Tag = void> class FreeListNode : public NonCopyable<FreeListNode<Tag> > {
public:
//! Get pointer to parent node from pointer to internal data.
static FreeListNode* list_node(FreeListData* data) {
return ROC_CONTAINER_OF(data, FreeListNode, list_data_);
}

//! Get pointer to internal data.
FreeListData* list_data() const {
return &free_list_data_;
}

private:
mutable FreeListData free_list_data_;
};

} // namespace core
} // namespace roc

#endif // ROC_CORE_FREE_LIST_NODE_H_
26 changes: 26 additions & 0 deletions src/internal_modules/roc_core/freelist.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2024 Roc Streaming authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

//! @file roc_core/freelist.h
//! @brief TODO.

#ifndef ROC_CORE_FREELIST_H_
#define ROC_CORE_FREELIST_H_

namespace roc {
namespace core {

template <class T, class Node = ListNode<> > class List : public NonCopyable<> {
public:
FreeList()
: member_initialization {
}
}
} // namespace core

#endif // ROC_CORE_FREELIST_H_
Loading