Understanding Processes in Embedded Linux Systems

What Is a Process?

A program is a static file stored on disk, consisting of executable instructions and data. In contrast, a process represents the dynamic execution of that program, encompassing its creation, scheduling, and eventual termination.

Essential Process Management Commands

  • top: Displays real-time system processes sorted by CPU usage.
    • PID: Unique process identifier (always > 0).
    • Nice value: Ranges from -20 (highest priority) to 19 (lowest) in Linux.
    • Process states:
      • R: Running or runnable
      • S: Interruptible sleep
      • D: Uninterruptible sleep
      • T: Stopped
      • Z: Zombie
      • X: Dead (rarely visible)
  • nice: Launches a process with a specific nice value.
    Example: nice -n 10 ./my_app
  • renice: Adjusts the priority of a running process.
    Example: renice -n 5 1234
  • kill / killall: Terminate processes by PID or name.
    Examples: kill -9 1234, killall -9 my_app
  • ps -ef: Lists all processes with full details (including PPID and PID).
    Filter example: ps -ef | grep app_name
  • pstree: Visualizes parent-child process relationships as a tree.
  • ps aux: Alternative detailed process listing.
  • ./app &: Runs a program in the background.
  • jobs: Shows background jobs in the current shell.
  • fg %1: Brings job #1 to the foreground.

Process Memory Layout (32-bit Systems)

Each process operates within a 4GB virtual address space divided into segments:

  • Text segment: Contains executable code (read-only).
  • Data segment:
    • Initialized global/static variables
    • Uninitialized global/static variables (.bss)
    • String literals
  • System data segment:
    • Heap: Dynamically allocated memory (grows upward)
    • Stack: Function call frames and local variables (grows downward)

The Memory Management Unit (MMU) maps this virtual space to physical RAM, ensuring proces isolation.

Process Scheduling

Linux uses several scheduling strategies:

  • First-Come-First-Served (FCFS)
  • Priority-based scheduling
  • Round-robin with time slices
  • Multilevel feedback queues
  • Load balancing across CPUs

Although systems appear to run multiple processes simultaneously (macroscopic parallelism), the CPU executes them one at a time in rapid succession (microscopic serialism).

Key Process System Calls

Process Creation: fork()

#include <sys/types.h>
#include <unistd.h>

pid_t fork(void);

Returns 0 in the child process, the child's PID in the parent, or -1 on error.

Process Identification

  • getpid(): Returns current process ID
  • getppid(): Returns parent process ID

Process Termination

  • exit(int status): Performs cleanup (flushes buffers) before termination
  • _exit(int status): Terminates immediately without cleanup

Process Lifecycle Issues

Zombie processes occur when a child exits but the parent hasn't collected its exit status. Solutions:

  1. Terminate the parent first (child becomes orphaned)
  2. Use wait() to reap child processes

Orphan processes (parent dies first) are adopted by init (PID 1), which automatically reaps them.

Reaping Child Processes: wait()

#include <sys/wait.h>

pid_t wait(int *status);

Blocks until a child terminates. Use macros to interpret status:

  • WIFEXITED(status): True if child exited normally
  • WEXITSTATUS(status): Exit code (if normally exited)
  • WIFSIGNALED(status): True if killed by signal
  • WTERMSIG(status): Signal number (if killed)

Replacing Process Image: exec Family

These functions replace the current process image with a new program:

  • execl(), execlp(): Arguments as list
  • execv(), execvp(): Arguments as array
  • execle(), execvpe(): Custom environment

Suffix meanings:

  • l = list arguments
  • v = vector (array) arguments
  • e = explicit environment
  • p = search PATH for executable

Environment Variable Management

char *getenv(const char *name);
int setenv(const char *name, const char *value, int overwrite);

Example usage:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main() {
    char cwd[1024];
    getcwd(cwd, sizeof(cwd));
    setenv("PATH", cwd, 1);
    execlp("hello", "hello", "arg1", "arg2", NULL);
    perror("execlp failed");
    return 1;
}

Practical Exercise: Creating Multiple Children

Create 9 child processes that print their PIDs, then have the parent print all child PIDs:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
    pid_t children[9];
    
    for (int i = 0; i < 9; i++) {
        children[i] = fork();
        if (children[i] == 0) {
            printf("Child %d: PID=%d, Parent PID=%d\n", 
                   i, getpid(), getppid());
            _exit(0);
        }
        wait(NULL); // Reap immediately to prevent zombies
    }
    
    printf("Parent PID: %d\n", getpid());
    for (int i = 0; i < 9; i++) {
        printf("Child %d PID: %d%s", i, children[i], 
               (i == 4) ? "\n" : " ");
    }
    printf("\n");
    return 0;
}

Tags: Linux process fork exec system-calls

Posted on Thu, 14 May 2026 06:23:51 +0000 by venom999