Reputation: 529
I'm getting a segfault when executing this code. Specifically after g_lru_stack.add_node(&lru_node) is called.
Running under GDB shows that the dummy node doesn't look like it has been initialised. Is this to do with how extern globals are initialised? If so any help would be greatly appreciated here.
I have included snippets from both the header and cpp file.
Specifically, my question is this: How can I get LRU_Stack g_lru_stack , declared at the top of object.cc, to call the LRU_Node ctor that takes no arguments.
It seems this ctor never gets called, hence why my dummy node isn't initialised.
class obj_payload;
extern cas_mutex g_lru_stack_mutex;
class LRU_Node {
private:
obj_payload* payload;
LRU_Node* up;
LRU_Node* down;
size_t predicted_bytes_in_cache;
public:
LRU_Node() : payload(nullptr), up(this), down(this), predicted_bytes_in_cache(1337) {} // Dummy ctor
LRU_Node(obj_payload* p) : payload(p), up(nullptr), down(nullptr), predicted_bytes_in_cache(88) {} // Normal Creation of node
//Adds a node to the top of the stack
//Has dummy context
void add_to_stack(LRU_Node* newNode);
//Sets how many bytes of the object are predicted to be in the cache
//Has dummy context
void is_node_in_cache(LRU_Node* node);
//Moves a node to the top of the stack
//Has dummy context
void move_node_to_top(LRU_Node* node);
//Has context of caller
size_t get_predicted_bytes_in_cache();
};
class LRU_Stack {
LRU_Node dummy;
public:
void add_node(LRU_Node* node);
void move_node_to_top(LRU_Node* node);
};
extern LRU_Stack g_lru_stack;
class obj_payload {
typedef uint32_t ctr_t;
private:
ctr_t refcnt;
const uint32_t sz; // size of the data space in bytes
LRU_Node lru_node; // Jordan -- This arg objects node for the LRU_Stack
obj_payload( typeinfo tinfo_,
uint32_t size_,
int refcnt_init=1 )
: refcnt( refcnt_init ),
sz( size_ ),
tinfo( tinfo_ ), lru_node(this) {
g_lru_stack.add_node(&lru_node);
}
#include "object.h"
namespace obj {
//Jordan -- Global LRU_Node Stack
cas_mutex g_lru_stack_mutex;
LRU_Stack g_lru_stack;
//Adds a node to the top of the stack
//Has dummy context
void LRU_Node::add_to_stack(LRU_Node* newNode) {
newNode->down = down; // Set the new nodes previous -> dummys previous
newNode->up = this; // Set new nodes next -> dummy
down->up = newNode; // Dummy next -> new node (i.e. Previous top of stack node up -> newNode)
down = newNode; // Dummy previous -> new node (i.e. Dummy down pointer now links back round to the new node at the top)
}
//Sets how many bytes of the object are predicted to be in the cache
//Has dummy context
void LRU_Node::is_node_in_cache(LRU_Node* node) {
size_t total = 0;
LRU_Node* orignal = node;
while (node != this) {
total += node->payload->get_size(); // Add current size to total
node = node->up; // Go to next node
}
node = orignal; //Reset node to the passed in node, then set how many bytes it has contained within cache
if (total <= cache_size) {
node->predicted_bytes_in_cache = node->payload->get_size();
}
else {
node->predicted_bytes_in_cache = (node->payload->get_size()) - (total - cache_size) < node->payload->get_size() ? (node->payload->get_size()) - (total - cache_size) : 0;
}
}
//Moves a node to the top of the stack
//Has dummy context
void LRU_Node::move_node_to_top(LRU_Node* node) {
if (down != node) { // Check that the node to move is not already top of stack
node->down->up = node->up;
node->up->down = node->down;
if (down == node->up) { // If the node is seccond top of stack
node->up->up = node;
}
node->down = down;
node->up = this;
down->up = node;
down = node;
}
}
//Has context of caller
size_t LRU_Node::get_predicted_bytes_in_cache() {
return predicted_bytes_in_cache;
}
//Has dummy context
bool LRU_Node::is_empty() {
return (up == this);
}
void LRU_Stack::add_node(LRU_Node* node) {
g_lru_stack_mutex.lock();
dummy.add_to_stack(node);
g_lru_stack_mutex.unlock();
}
void LRU_Stack::move_node_to_top(LRU_Node* node) {
g_lru_stack_mutex.lock();
dummy.is_node_in_cache(node);
dummy.move_node_to_top(node);
g_lru_stack_mutex.unlock();
}
Upvotes: 0
Views: 60
Reputation: 45654
"extern globals" are not objects (unless they include an initializer): They are forward-declarations.
Global objects are initialized in two phases:
Seems like UB got you there.
To solve the error, do one of these:
Put the object as a static in an accessor function. Init will be on first use (thread-safe!).
Type& getTypeSingleton() {
static Type x/*optional initializer*/;
return x;
}
Upvotes: 2