Linked list in C losing head information
I've implemented a basic linked list in C as part of a project to develop a simple shell - it supports backgrounding of processes by maintaining a list of the pids that the shell has run in the background. Code is below. Inserting with queue_process(some_pid)
works fine the first time, but subsequent times the linked list acts as if there are never any nodes in the list (i.e. "No existing processes" is always printed by the debug function). I've checked this file and the file that calls these functions for anything that would reset the head pointer to no avail. Am I missing something in my linked list logic?
The call to queue_process EDIT: happens in the child process started by the shell and looks like this /EDIT: queue_process(getpid())
Thanks!
void queue_process(pid_t pid_to_insert)
{
pmesg(2, "In queue_process.\n");
if (head == NULL)
{
pmesg(3, "No existing processes.\n");
head = malloc(sizeof(struct xssh_process));
head->pid = pid_to_insert;
head->next = NULL;
}
else
{
pmesg(3, "There are existing processes.\n");
struct xssh_process *new_process = malloc(sizeof(struct xssh_process));
new_process->next= head;
head = new_process;
}
print_processes();
}
void print_processes()
{
pmesg(2, "In print_processes.\n");
struct xssh_process *at_node = head;
if (head == NULL) { pmesg(2, "There are currently no background processes.\n"); return; }
pmesg(2, "Process IDs from head (most recently executed) to tail: %i -> ", at_node->pid);
while (at开发者_StackOverflow中文版_node != NULL)
{
pmesg(2, "%i ->", at_node->pid);
at_node = at_node->next;
}
pmesg(3, "Head's pid in print is %i.\n", head->pid);
}
It's no help with the bug you've encountered, but your code strikes me as excessively complex:
pmesg(2, "In queue_process.\n"); if (head == NULL) { pmesg(3, "No existing processes.\n"); head = malloc(sizeof(struct xssh_process)); head->pid = pid_to_insert; head->next = NULL; tail = malloc(sizeof(struct xssh_process)); tail = head; } else { pmesg(3, "There are existing processes.\n"); struct xssh_process *new_process = malloc(sizeof(struct xssh_process)); new_process->next= head; head = new_process; }
This can be simplified quite a bit. Since you're inserting at the head of the list anyway, you don't need separate logic for an empty list:
void queue_process(pid_t pid_to_insert) {
struct xssh_process *new_process = malloc(sizeof(*new_process));
new_process->pid = pid_to_insert;
new_process->next = head;
head = new_process;
}
Likewise, print_processes can be trimmed down a bit:
void print_processes() {
struct xssh_process *p;
for (p=head; p!=NULL; p=p->next)
printf("%d\n", p->pid);
}
OTOH, a linked list strikes me as a poor choice -- given that a pointer is at least as large as a PID, at least 50% of your memory is overhead for the pointers.
Based on your extra information supplied:
The call to queue_process happens in the child process started by the shell and looks like this:
queue_process(getpid())
You are trying to add to the linked list in a child process (created by fork()
) and then examine that linked list in the parent.
This won't work - fork()
creates a complete, independent copy of the process. Except for memory that is explicitly marked as shared, modications to variables made after the fork()
are private to each process. The parent won't see modifications made by the child, and the child won't see modifications made by the parent.
You should have the parent call queue_process(child_pid)
, where child_pid
is the return value of fork()
.
When a variable's value mysteriously changes, it's often because you're writing beyond the bounds of another variable, that happens to be adjacent in memory.
Try setting a watch point in your debugger on head
, which will break into the debugger whenever that variable changes. This should let you track the issue down quite quickly. In gdb
, the command would be watch head
.
Try this:
void queue_process(pid_t pid_to_insert)
{
pmesg(2, "In queue_process.\n");
if (head == NULL)
{
pmesg(3, "No existing processes.\n");
head = malloc(sizeof(struct xssh_process));
head->pid = pid_to_insert;
head->next = NULL;
// This malloc is not required
// tail = malloc(sizeof(struct xssh_process));
tail = head;
}
else
{
pmesg(3, "There are existing processes.\n");
struct xssh_process *new_process = malloc(sizeof(struct xssh_process));
new_process->next= head;
head = new_process;
}
print_processes();
}
void print_processes()
{
pmesg(2, "In print_processes.\n");
if (head == NULL) { pmesg(2, "There are currently no background processes.\n"); return; }
struct xssh_process *at_node = head;
// While at_node != null
do
{
pmesg(2, "%i ->", at_node->pid);
at_node = at_node->next;
}
while (at_node != null);
pmesg(3, "Head's pid in print is %i.\n", head->pid);
}
精彩评论