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;
}