Linked list in a shared memory segment - c

I am currently working on a part where a linked list, one linked list node has multiple variable data, is to be saved in a shared memory segment so that another program can read that list and do operations accordingly.
I have previously worked on socket programming, but sending a stream of data does not fulfill my purpose, as I have to do validation based on reading one node/element at a time. So, of all the IPC's, I think shared memory would be the best as it also has good performance than others(in this case, not generally).
The following is the struct that I have made:
struct DNode {
char *polname;
char *devname;
char *status;
char *srczone;
char *dstzone;
char *srcaddr;
char *dstaddr;
char *srcuser;
char *app;
char *service;
char *urlcategory;
char *action;
char *vulnerability;
char *value;
struct DNode *next;
};
struct DNode *head = NULL;
struct DList {
DNode pool[MAX_DNODE]; // fixed-size space for nodes
size_t npool; // used space in pool
size_t pfree; // pointer to re-use freed nodes
size_t head; // global list head
};
DList *dlist;
DNode *dnode_alloc(void)
{
if (dlist->pfree != DNULL) {
DNode *node = dlist->pool + dlist->pfree;
dlist->pfree = dlist->pool[dlist->pfree].next;
return node;
} else {
if (dlist->npool < MAX_DNODE) return &dlist->pool[dlist->npool++];
}
return NULL;
}
void dnode_free(DNode *node)
{
if (node) {
node->next = dlist->pfree;
dlist->pfree = node - dlist->pool;
}
}
DNode *dnode(size_t index)
{
return (index == DNULL) ? NULL : dlist->pool + index;
}
DNode *dnode_next(const DNode *node)
{
return dnode(node->next);
}
DNode *dnode_push(size_t *head, const char *str)
{
DNode *node = dnode_alloc();
if (node) {
strncpy(node->polname, str, sizeof(node->polname));
node->next = *head;
*head = node - dlist->pool;
}
return node;
}
void dnode_pop(size_t *head)
{
if (*head != DNULL) {
size_t next = dlist->pool[*head].next;
dnode_free(&dlist->pool[*head]);
*head = next;
}
}
int list_insert_front(struct node* new_node) {
struct node *temp;
temp = malloc(sizeof *temp);
if (temp && new_node) {
memcpy(temp, new_node, sizeof(struct node));
temp->next = head;
head = temp;
return 1;
}
return 0;
}
int main(int argc, char **argv)
{
struct Dnode *iter = head;
int shmid;
xmlDocPtr doc;
xmlNode *root_element = NULL;
if (argc != 2)
{
printf("\nInvalid argument\n");
return(1);
}
doc = xmlReadFile(argv[1], NULL, XML_PARSE_NOBLANKS | XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NONET);
if (doc == NULL)
{
fprintf(stderr, "Document not parsed successfully.\n");
return 0;
}
root_element = xmlDocGetRootElement(doc);
if (root_element == NULL)
{
fprintf(stderr, "empty document\n");
xmlFreeDoc(doc);
return 0;
}
printf("Root Node is %s\n", root_element->name);
traverse_dom_trees(root_element);
shmid = shmget(IPC_PRIVATE, sizeof(DList), IPC_CREAT | 0660);
if (shmid < 0) exit (1);
dlist = shmat(shmid, NULL, 0);
if (dlist == (void *) (-1)) exit(1);
dlist->head = DNULL;
dlist->pfree = DNULL;
dlist->npool = 0;
while(iter != NULL){
dnode_push(&dlist->head, head->polname);
dnode_pop(&dlist->head);
iter = head->next;
}
shmdt(dlist);
xmlFreeDoc(doc); // free document
xmlCleanupParser(); // Free globals
return 0;
}
As you can see, I have also included an XML parser part in the main function so as to give you an idea of what I am taking as an input. But the part where I am stuck is how to save/use this struct inside a shared memory, and making it easy for the other program to access it.
Please can somebody provide me with some pseudo-code for the same as I have never used such C functionalities before and am absolutely clueless on how to approach this.
Any and all suggestions are welcome and am thankful in advance.
Edit 1
Using Centos7 on a virtual machine since somebody pointed out that mentioning the platform would be fruitful.
Edit 2
Just added some code to implement shared memory segments, and it does not give me any such errors. What my concern is:
Is it doing what I intended?
Is the approach correct?
I know I am currently just pushing one element but this sure is right, right?
Am I wasting time and efforts trying to work it out using shared memory?

In general you cannot warrant that a shared memory segment will occupy the same virtual address range in one process than in other. So you'll have a problem when trying to interpret the values in the pointer fields, as they represent the address of the pointed object in the virtual address space of the process that wrote there the pointer value and this can be different if both processes map the shared memory segment at different places.
You can pass the mmap call a pointer to tell the system where in your virtual address space you want the segment to be mapped, so the shared pointers point to the same place in both virtual address spaces. But that pointer is only a hint, and the operating system is not forced to follow your pointer.
There are two solutions for this. The first is to offset the pointer values, so you construct your virtual address space pointer from the one you see in the shared segment. The second is to ensure your memory segments both are mapped to the same address. This has to be coordinated between both processes (but it has to be done only once, at memory mapping) as the place that is good for one can be forbidden for the other (because it has mapped some other thing there)
In 64bit architectures this is easy, as you have a zillion virtual addresses to map the segment to, and probably you can select an address without clashing with other subsystem. Think that in 32bit systems, normally shared libraries consume a bunch of addresses for the data segments of the modules herein, and the stacks makes provision for large amounts of memory, and the heap also... so you have to plan the thing before an attempt of putting both segments in a shared, identical address.
NOTE
In your particular case, that almost all the fields of the structure are pointers, this applies to all the fields, and not only the list linking ones. Not only all the list nodes must lie in the shared segment... also all the strings, and everything you access that is shared.

You will need to:
Setup shared memory on your platform - see here.
In your program, call shm_open to open the shared memory and use mmap to access it using a pointer - see here.
Accessing shared memory from different processes/thread must use some arbitration/mutual exclusion mechanism - see here.

Related

Custom implementation of dynamic memory allocators in C

So for my C assignment, I need to implement a dynamic memory allocator with a similar interface to the standard library like malloc, free, realloc. I'm implementing the allocator as a library of functions that can be called by other programs. Virtual heap will be managed by a simple buddy allocation algorithm.
My functions given are:
void * virtual_sbrk(int32_t increment);
pretty much the same as the real-world sbrk and brk syscalls. I don't need to implement this.
void init_allocator(void * heapstart, uint8_t initial_size, uint8_t min_size);
This function will be called once at the beginning and initialise the virtual heap.
void * virtual_malloc(void * heapstart, uint32_t size);
mallocs memory
int virtual_free(void * heapstart, void * ptr);
frees memory
void * virtual_realloc(void * heapstart, void * ptr, uint32_t size);
reallocates memory
void virtual_info(void * heapstart);
prints the current state of the buddy allocator to standard output.
This is my current problem:
How do you initialise the heap and implement malloc without anything in the first place? Like I can't use malloc or any of the pre existing allocator functions. So far I've tried to use a linked list with nodes containing the memory as a value. Eg if initial size is 3 and min size is 1, I'd have 5 nodes with the root containing 8 bytes, two more containing 4 bytes each , and lastly 2 more contining 2 bytes each. But I'm still confused on how to use sbrk or how the heap is structured in the first place. I've browsed online resources but still confused on how to construct the heap memory.
Following is my code so far:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
struct node{
size_t memory;
struct node *nextInLine;
};
void printNode(const struct node *nd, const char *comment){
if(nd == NULL){
printf("%s is null\n", comment);
}
else{
printf("%s: memory:%d address:%p nextInLine:%p\n",
comment,
nd->memory,
nd,
nd->nextInLine);
}
}
void printList(const struct node *list){
printf("Printing List:\n");
const struct node *t;
t = list;
if(t == NULL){
printf("current node is empty\n");
}
else{
while(t){
printNode(t, "node");
t = t->nextInLine;
}
}
}
void * virtual_sbrk(int32_t increment) {
void *p = malloc(increment);
return p;
}
uint8_t return_init_size(uint8_t size){
return size;
}
struct node *getNewNode(const uint8_t memory_size){
struct node *newNode = NULL;
double two = 2;
size_t m_size = memory_size;
double result = pow(two, m_size);
newNode = virtual_sbrk(result);
if(newNode != NULL){
newNode->memory = result;
newNode->nextInLine = NULL;
}
else{
printf("Allocation error: newNode is still NULL\n");
}
return newNode;
}
void init_allocator(void * heapstart, uint8_t initial_size, uint8_t min_size) {
//error catchers
if(initial_size == 0){
printf("Initial size is 0\n");
}
if(initial_size < min_size){
printf("initial_size is smaller than min_size\n");
}
//initialising the virtual heap using a linked array with nodes the memory size of 2^some_size
uint8_t i = initial_size;
struct node *first = heapstart;
heapstart = first;
struct node *tail = NULL;
while(i >= min_size){
if(first == NULL){
first = getNewNode(i);
if(first != NULL){
tail = first;
}
}
else{
tail->nextInLine = getNewNode(i);
if(tail->nextInLine != NULL){
tail = tail->nextInLine;
}
tail->nextInLine = getNewNode(i);
if(tail->nextInLine != NULL){
tail = tail->nextInLine;
}
}
i -= 1;
}
printList(first);
}
void * virtual_malloc(void * heapstart, uint32_t size) {
if(size == 0){
return NULL;
}
return NULL;
}
int virtual_free(void * heapstart, void * ptr) {
return 1;
}
void * virtual_realloc(void * heapstart, void * ptr, uint32_t size) {
return NULL;
}
void virtual_info(void * heapstart) {
}
It would be great if someone could help explain how I would go about doing this, as in the structure I need to follow, if that makes sense.
You can use both sbrk and mmap as glibc malloc does.
glibc malloc works with threads, with something called arenas.
When malloc is initialized it calls sbrk to extend the mapped memory.
When big allocations happen, or new threads are created malloc ends up calling mmap.
mmap allocates a new mapping in the address space of the process.
sbrk extends the current mapping to make it bigger.
Simple example of sbrk:
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#define HEAP_SZ 0x8000
int main(void) {
void *p = sbrk(0);
printf("current break addr = %p\n", p);
sbrk(HEAP_SZ);
void *n = sbrk(0);
printf("new break addr = %p\n", n);
return 0;
}
The first call (with argument 0) returns the current program break.
When specifying a size greater than 0, program break is extended, so on the next call with argument 0, the new program break will be returned.
You can do then something like this:
unsigned long heap_mem_sz = 0;
void *heap_start_addr = NULL;
void init_heap(void) {
void *p = sbrk(0);
#if DEBUG
printf("current break addr = %p\n", p);
#endif
sbrk(HEAP_SZ);
heap_mem_sz = (unsigned long)HEAP_SZ;
void *n = sbrk(0);
#if DEBUG
printf("new break addr = %p\n", n);
#endif
heap_start_addr = (void *)n;
return;
}
Having that information on globals allows you to continue the development of the allocator implementation.
You can call init_heap() the first time an allocation is requested.
Now you can return that allocation and craft a "top chunk".
It will be a chunk with the same structure than the others but containing all the memory from which allocations take memory, and it gets shrinked on allocations.
Also, you will need to do something once the heap memory is full, so consider calling syscalls like mmap or sbrk again.
Linked lists on malloc are used for bins. They are used for searching freed chunks that can satisfy new allocations so you reuse chunks that are not used anymore.
For such linked list, you can create a global:
struct heap_chunk *freed_chain = NULL
When memory is requested, you first check if freed_chain is NULL, if not, traverse the linked list until a block compatible with the user request is found, or the next pointer is NULL.
If any of those chunks is valid, you will need to unlink that chunk from the linked list, and make the previous chunk point to the next one, so no more memory requests access to it as now it is allocated and not freed.
On freeing memory, you would need to link a new chunk to that linked list.
Obviously on malloc, for optimization purposes this is more complex, and some different bins with different size requirements and different properties exist to speed up allocations.

Stack pop/push segmentation fault wrong same numbers

I'm writing a stack that's a linked list of data (void type). The data I am testing, is
struct my_data {
int val;
char name[60];
};
struct my_stack_node {
void *data;
struct my_stack_node *next;
};
struct my_stack {
int size;
struct my_stack_node *first;
};
the data used to be pushed, is initialized like this:
s1 = my_stack_init(sizeof(struct my_data));
if (!s1) {
puts("Error in my_stack_init()");
exit(1);
}
printf("\ns1 initialized, size of data: %lu\n", sizeof(struct my_data));
for (int i = 0; i < NODES; i++) {
data = malloc(sizeof(struct my_data)); // We must allocate static memory
data->val = i;
sprintf(data->name, "Value %d", i);
if (my_stack_push(s1, data)) {
puts("Error in my_stack_push()");
exit(1);
}
} //s1 is the stack we are using here
And pushing them by my_stack_push(s2, data); stack and the data as the arguments.
My push function is this one:
int my_stack_push(struct my_stack *stack, void *data){
if(stack == NULL && sizeof(data)> 0){
printf("Null Stack or data size error.\n");
//la pila debe existir
return -1;
}
else {
struct my_stack_node *nodeToPush = malloc(sizeof(struct my_stack_node));
nodeToPush -> data = data;
if(stack -> first == NULL) {
nodeToPush -> next = NULL;
stack -> first = nodeToPush;
}
else {
nodeToPush -> next = stack -> first;
stack -> first = nodeToPush;
}
}
return 0;
}
And my pop function is this one
void *my_stack_pop(struct my_stack *stack){
struct my_stack_node *node = stack->first;
if(stack->first == NULL){
return 0;
}
stack->first = node->next;
void *ret = node->data;
free(node);
return ret;
}
But in my main, when I pop them and try to compare them, I get a segmentation fault:
while ((data1 = my_stack_pop(s1))) {
data2 = my_stack_pop(fs1);
printf("Node of s1: (%d, %s)\t", data1->val, data1->name);
printf("Node of fs1: (%d, %s)\n", data2->val, data2->name);
if (!data2 || data1->val != data2->val || my_strcmp(data1->name, data2->name)) {
printf("Data in s1 and fs1 are not the same.\n (data1->val: %d <> data2->val: %d) o (data1->name: %s <> data2->name: "
"%s)\n",
data1->val, data2->val, data1->name, data2->name);
exit(1);
}
size1 = sizeof(*data1);
size2 = sizeof(*data2);
free(data1);
free(data2);
}
printf("size of data from s1: %d\t", size1);
printf("size of data from fs1: %d\n", size2);
(the 2 stacks are a copy of each other so what I inputed, should be the same I read). When I return the whole node in the pop function (not the data, but the whole my_stack_node), everything is right.. but wrong:
Comparing the data...
Node of s1: (0, Value 0) //good one
Node of fs1: (0, Value 0)
8
8
Node of s1: (-1203217792, NV) //here it begins to go all wrong
Node of fs1: (-1203217792, NV)
8
8
Node of s1: (-1203217792, NV)
Node of fs1: (-1203217792, NV)
8
8
Node of s1: (-1203217792, NV)
Node of fs1: (-1203217792, NV)
8
8
Node of s1: (0, )
Node of fs1: (0, )
double free or corruption (fasttop)
Aborted (core dumped)
Size is the same as the data inputed, but the value and name are bad (even in the non copied stack), which is supposed to be:
New node in s1: (0, Value 0)
New node in s1: (1, Value 1)
New node in s1: (2, Value 2)
New node in s1: (3, Value 3)
New node in s1: (4, Value 4)
New node in s1: (5, Value 5)
New node in s1: (6, Value 6)
New node in s1: (7, Value 7)
New node in s1: (8, Value 8)
New node in s1: (9, Value 9)
But when I return (on my stack pop) the data itself like in the code, I get core dumped in the print of the test.(data that has 8 bytes of length, like the one input).
When I return the node (size = 64) it prints correctly wrong data, but when I return the data(size = 8 (like the one pushed)), it core faults.
If I push the same data and read the same data (as it shown when I return node because even when weird output, are the same), why do I get a core segmentation fault when I return the data that's supposed to print like the example above?
It looks that it only happens when I read the data2, and not data1. This is the code I use to write and read the file :
Write:
int my_stack_write(struct my_stack *stack, char *filename){
int count = 0;
struct my_stack_node *aux =malloc(sizeof(struct my_stack_node));
FILE *file = fopen(filename, "wb");
if(stack->first != NULL){
aux = stack->first;
count++;
while(aux->next != NULL){
printf("New node in s1: (%p)\n", aux->data);
fwrite(aux ,sizeof(struct my_stack_node), 1, file);
aux = aux->next;
count++;
}
printf("New node in s1: (%p)\n", aux->data);
fwrite(aux ,sizeof(struct my_stack_node), 1, file);
}
fclose(file);
return count;
}
Read:
struct my_stack *my_stack_read(char *filename){
struct my_stack *stackRead = my_stack_init(sizeof(struct my_stack_node));
struct my_stack_node *stackNode = malloc(sizeof(struct my_stack_node));
FILE *file = fopen(filename, "rb");
if(!file){
puts("Impossible obrir el fitxer");
return NULL;
}else{
while(fread(stackNode, sizeof(struct my_stack_node), 1, file)){
printf("New node in fs1: (%p)\n", stackNode->data);
stackNode = (struct my_stack_node*) stackNode;
my_stack_push(stackRead, stackNode->data);
}
fclose(file);
struct my_stack *InvertedStack = my_stack_init(sizeof(struct my_stack_node));
struct my_stack_node *aux = malloc(sizeof(struct my_stack_node));
while(my_stack_len(stackRead) !=0){
printf("Inverting the stack\n");
aux = my_stack_pop(stackRead);
my_stack_push(InvertedStack, aux);
}
return InvertedStack;
}
}
Thank you to anyone that helps.
MCVE of the program, so people can check the whole code and help better:
test2.c:
https://codeshare.io/244eN4
my_lib.c:
https://codeshare.io/G7L8Ab
my_lib.h:
https://codeshare.io/5DzZOm
With this, you should have a broader view and an executable once compiled on what's happening to me.
you have problems in my_stack_pop
void *ret = malloc(sizeof(struct my_stack_node));
ret = node->data;
The malloc is useless (and create a memory leak), and you miss to free node too
You can replace these 2 lines by :
void * ret = node->data;
free(node);
Other remarks
in my_stack_push check the error before to do the allocation, or free nodeToPush in case of the error else you have a memory leak
sizeof(x) where x is a void* will always values 4 if you are on a 32b CPU, and 8 if it is a 64b CPU. sizeof is not strlen for instance
Finally concerning the 2 stacks are a copy of each other so what I inputed, should be the same it is difficult to help you because you do not say how you cloned the stack
(remarks after your edit)
In my_stack_write
do not initialize aux with an allocation, you again have a memory leak doing that.
to dump the memory of my_stack_node do not work, your goal is to save the data (contains of my_data), not the cell pointing to the data
In my_stack_read
it is useless to use a dynamic allocation for my_stack_node, it can be placed into the stack ( struct my_stack_node stackNode; ), else do not forget to free it because you again introduce a memory leak.
same error when you read a my_stack_node, you have to read the saved data (a my_data)
stackNode = (struct my_stack_node*) stackNode; that does nothing because it sets stackNode with itself
my_stack_push(stackRead, stackNode->data); does not have the expected result because stackNode->data has a wrong value read in the file.
Both read and write are wrong, this is why the two stack do not have the same contents
Designing good, reliable and consistent API and libraries is a very hard job, especially in programming languages in which creating interfaces is somewhat harder then in object oriented languages.
I mean to be really nice, but the code you posted has memory leaks, unhandled errors, undefined behavior and bad design. The sizeof operator is misused. I can only guess you fail to understand how the memory allocation really works and the concept of a pointer and general void* pointer.
Well, let's go.
So the reasons the code will seg fault is:
As suspected, the data to which the stack points is invalid. Indeed it is mallocated, but is subsequently freed some lines later:
for (int i = 0; i < NODES; i++) {
struct ... * data = malloc(sizeof(struct my_data));
my_stack_push(s1, data); // pushes the data pointer to the stack
void *data1 = my_stack_pop(s1); // pops the data pointer to the stack
...
assert(data1 == data); // data and data1 are the same
free(data1); // and data get's freed
// the memory behind both data and data1 is freed in this point
// thus the pointer s1.first->node->data is invalid
// as the code runs in loop, effectively all the data in this stack are invalid
}
You double free pointer in the main() in the while loop. Both s1 and fs1 are obtained from calling my_stack_read on the same file - thus logically they should contain the same values. As they store the same values, stored pointers to data are the same, thus freeing the pointer will also free and invalidate the second pointer in the second list. Double free is undefined behavior and I guess should result in something similar to segmentation fault on normal systems.
while ((data1 = my_stack_pop(s1))) {
data2 = my_stack_pop(fs1);
...
assert(data1 == data2); // same pointers
free(data1);
free(data2); // double free corruption - seg fault
}
After fixing the errors the code will run and print "All tests passed", live version available here. Anyway below are some notes:
There is no need to allocate an array of stacks in my_stack_init:
struct my_stack *my_stack_init(int size){
struct my_stack *stack = malloc(sizeof(struct my_stack_node) * size);
...
stack now points to size count of sizeof(struct my_stack_node) bytes of memory. You need only a single my_stack_node structure. Also, sizeof returns size_t. A better version would be:
struct my_stack *my_stack_init(size_t size){
struct my_stack *stack = malloc(sizeof(struct my_stack_node));
...
my_stack_read leaks memory:
struct my_stack_node *aux = malloc(sizeof(struct my_stack_node));
...
aux = my_stack_pop(stackRead);
Indentation in the code you posted is a bit off. Try to keep one indentation style, I could advertise the good old' Linux kernel coding style but you can use anything but be consistent. Also your code could use some restructuring - limiting the scope of variables or like removing else after return NULL may increase readability.
sizeof returns size_t. The proper way to print size_t is to use "%zu" printf modifier. You can print pointers by casting to void* and using "%p" printf modifier.
Generally, this is really good work, but you need to understand that pointers point to data and are data themselves (as they have value). Currently your implementation stores only pointers to the data, thus client code is responsible for freeing the pointers. It's easy to trap yourself in confusion in such implementation. One could rewrite your stack implementation to allocate memory for the node and for the data itself, thus freeing the need for client code to handle the memory in any special manner. It could look like:
int my_stack_push(struct my_stack *stack, void *data) {
...
// allocate memory for new link in the list
struct my_stack_node *nodeToPush = malloc(sizeof(struct my_stack_node));
if (nodeToPush == NULL) abort();
// allocate memory for data itself
nodeToPush->data = malloc(stack->size);
if (nodeToPush->data == NULL) abort();
// memory copy the data into the pointer
memcpy(nodeToPush->data, data, stack->size);
..
In such implementation the stack is responsible in freeing the pointer and stores only copies of the data. Thus all the handles need to be rewritten to support that. The size of the data is available via stack->size and initialized in my_stack_init with the argument.
Storing pointers value in a file seems like a bad idea from serialization point of view. Pointer values change in between runs. Storing pointers to list elements feels exactly bad. It's better to store the memory of the data itself, I see no reason in storing the pointer values of the list. Note that in current implementation the value of stackNode->next is indeed not used in my_stack_read, because it's value has been freed already before. I fail to see why do you even write the value of stackNode->next to the file if you never use it.
So we can store the data itself in the file:
int my_stack_write(struct my_stack *stack, char *filename){
...
node = stack->first;
void *data = node->data;
// write the data behind the node to the file
if (fwrite(data, stack->size, 1, file) != 1) {
return -100;
}
}
In a similar way we could rewrite my_stack_read:
struct my_stack *my_stack_read(char *filename, size_t size) {
...
struct my_stack *stack = stack_init(size);
...
void *newdata = malloc(stack->size);
while (fread(newdata, stack->size, 1, file)) {
my_stack_push(stack, newdata);
}
free(newdata); // as in my proposed implementation my_stack stores copy
// of the memory behind the pointers, we can safely manage own memory
// by freeing the pointer
}

Adding a struct to linkedlist in c

I'm trying to add Process-structs to a linked list. Their definitions are as follows.
typedef struct {
char name[2];
int duration;
int priority;
int arrival;
} Process;
typedef struct {
Process p;
struct LinklistNode* next;
} LinklistNode;
The function that I'm using to create the process looks like this.
Process makeProcess(char nameIn[2], int durationIn, int priorityIn, int arrivalIn){
Process p = (Process*) malloc(sizeof(Process)); //getting an error
p->name = nameIn;
p->duration = durationIn;
p->arrival = arrivalIn;
p->priority = priorityIn;
}
I'm not sure that I'm doing that part right, and I'm also not sure that I should be returning a process or have it void, as this process "should" go into the linked list.
My code for creating a linked list node is as follows:
LinklistNode* create_linklist_node(Process pIn) {
LinklistNode* node = (LinklistNode*) malloc(sizeof(LinklistNode));
node->p = pIn;
node->next = NULL;
return node;
}
For a bit more context I'll be calling these functions in main() where I've tokenized a string from a file I'm reading from. I'm wondering the best way to make the Process struct. Right now I have this:
while(!feof(fPointer)){
//the i counter is for the first line in the text file which I want to skip
while ((fgets(singleLine, 1500, fPointer) != NULL) && !(i == 0)){
char *token = strtok (singleLine, delimit);
while(token != NULL){
printf(" %s\n", token);
token = strtok(NULL, delimit);
}
}
i++;
}
Bit of a long question but any references or additional information is always appreciated. Let me know if you have additional questions or need more info on what I'm doing or why I'm doing something. Or if you can find an example of something similar, that would be greatly appreciated as I haven't had much luck with that so far.
Thanks
You seem to have some issues with pointers. In this line
Process p = (Process*)malloc(sizeof(Process)); //getting an error
what you should be doing is
Process *p = malloc(sizeof(Process));
because unlike a new in some other languages, the malloc will just return a void *, (which in pure C can be automatically converted to any other data object pointer type). That pointer stores the address of the memory allocated for your struct. Of course you will also have to return the pointer, thus changing the return type to Process*.
Continuing with your original design, you would also have to store the Process* in the list-node, and consequently pass it to your construction method (LinklistNode* create_linklist_node(Process *pIn)).
You would then have to free both the node and possibly the pointer to the contained struct, if it is no longer used anywhere else, when you destroy the node.
However, given the size of your Process struct, I would suggest something else:
Since you already have your list nodes like this:
typedef struct{
Process p;
struct LinklistNode* next;
}LinklistNode;
You would allocate the memory for the actual process struct inside the node in during the call to create_linklist_node. Then you can just pass in a Process struct that is on the stack and copy it into the struct in the list, which lives in the heap-memory allocated by the create-call. In that case you don't need to dynamically allocate the Process at all, and the pointer issues in the first part become irrelevant.
LinkListNode *create_linklist_node(Process proc)
{
LinklistNode *p = malloc(sizeof *p);
if (p == NULL)
{
perror("Failed to allocate new node: ");
exit(EXIT_FAILURE);
}
p->p = proc;
p->next = NULL;
return p;
}
You would then do something like this:
Process proc = {{'a', 'b'}, 0, 0, 0};
LinklistNode *p = create_linklist_node(proc);
However, it is more common to have a method that directly creates and inserts the node into the list, for example, given:
typedef struct {
LinklistNode *head;
} Linklist; //doing this is kinda optional, using a simple pointer would do too
you could insert at the head of the list by doing something like:
void insert (Linklist *list, Process ins)
{
LinklistNode *tmp = create_linklist_node(ins);
tmp->next = list->head;
list->head = tmp;
}

How to allocate linked list inside struct in shared memory c

I have a linked list inside a struct in C, or so I think.
The structs are:
//Structure of the domain list
typedef struct domains *domain_list;
struct domains{
char *domain;
domain_list next;
}domains_node;
//Structure of the configuration of the server
typedef struct{
int n_threads;
domain_list domain_list;
char* local_domain;
char* named_pipe_statistics;
}server_config;
I tried to enter them in shared memory, I'm sure that the struct is fine, but I don't know if the linked list is correct (Global variables used):
//Initialize shared memory
if((config_shmid = shmget(IPC_PRIVATE, sizeof(server_config), IPC_CREAT|0777)) < 0){
perror("Error in config shmid\n");
exit(1);
}
if((config = (server_config*)shmat(config_shmid, NULL, 0)) == (server_config *)-1){
perror("Error in config shmat\n");
exit(1);
}
if((config_domain_shmid = shmget(IPC_PRIVATE, sizeof(struct domains), IPC_CREAT|0777)) < 0){
perror("Error in domain_list config shmid\n");
exit(1);
}
if((config->domain_list = (domain_list)shmat(config_domain_shmid, NULL, 0)) == (domain_list)-1){
perror("Error in domain_list config shmat\n");
exit(1);
}
This is for process comunication. I need a dynamic (not fixed) linked list, inside a struct, in shared memory.
So, what I need is a way to allocate space in memory for the new nodes I create, and how to link them after. I now it's not with malloc, but answers on this matter just go as "adequate allocation" and I don't know what it is.
You don't say this, but I guess that you use shared memory so that several processes can access the same linked list, either simultaneously or sequentially.
In that case, you can create a shared-memory segment that will hold a pool of nodes plus some control data.
The whole information must be contained in that segment, though, for the other processes to see it. Therefore, your domain member should be a char buffer, not a pointer to a string that lies somewhere else in memory.
All non-null node pointer values will be addresses in the pool, but the shared memory segments will probably be mapped to different addresses on different processes. Therefore, the nodes can't have absolute next pointers. They could keep a relative index into the shared node pool, though. The same applies to the headsm of the lists.
In your linked-list code you should replace the malloc and free with custom functions that fetch a node in the pool or put it back there. Because the pool has a fixed size, the custom malloc can return NULL, for which you should check.
The code below implements a simple linked list with a fixed-sized pool that is contained in a shared memory segment. It keeps all visible data as relative sizes, but operates on node pointers, which you can get with dnode, for local iteration. Because 0 is a valid pool index, there is a special value, DNULL, which describes the null pointer by means of a size_t.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/shm.h>
typedef struct DNode DNode;
typedef struct DList DList;
#define MAX_DNODE 32 // Max. domain string length
#define MAX_DLEN 64 // Max. number of list nodes
#define DNULL (MAX_DLEN + 1) // NULL value
struct DNode {
char domain[64];
size_t next;
};
struct DList {
DNode pool[MAX_DNODE]; // fixed-size space for nodes
size_t npool; // used space in pool
size_t pfree; // pointer to re-use freed nodes
size_t head; // global list head
};
DList *dlist;
DNode *dnode_alloc(void)
{
if (dlist->pfree != DNULL) {
DNode *node = dlist->pool + dlist->pfree;
dlist->pfree = dlist->pool[dlist->pfree].next;
return node;
} else {
if (dlist->npool < MAX_DNODE) return &dlist->pool[dlist->npool++];
}
return NULL;
}
void dnode_free(DNode *node)
{
if (node) {
node->next = dlist->pfree;
dlist->pfree = node - dlist->pool;
}
}
DNode *dnode(size_t index)
{
return (index == DNULL) ? NULL : dlist->pool + index;
}
DNode *dnode_next(const DNode *node)
{
return dnode(node->next);
}
DNode *dnode_push(size_t *head, const char *str)
{
DNode *node = dnode_alloc();
if (node) {
strncpy(node->domain, str, sizeof(node->domain));
node->next = *head;
*head = node - dlist->pool;
}
return node;
}
void dnode_pop(size_t *head)
{
if (*head != DNULL) {
size_t next = dlist->pool[*head].next;
dnode_free(&dlist->pool[*head]);
*head = next;
}
}
int main(int argc, char* argv[])
{
int shmid;
shmid = shmget(IPC_PRIVATE, sizeof(DList), IPC_CREAT | 0660);
if (shmid < 0) exit(1);
dlist = shmat(shmid, NULL, 0);
if (dlist == (void *) (-1)) exit(1);
dlist->head = DNULL;
dlist->pfree = DNULL;
dlist->npool = 0;
dnode_push(&dlist->head, "Alpha");
dnode_push(&dlist->head, "Bravo");
dnode_push(&dlist->head, "Charlie");
dnode_push(&dlist->head, "Delta");
dnode_push(&dlist->head, "Echo");
while (dlist->head != DNULL) {
puts(dnode(dlist->head)->domain);
dnode_pop(&dlist->head);
}
shmdt(dlist);
return 0;
}
This was very helpful, thanks for posting. A few tweaks & fiddles:
dnode_alloc needs to increment npool when dlist->pfree != DNULL (add the line list->npool++; just before the return statement).
Similarly dnode_free needs to decrement npool prior to returning (add line list->npool--; just before returning).
In dnode_alloc the section dlist->npool < MAX_DNODE should be dlist->npool < MAX_DLEN

When should you free memory dynamically allocated?

Essentially, I have created a piece of Code which consists of a tree, whereby each tree node has its own linked list containing data, (each treeNode containing data as well). So that each treeNode can have multiple data items for that specific treeNode.
For this structure therefore to be created, I calloc a treenode, pass the address of that treenode to a createListNode function, and calloc a ListNode. My confusion stems really from, where exactly should I be freeing memory? Merely at the end of the program before return 0; in main, or elsewhere. Baring in mind once all the input is added to the tree and list, it then asks the user for a name, and displays the linked list of data appropriate for that name.
Cheers.
T.C.
EDIT:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
typedef struct ListNode {
char *number;
struct ListNode *next;
}ListNode;
typedef struct TreeNode {
char *name;
ListNode *numbers;
struct TreeNode *left;
struct TreeNode *right;
}TreeNode;
TreeNode* AddNode(TreeNode *, char *, char *);
void AddNum(TreeNode *, char *);
void N_Print(TreeNode* root);
TreeNode* SearchTree(TreeNode* root, char *search);
int main(void) {
char my_string[50], name[25], number[25];
TreeNode *root = NULL;
while ((fgets(my_string, 50, stdin)) != NULL) {
if (my_string[0] == '.')
break;
sscanf(my_string, "%s %s", name, number);
root = AddNode(root, name, number);
}
N_Print(root);
free(root);
free(root->numbers);
return 0;
}
TreeNode* AddNode(TreeNode *root, char *name, char *number) {
int comparison;
if (root == NULL) {
root = (TreeNode*)calloc(1,sizeof(TreeNode));
root->name = strdup(name);
root->left = root->right = NULL;
AddNum(root, number);
}else if ((comparison = strcasecmp(name, root->name)) < 0)
root->left = AddNode(root->left, name, number);
else if ((comparison = strcasecmp(name, root->name)) > 0) {
root->right = AddNode(root->right, name, number);
} else if ((comparison = strcasecmp(name, root->name)) == 0 ) {
AddNum(root, number);
}
return root;
}
void AddNum(TreeNode *tn, char *number) {
ListNode *ln = (ListNode *)calloc(1, sizeof(ListNode));
ln->number = strdup(number);
ln->next = tn->numbers;
tn->numbers = ln;
}
TreeNode* SearchTree(TreeNode* root, char *search) {
int comparison;
if (root == NULL) {
return NULL;
} else if ((comparison = strcasecmp(search, root->name)) == 0) {
return root;
} else if ((comparison = strcasecmp(search, root->name)) < 0) {
return SearchTree(root->left, search);
} else if ((comparison = strcasecmp(search, root->name)) > 0)
return SearchTree(root->right, search);
}
void N_Print(TreeNode* root) {
TreeNode* search_val;
char search[25];
while(1) {
printf("Type a name please: ");
scanf("%24s", search);
if (search[0] == '.')
break;
search_val = SearchTree(root, search);
if (search_val == NULL) {
printf("NOT FOUND\n");
continue;
}
ListNode* ln = search_val->numbers;
while ( ln != NULL) {
printf("%s\n", ln->number);
ln = ln->next;
}
}
}
You should free the memory when it is no longer needed. That of course depends on your application's needs.
In garbage collected environments (e.g. Java) the garbage collector frees memory when nothing is pointing at it. Following that as a starting point, you want to be sure to free memory before you remove your references to it.
The best plan (IMO) is to free memory at the point where you don't need to access it any more. however if you only use a small amount of dynamically allocated memory it probably wont make much of a difference if you do it all at the end of your program (assuming you keep track of it all)
It's simple:
You free the memory when you have no more need for it. In your case, it seems you'll never have to remove a node so don't worry about deleting any. It is automatically freed when your program exits. Be careful though, you should delete all memory which all of its pointers that reference it get out of scope, making it unusable. This may cause memory leaks.
When you no longer need the resources acquired from free store. So, it depends on what point you are not using calloc resources, you can start free it. But beware of dangling references.
You free the memory, once you have no use for it anymore. If that happens before program exit, well you free it before return. If the program wants to continue on whatever and you don't have need for the tree anymore, you free it and the continue with the program.
If for example the linked lists in the tree could at some stage shrink, the no-more-used nodes should be immediately freed.
You can free all the data as soon as you don't need it anymore, like when you're done printing it. In your case, if this is all what you program do it does not really matter as your kernel will free all memory allocated by your program at termination. However it matters if the program keeps running as it means you eating memory that cannot be used for other programs.
It's a bit like with previous version of firefox where it did not release memory after closing a tab. The program kept asking for more and more memory without releasing it.
As everyone above says, free it whe you don't need it anymore, but additionally it is often a good idea to try to free on the same level that you create. This is more complicated when you are passing references around and such.

Resources