Skip to content
/ C_Linux Public

Contains examples on using C Linux system call (fork, wait, thread, kill, pause, pipe, condition variable, mutex, semaphores, ...)

License

Notifications You must be signed in to change notification settings

Unix69/C_Linux

Repository files navigation

C_Linux




A set of C example programs showing the basic usage of Unix system calls related to Filesystem, Processes and Threads to learn about Unix-like filesystem manipulation and C multiprocess and multithread programming.




📖 Table of Contents




Summary

This collection of examples demonstrates:

  • Function pointers & generic programming – dynamic invocation and flexible code structures.
  • File I/O with C Standard Library – byte-wise and stream-based file operations.
  • Unix process management – creation, synchronization, and termination of child processes.
  • Signals & IPC mechanisms – using kill(), pause(), pipe(), and wait() for inter-process communication.
  • Multithreading & thread-safe operations – concurrent processing of data, file I/O, and sorting using pthread_create and pthread_join.


📚 C Unix & Standard Library Examples

This collection of examples demonstrates key concepts in C programming on a Unix-like operating system using standard tools and libraries. All examples were developed using:

  • Language: C (C99/C11 standard)
  • OS: Linux / Unix-like environments
  • Toolchain: GCC, Make, POSIX-compliant libraries
  • Techniques demonstrated: Process creation and management, inter-process communication (IPC), file I/O, signals, threading, synchronization, assertion-based error checking
  • Libraries used: <stdio.h>, <stdlib.h>, <unistd.h>, <fcntl.h>, <pthread.h>, <assert.h>, <string.h>
  • Programming techniques: Forking, wait/waitpid, pipes, signals, pause, kill, thread creation and joining, dynamic memory management, bubble sort in threads, concurrent file processing

Below is a comprehensive list of the examples included in this folder, grouped by topic, with direct links to their detailed sections:

🧩 Function Pointers

  • C-Func-pointer – Demonstrates function pointers in C, dynamic invocation, and generic programming using void *.

📄 Standard File I/O

  • C-STD-File – Basic file input/output, copying files byte by byte, error handling, and EOF processing.

🖥️ Unix Process Management – Fork & Wait

🔄 Unix Executables & Directories

⚡ Signals & Inter-Process Communication

🧵 Threads & Concurrent File Processing

Each example includes detailed explanations of the system calls, functions, and programming techniques used. They serve as a reference for:

  • Process creation and management
  • Inter-process communication (pipes, signals)
  • File I/O and directory exploration
  • Threading and synchronization
  • Assertion-based error checking and debugging
  • Concurrent algorithms (sorting, data processing)

Let's start to see each example into detail.



🧪 C-Func-pointer

Path: src/C-Func-pointer/main.c

🔍 View Code

🎯 Purpose

This example demonstrates the use of function pointers in C, showing how functions can be assigned to variables, passed around, and invoked dynamically at runtime.

The goal is to understand:

  • how to declare and use function pointers
  • how to pass generic data using void *
  • how to build flexible and reusable logic

🛠️ Description

The program manages an integer array of fixed size using a set of functions operating on generic pointers.

The execution flow is the following:

  1. init() dynamically allocates and initializes an integer array of size dim with all values set to zero
  2. Two function pointers are declared:
    • add → points to inc()
    • dec → points to sub()
  3. inc() increments each element of the array by a given value
  4. sub() decrements each element of the array by a given value
  5. show() prints the content of the array

All data manipulation functions receive the array as a void *, demonstrating a generic programming approach in C.

📦 Headers and Libraries Used

Header Description Reference
<stdio.h> Standard input/output operations cppreference
<stdlib.h> Dynamic memory allocation cppreference
<string.h> String manipulation utilities cppreference

⚙️ Functions Used

Function Role Reference
malloc() Allocates memory dynamically cppreference
printf() Prints formatted output cppreference

🧠 Key Concepts Introduced

  • 🧷 Function pointers
  • 🧬 Generic programming with void *
  • 🧠 Indirect function invocation
  • 📦 Dynamic memory allocation
  • ♻️ Reusable and modular code

🔗 Links


🧪 C-STD-File

Path: src/C-STD-File/main.c

🔍 View Code

🎯 Purpose

This example shows how to perform basic file input/output using the C standard library. The program copies the content of a source file into a destination file, byte by byte.

It introduces fundamental concepts such as file streams, error handling, and sequential file processing.

🛠️ Description

The program expects exactly two command-line arguments:

  • the path of the source file to read
  • the path of the destination file to write

The execution flow is the following:

  1. Checks the number of command-line arguments
  2. Opens the source file in read mode using fopen()
  3. Opens (or creates) the destination file in write mode
  4. Reads characters one by one from the source file using fgetc()
  5. Writes each character to the destination file using fputc()

The program stops copying when the EOF (End Of File) marker is reached. This demonstrates a simple and classic file copy algorithm using standard I/O.

📦 Headers and Libraries Used

Header Description Reference
<stdio.h> Standard input/output and file streams cppreference
<stdlib.h> General utilities cppreference
<assert.h> Runtime assertions for error checking cppreference

⚙️ Standard Functions Used

Function Role Reference
fopen() Opens a file stream cppreference
fgetc() Reads a character from a file cppreference
fputc() Writes a character to a file cppreference
fprintf() Prints formatted output to a stream cppreference
assert() Checks runtime conditions cppreference

🧠 Key Concepts Introduced

  • 📂 File streams (FILE *)
  • 📝 Character-based file I/O
  • ⚠️ Basic error handling
  • 🧪 Runtime assertions
  • 📄 End Of File (EOF) handling

🔗 Related References


🧪 C-Unix-STD-Basic-Fork

Path: src/C-Unix-STD-Basic-Fork/main.c

🔍 View Code

🎯 Purpose

This example demonstrates the basic behavior of the fork() system call and how a process is duplicated into a parent and a child process.

The goal is to understand:

  • how to distinguish parent and child processes
  • how execution flow is duplicated
  • how concurrent processes produce output

🛠️ Description

The program executes a decreasing for loop (i = 2 → 1). At each iteration:

  1. the fork() system call is invoked
  2. the parent process receives a value greater than 0
  3. the child process receives 0
  4. based on the return value:
    • the parent prints i
    • the child prints -i

Since fork() duplicates the current process:

  • after the first iteration there are 2 running processes
  • after the second iteration there are 4 running processes

The order of the printed output is non-deterministic, because it depends on the operating system scheduler.

📦 Headers and Libraries Used

Header Description Reference
<stdlib.h> Standard utility functions cppreference
<stdio.h> Standard input/output cppreference
<unistd.h> POSIX process control Open Group

⚙️ System Calls and Functions

Function Role Reference
fork() Creates a new process by duplicating the caller man7.org
printf() Writes formatted output to stdout cppreference

🧠 Key Concepts Introduced

  • 🔀 Process creation
  • 👨‍👦 Parent vs child execution
  • 🔁 Concurrent execution
  • 🎲 Non-deterministic output
  • 📈 Exponential process growth

🔗 Links


🧪 C-Unix-STD-Copy-DirectoryTree

Path: src/C-Unix-STD-Copy-DirectoryTree/main.c

🔍 View Code

🎯 Purpose

This example demonstrates recursive copying of a directory tree using Unix system calls. It shows how to duplicate all files and subdirectories from a source directory to a destination directory.

The goal is to understand:

  • how to traverse directories recursively
  • how to handle files and directories differently
  • how low-level file I/O works in Unix
  • how to implement robust error handling

🛠️ Description

The program expects exactly two command-line arguments:

  • the path of the source directory
  • the path of the destination directory

Execution flow:

  1. Validate argument count using assert().
  2. Retrieve file status of source and destination using lstat().
  3. Check that both paths are directories using S_ISDIR().
  4. Invoke the recursive copia() function:
    • Open source and destination directories with opendir().
    • Iterate over directory entries using readdir(), skipping . and ...
    • Build full paths for each entry with sprintf().
    • Check entry type using lstat():
      • If a file, copy its contents using open(), read(), and write().
      • If a directory, create it using mkdir() and recursively call copia().
    • Close directory streams with closedir().

📦 Headers and Libraries Used

Header Description Reference
<stdio.h> Standard I/O for fprintf() cppreference
<stdlib.h> Standard utilities, exit() cppreference
<sys/types.h> Data types for system calls man7.org
<sys/stat.h> File status and mode macros (S_ISDIR) man7.org
<unistd.h> Unix standard functions (read, write, close) man7.org
<dirent.h> Directory handling (opendir, readdir, closedir) man7.org
<fcntl.h> File control flags (O_RDONLY, O_WRONLY, O_CREAT) man7.org
<assert.h> Runtime assertions cppreference

⚙️ System Calls and Functions

Function Role Reference
lstat() Retrieve file or directory status man7.org
S_ISDIR() Check if path is a directory man7.org
opendir() Open a directory stream man7.org
readdir() Read entries from a directory man7.org
closedir() Close a directory stream man7.org
open() Open a file descriptor man7.org
read() Read bytes from a file descriptor man7.org
write() Write bytes to a file descriptor man7.org
mkdir() Create a new directory man7.org
sprintf() Build full file paths as strings cppreference
assert() Runtime condition checks cppreference
fprintf() Print formatted error messages to stderr cppreference

🧠 Key Concepts Introduced

  • 📂 Recursive directory traversal
  • 📝 Low-level file I/O with open/read/write
  • ⚠️ Error handling with fprintf(), assert(), and exit()
  • 🔄 Preserving directory structure
  • 🧪 Runtime validation of command-line arguments
  • 🔁 Recursion for nested directories

🔗 Links


🧪 C-Unix-STD-Execl

Path: src/C-Unix-STD-Execl/main.c

🔍 View Code

🎯 Purpose

This example demonstrates the use of the execl() system call to replace the current process image with a new program.

The goal is to understand:

  • how execl() replaces the current process
  • how execution flow stops after a successful execl()
  • the effect on program output when execl() fails

🛠️ Description

The program expects one command-line argument specifying the program to execute:

  • Print the current process ID and increment a counter.
  • Call execl() with the provided program path.
  • If execl() succeeds, the new program replaces the current process and the next fprintf() is not executed.
  • If execl() fails, an error message is printed and the program exits with return 1.

📦 Headers and Libraries Used

Header Description Reference
<stdio.h> Standard input/output functions cppreference
<stdlib.h> General utilities, exit() cppreference
<unistd.h> POSIX system calls, execl(), getpid() man7.org

⚙️ System Calls and Functions

Function Role Reference
execl() Replaces current process image with a new program man7.org
getpid() Returns the process ID of the current process man7.org
fprintf() Print formatted output to a stream (stdout or stderr) cppreference

🧠 Key Concepts Introduced

  • 🔁 Process replacement with execl()
  • 👀 Execution flow stops after successful execl()
  • ⚠️ Handling execl failure
  • 📄 Process identification with getpid()

🔗 Links


🧪 C-Unix-STD-Execlp-System

Path: src/C-Unix-STD-Execlp-System/main.c

🔍 View Code

🎯 Purpose

This example demonstrates process creation and execution using fork(), system(), and execlp().

The goal is to understand:

  • how fork() creates concurrent processes
  • how system() can execute shell commands
  • how execlp() replaces the process image
  • how parent and child processes interact

🛠️ Description

The program executes nested loops with process creation:

  1. Call fork() to create the first child.
  2. For i = 0 to 1:
    • If in the parent process, build a command string and execute it using system().
    • If in the child process, build a string and execute it using execlp() with echo.
  3. The execlp() calls replace the child process image with echo, while system() runs in the parent process.
  4. This demonstrates concurrent execution and process replacement within the same loop.

📦 Headers and Libraries Used

Header Description Reference
<stdio.h> Standard input/output functions cppreference
<stdlib.h> General utilities, system() cppreference
<unistd.h> POSIX system calls (fork(), execlp()) man7.org

⚙️ System Calls and Functions

Function Role Reference
fork() Create a new child process man7.org
execlp() Replace current process image with a new program found in PATH man7.org
system() Execute shell command in a separate process man7.org
sprintf() Format string into buffer for command execution cppreference

🧠 Key Concepts Introduced

  • 🔀 Process creation and concurrency with fork()
  • 🔁 Process replacement with execlp()
  • 💻 Shell command execution with system()
  • ⚠️ Parent vs child process execution control
  • 📄 Demonstrates interaction between multiple processes in a loop

🔗 Links


🧪 C-Unix-STD-Explore-Directories

Path: src/C-Unix-STD-Explore-Directories/main.c

🔍 View Code

🎯 Purpose

This example demonstrates recursive exploration of directories in a file system.

The goal is to understand:

  • how to navigate directories using opendir() and readdir()
  • how to distinguish files and directories using lstat()
  • how recursion can be applied to traverse an entire directory tree

🛠️ Description

The program expects a single command-line argument specifying the root directory:

  1. Check if the provided path exists and is a directory using lstat().
  2. Call a recursive function funzione() to explore the directory tree.
  3. Inside the recursive function:
    • Open the directory with opendir().
    • Iterate over all entries with readdir().
    • For files, print the full path.
    • For directories, print the path and recursively explore its contents.
  4. Close the directory after traversal with closedir().

📦 Headers and Libraries Used

Header Description Reference
<stdio.h> Input/output functions cppreference
<stdlib.h> General utilities, exit() cppreference
<unistd.h> POSIX system calls (lstat()) man7.org
<sys/stat.h> File status information cppreference
<dirent.h> Directory stream handling man7.org
<string.h> String manipulation functions cppreference

⚙️ System Calls and Functions

Function Role Reference
lstat() Get information about a file or directory man7.org
opendir() Open a directory stream man7.org
readdir() Read the next entry in a directory man7.org
closedir() Close a directory stream man7.org
fprintf() Print formatted output to stdout/stderr cppreference

🧠 Key Concepts Introduced

  • 📂 Directory traversal using opendir()/readdir()
  • 📝 Differentiating files and directories
  • 🔁 Recursive algorithms
  • ⚠️ Basic error handling in file systems

🔗 Links

  • 📘 POSIX Directory Operations: man7.org

🧪 C-Unix-STD-Fork

Path: src/C-Unix-STD-Fork/main.c

🔍 View Code

🎯 Purpose

This example demonstrates process creation using fork() and semaphores to control output order.

The goal is to understand:

  • how multiple child processes can be created concurrently
  • how to use semaphores to synchronize process output
  • how process execution order can be controlled

🛠️ Description

The program reads a string from stdin and creates one child process per character:

  1. Initialize a semaphore to zero.
  2. For each character, create a child process using fork().
  3. Each child waits on the semaphore (sem_wait()) before printing its character.
  4. The parent posts to the semaphore (sem_post()) sequentially to allow children to print in order.
  5. Child processes exit after printing, ensuring ordered output.

📦 Headers and Libraries Used

Header Description Reference
<stdio.h> Standard input/output cppreference
<stdlib.h> General utilities, memory allocation, exit() cppreference
<unistd.h> POSIX process control (fork()) man7.org
<semaphore.h> POSIX semaphores for process synchronization man7.org
<string.h> String manipulation (strlen(), strdup()) cppreference

⚙️ System Calls and Functions

Function Role Reference
fork() Create a new child process man7.org
sem_init() Initialize semaphore man7.org
sem_wait() Wait (decrement) on semaphore man7.org
sem_post() Signal (increment) semaphore man7.org
printf() Output character to stdout cppreference

🧠 Key Concepts Introduced

  • 🔀 Process creation with fork()
  • 🔁 Process synchronization using semaphores
  • 📝 Ordered output from concurrent processes
  • ⚠️ Proper use of exit() in child processes

🔗 Links


🧪 C-Unix-STD-Fork-Sleep

Path: src/C-Unix-STD-Fork-Sleep/main.c

🔍 View Code

🎯 Purpose

This example demonstrates nested process creation using fork() and controlled termination with sleep().

The goal is to understand:

  • how multiple levels of processes can be spawned
  • how to differentiate "leaf" processes
  • how sleep() can be used to control process timing and termination

🛠️ Description

The program expects two command-line arguments: number of iterations n and sleep time t:

  1. Loop i = 0 → n-1, creating child processes with fork().
  2. Within the loop, if in the parent process, another fork() may be called to create nested children.
  3. After all forks, the process sleeps for t seconds.
  4. After waking, the leaf process prints a termination message.

📦 Headers and Libraries Used

Header Description Reference
<stdio.h> Input/output functions cppreference
<stdlib.h> General utilities, atoi(), exit() cppreference
<unistd.h> POSIX system calls, fork(), sleep() man7.org
<sys/wait.h> Waiting for process termination man7.org
<assert.h> Runtime assertions cppreference

⚙️ System Calls and Functions

Function Role Reference
fork() Create a new child process man7.org
sleep() Pause process execution for a specified time man7.org
printf() Output to stdout cppreference
assert() Verify runtime conditions cppreference

🧠 Key Concepts Introduced

  • 🔀 Nested process creation with fork()
  • ⏳ Process timing control with sleep()
  • ⚠️ Parent vs leaf process identification
  • 📄 Controlled process termination

🔗 Links


🧪 C-Unix-STD-Fork-Wait

Path: src/C-Unix-STD-Fork-Wait/main.c

🔍 View Code

🎯 Purpose

This example demonstrates process creation with fork() and parent-child synchronization using wait().

The goal is to understand:

  • how the parent waits for child processes to complete before continuing
  • how to pass data from the parent to children using memory arrays
  • how sequential output can be enforced using wait()

🛠️ Description

The program expects a single command-line argument n for the number of integers:

  1. Allocate an array of size n dynamically using malloc().
  2. Read n integers from the user into the array.
  3. Loop over the array, and for each element:
    • Call fork() to create a child process.
    • In the parent process:
      • Call wait(NULL) to wait for the child to finish.
      • Print the corresponding integer from the array.
      • Exit with the child index as exit code.
  4. Child processes exit immediately after creation.

📦 Headers and Libraries Used

Header Description Reference
<stdio.h> Standard input/output cppreference
<stdlib.h> Memory allocation (malloc()), atoi(), exit() cppreference
<unistd.h> Process creation (fork()) man7.org
<sys/wait.h> Waiting for child process termination (wait()) man7.org
<assert.h> Runtime assertions cppreference

⚙️ System Calls and Functions

Function Role Reference
fork() Create child processes man7.org
wait() Wait for a child process to terminate man7.org
malloc() Allocate dynamic memory for the integer array cppreference
exit() Terminate a process with a specific exit code cppreference

🧠 Key Concepts Introduced

  • 🔀 Process creation and parent-child hierarchy
  • ⏳ Sequential execution of child processes using wait()
  • 📝 Passing and printing data via shared memory arrays
  • ⚠️ Proper termination of child processes

🔗 Links

🧪 C-Unix-STD-Fork-Wait-Precedence

Path: src/C-Unix-STD-Fork-Wait-Precedence/main.c

🔍 View Code

🎯 Purpose

This example demonstrates process creation with multiple fork() calls and wait() to enforce execution precedence.

The goal is to understand:

  • how a complex tree of processes can be spawned
  • how wait() controls which child completes before the parent proceeds
  • how to trace parent-child relationships and execution order

🛠️ Description

The program creates a complex hierarchy of child processes:

  1. Parent creates child P1 with fork(). P1 prints its PID and exits.
  2. The parent waits for P1 to finish using wait().
  3. Parent sequentially spawns P2, P3, … P12 with additional fork() calls, sometimes nested.
  4. Each child prints its PID, parent PID, and an iteration index, then exits.
  5. The use of wait() ensures that the parent continues only after specific children terminate, enforcing precedence.

📦 Headers and Libraries Used

Header Description Reference
<stdio.h> Standard input/output cppreference
<stdlib.h> Utilities, exit() cppreference
<unistd.h> Process creation (fork()) man7.org
<sys/wait.h> Process termination synchronization (wait()) man7.org
<assert.h> Runtime assertions cppreference

⚙️ System Calls and Functions

Function Role Reference
fork() Create child processes in sequence and nested hierarchies man7.org
wait() Wait for specific child process to terminate, enforcing execution order man7.org
printf() Print process information cppreference
exit() Terminate a process with a status code cppreference

🧠 Key Concepts Introduced

  • 🔀 Nested and sequential process creation
  • ⏳ Controlling execution precedence using wait()
  • 📄 Tracking PID and PPID relationships
  • ⚠️ Proper child process termination to prevent zombies

🔗 Links


🧪 C-Unix-STD-Fork-Waitpid

Path: src/C-Unix-STD-Fork-Waitpid/main.c

🔍 View Code

🎯 Purpose

This example demonstrates process creation using fork() and selective waiting using waitpid().

The goal is to understand:

  • how to create multiple child processes
  • how waitpid() can wait for specific child processes instead of any child
  • how to handle process termination selectively

🛠️ Description

The program creates N child processes in a loop:

  1. For each child, call fork() and store the child PID in an array.
  2. In child processes, immediately exit with EXIT_SUCCESS.
  3. After creating children, the parent selectively waits for children with index > M using waitpid().
  4. This demonstrates control over which child processes to wait for and allows partial concurrent execution.

📦 Headers and Libraries Used

Header Description Reference
<stdio.h> Standard input/output cppreference
<stdlib.h> General utilities, exit() cppreference
<unistd.h> Process creation (fork()) man7.org
<sys/wait.h> Selective waiting for child processes (waitpid()) man7.org

⚙️ System Calls and Functions

Function Role Reference
fork() Create child processes man7.org
waitpid() Wait for a specific child process to terminate man7.org
exit() Terminate a process cppreference

🧠 Key Concepts Introduced

  • 🔀 Multiple child process creation
  • 🧩 Selective waiting using waitpid()
  • ⚠️ Preventing zombie processes
  • ⏱️ Partial concurrency control

🔗 Links


🧪 C-Unix-STD-Signal-Fork-Pause-Kill-Pipe

Path: src/C-Unix-STD-Signal-Fork-Pause-Kill-Pipe/main.c

🔍 View Code

🎯 Purpose

This example demonstrates parent-child communication using a pipe, where the child reads a file and sends its content to the parent through the pipe.

The goal is to understand:

  • How to create a pipe for IPC between parent and child
  • How a child can write data to a pipe and parent can read it
  • How to coordinate file I/O with process communication

🛠️ Description

  1. Create a pipe using pipe() for IPC.
  2. Fork a child process:
    • Child closes the read-end of the pipe.
    • Opens testo.txt and reads its content.
    • Writes the content to the pipe.
  3. Parent process closes the write-end of the pipe.
  4. Parent reads from the pipe and writes the content to stdout.

📦 Headers and Libraries Used

HeaderDescriptionReference
<unistd.h>fork, pipe, read, writeman7.org
<fcntl.h>File open/readman7.org
<stdlib.h>Memory allocation, exitcppreference
<stdio.h>File I/O and stdoutcppreference
<assert.h>Error checkingcppreference

⚙️ System Calls and Functions

FunctionRoleReference
fork()Create child processman7.org
pipe()Create IPC pipeman7.org
read(), write()Read/write through pipe and fileman7.org
close()Close pipe endsman7.org
exit()Terminate a processcppreference

🧠 Key Concepts Introduced

  • 📡 Parent-child IPC via pipe
  • 👨‍👦 Coordinated file read and stdout output
  • 🔁 Streaming data between processes using pipe
  • ⚠️ Ensuring proper pipe closure to prevent deadlocks

🔗 Links


🧪 C-Unix-STD-Signal-Fork-Pause-Kill-Wait

Path: src/C-Unix-STD-Signal-Fork-Pause-Kill-Wait/main.c

🔍 View Code

🎯 Purpose

This example demonstrates two-child signal-based communication with parent synchronization using wait().

The goal is to understand:

  • How to use signals (SIGUSR1, SIGUSR2) for inter-process communication
  • How to synchronize parent with multiple children using wait()
  • How to coordinate sequential execution of child processes

🛠️ Description

  1. Fork two child processes.
  2. Child processes pause until receiving their respective signal (SIGUSR1 or SIGUSR2).
  3. Parent sends signals in a controlled order and waits for child termination using wait().
  4. This ensures orderly execution and prevents zombie processes.

📦 Headers and Libraries Used

HeaderDescriptionReference
<stdio.h>Standard input/outputcppreference
<stdlib.h>Exit, general utilitiescppreference
<unistd.h>fork(), pause()man7.org
<signal.h>Signal handlingman7.org
<sys/wait.h>wait() for child processesman7.org

⚙️ System Calls and Functions

FunctionRoleReference
fork()Create child processesman7.org
signal()Install signal handlersman7.org
pause()Wait for a signalman7.org
kill()Send signal to childman7.org
wait()Wait for child terminationman7.org

🧠 Key Concepts Introduced

  • 🔀 Parent-child signaling with SIGUSR1/SIGUSR2
  • ⏱️ Synchronizing parent with children using wait()
  • ⚠️ Preventing zombie processes
  • 🧩 Coordinated sequential execution

🔗 Links


🧪 C-Unix-STD-Kill

Path: src/C-Unix-STD-Kill/main.c

🔍 View Code

🎯 Purpose

This program demonstrates the use of the kill() system call to send signals to a specific process based on command-line arguments.

The goal is to understand:

  • how to target a process by PID
  • how to send different signals (SIGUSR1, SIGUSR2, SIGINT)
  • how command-line arguments can control signal behavior

🛠️ Description

  1. Expect exactly two command-line arguments: target PID and a command string.
  2. Compare the command string:
    • somma → send SIGUSR2
    • differenza → send SIGUSR1
    • fine → send SIGINT
  3. If the command is invalid, print an error message.
  4. Uses kill(pid, signal) to notify the target process.

📦 Headers and Libraries Used

Header Description Reference
<signal.h>Signal handling and sending (kill())man7.org
<stdlib.h>Conversion (atoi())cppreference
<unistd.h>Process primitivesman7.org
<string.h>String comparison (strcmp())cppreference
<assert.h>Runtime assertion to check argument countcppreference

⚙️ System Calls and Functions

FunctionRoleReference
kill()Send a signal to a process by PIDman7.org
atoi()Convert string to integer (PID)cppreference
strcmp()Compare command stringscppreference

🧠 Key Concepts Introduced

  • 🔀 Process targeting by PID
  • ⚡ Sending signals to control remote process behavior
  • ⚠️ Handling invalid commands safely

🔗 Links


🧪 C-Unix-STD-Signal

Path: src/C-Unix-STD-Signal/main.c

🔍 View Code

🎯 Purpose

Demonstrates signal handling using signal() and pause().

The goal is to understand:

  • how to handle multiple signals (SIGUSR1, SIGUSR2, SIGINT)
  • how a process can react to external signals
  • using pause() to wait for signals

🛠️ Description

  1. Set up handlers for SIGUSR1, SIGUSR2, SIGINT using signal().
  2. Read two integers from the user.
  3. Enter an infinite loop calling pause() to wait for signals.
  4. When a signal is received:
    • SIGUSR1: print the difference of the two integers.
    • SIGUSR2: print the sum of the two integers.
    • SIGINT: terminate the process.

📦 Headers and Libraries Used

HeaderDescriptionReference
<signal.h>Signal handling (signal())man7.org
<stdio.h>Input/outputcppreference
<stdlib.h>General utilities (exit())cppreference
<unistd.h>Pause and process controlman7.org

⚙️ System Calls and Functions

FunctionRoleReference
signal()Install a handler for a specific signalman7.org
pause()Wait until a signal is receivedman7.org
scanf()Read integers from usercppreference
printf()Print resultscppreference

🧠 Key Concepts Introduced

  • ⚡ Signal handling
  • ⏳ Waiting for signals using pause()
  • 📝 Dynamic reaction to external events
  • ⚠️ Graceful termination via signals

🔗 Links


🧪 C-Unix-STD-Signal-Fork

Path: src/C-Unix-STD-Signal-Fork/main.c

🔍 View Code

🎯 Purpose

Demonstrates the combination of fork() and signal handling, showing how a parent can control child processes using signals.

The goal is to understand:

  • creating multiple child processes with fork()
  • sending signals to children to trigger handlers
  • coordinating execution between parent and children

🛠️ Description

  1. Accept exactly one command-line argument n, the number of child processes.
  2. Install a signal handler manager() for SIGUSR1 in children.
  3. Loop n times:
    • fork a child process
    • child calls pause() and waits for a signal
    • parent sleeps 2 seconds, prints info, then sends SIGUSR1 to the child
  4. Children print a message when receiving SIGUSR1 and exit.
  5. Parent continues to the next child.

📦 Headers and Libraries Used

HeaderDescriptionReference
<signal.h>Signal handlingman7.org
<unistd.h>Process control and forkman7.org
<stdio.h>Input/outputcppreference
<stdlib.h>Memory allocation, exitcppreference
<assert.h>Runtime checkscppreference

⚙️ System Calls and Functions

FunctionRoleReference
fork()Create a child processman7.org
signal()Assign handler to SIGUSR1man7.org
pause()Wait until a signal arrivesman7.org
kill()Parent sends signal to childman7.org
printf()Output messages to stdoutcppreference

🧠 Key Concepts Introduced

  • 👶 Child processes with fork()
  • ⚡ Signal communication parent → child
  • ⏳ Synchronized execution using pause() and sleep()
  • 📝 Process info reporting via signals

🔗 Links


🧪 C-Unix-STD-Signal-Fork-Kill

Path: src/C-Unix-STD-Signal-Fork-Kill/main.c

🔍 View Code

🎯 Purpose

Demonstrates a bidirectional signal exchange between parent and child processes combined with fork() and kill().

The goal is to understand:

  • parent-child communication using signals
  • how children can respond to signals and reply to parent
  • looping signal interactions in a controlled sequence

🛠️ Description

  1. Parent sets up handlers for SIGUSR1, SIGUSR2, SIGINT.
  2. Parent forks a single child process.
  3. Child enters an infinite loop, waiting for signals using pause() and reacts:
    • SIGUSR1: send SIGUSR2 to parent
    • SIGUSR2: send SIGUSR1 to parent
    • SIGINT: send SIGINT to parent and terminate
  4. Parent cycles through an array of signals, sending one to the child every second in a loop.
  5. Demonstrates bidirectional signaling, signal handling, and safe process termination.

📦 Headers and Libraries Used

HeaderDescriptionReference
<signal.h>Signal handlingman7.org
<unistd.h>Process control and forkman7.org
<stdio.h>Input/outputcppreference
<stdlib.h>Memory allocation, exitcppreference

⚙️ System Calls and Functions

FunctionRoleReference
fork()Create child processman7.org
signal()Install signal handlers in parent and childman7.org
kill()Send signal to a processman7.org
pause()Child waits for signalsman7.org
malloc()/free()Allocate/free memory for signal arraycppreference

🧠 Key Concepts Introduced

  • 👨‍👦 Parent-child process communication
  • 🔁 Bidirectional signaling
  • ⏳ Synchronization using signals and pause()
  • ⚡ Dynamic reaction to signal events
  • 🛡️ Safe process termination via SIGINT

🔗 Links


🧪 C-Unix-STD-Signal-Fork-Pause

Path: src/C-Unix-STD-Signal-Fork-Pause/main.c

🔍 View Code

🎯 Purpose

Demonstrates parent-child synchronization using signals and pause() with file I/O from child processes.

The goal is to understand:

  • forking multiple child processes
  • sending signals to children to trigger specific actions
  • reading files in child processes and writing to stdout
  • using pause() for waiting on signals

🛠️ Description

  1. Open two files for reading: son1.txt and son2.txt.
  2. Install a signal handler for SIGUSR1 and SIGCHLD.
  3. Fork the first child:
    • Child pauses until SIGUSR1 is received
    • Reads 50 bytes from son1.txt and writes to stdout
  4. Fork the second child:
    • Child pauses until SIGUSR1 is received
    • Reads 50 bytes from son2.txt and writes to stdout
    • Child sleeps 5 seconds then exits
  5. Parent prints PIDs of both children, sends SIGUSR1 to each child in sequence, using pause() to synchronize.
  6. After both children finish, parent closes file descriptors and exits.

📦 Headers and Libraries Used

HeaderDescriptionReference
<signal.h>Signal handlingman7.org
<unistd.h>Process control, fork, pauseman7.org
<fcntl.h>File I/O open/read/writeman7.org
<stdio.h>Standard input/outputcppreference
<stdlib.h>Exit, malloccppreference

⚙️ System Calls and Functions

FunctionRoleReference
fork()Create child processesman7.org
signal()Install signal handlersman7.org
pause()Wait for a signalman7.org
open(), read(), write()File I/O in child processesman7.org
kill()Send signal to childman7.org

🧠 Key Concepts Introduced

  • 👨‍👦 Parent-child communication via signals
  • ⏳ Process synchronization using pause()
  • 📂 File reading in forked processes
  • ⚡ Signal-triggered execution in children
  • 🛡️ Handling child termination signals

🔗 Links


🧪 C-Unix-STD-Signal-Fork-Pause-Kill

Path: src/C-Unix-STD-Signal-Fork-Pause-Kill/main.c

🔍 View Code

🎯 Purpose

Demonstrates signal handling and inter-process notification using a single child process.

  • Child waits for SIGINT signal before executing
  • Parent can send SIGINT to terminate the child
  • Shows basic pause-and-signal synchronization

🛠️ Description

  1. Install empty signal handlers for SIGINT and SIGCHLD.
  2. Fork a child process:
    • Child pauses until SIGINT is received
    • After signal, child prints a message and exits
  3. Parent pauses, sends SIGINT to child, and waits for completion.

📦 Headers and Libraries Used

HeaderDescriptionReference
<signal.h>Signal handlingman7.org
<unistd.h>Process controlman7.org
<stdlib.h>Exit, memory allocationcppreference
<stdio.h>Standard I/Ocppreference
<assert.h>Assertions for error checkingcppreference

⚙️ System Calls and Functions

FunctionRoleReference
fork()Create child processman7.org
signal()Install signal handlersman7.org
pause()Wait for a signalman7.org
kill()Send signal to childman7.org

🧠 Key Concepts Introduced

  • 👨‍👦 Parent-child synchronization via signals
  • ⏳ Using pause() for waiting signals
  • ⚡ Sending SIGINT to terminate child process
  • 🛡️ Signal handling to control execution flow

🔗 Links


🧪 C-Unix-STD-Signal-Fork-Pause-Kill-File-Wait

Path: src/C-Unix-STD-Signal-Fork-Pause-Kill-File-Wait/main.c

🔍 View Code

🎯 Purpose

Demonstrates two-child process coordination using signals, pause(), and file I/O.

  • Child processes read separate text files and print to stdout
  • Synchronization between children using signals
  • Parent controls execution flow

🛠️ Description

  1. Install signal handlers for SIGUSR1 and SIGCHLD.
  2. Fork first child:
    • Wait for signal from parent
    • Read testo_1.txt and print content
    • Send signal to second child after finishing
  3. Fork second child:
    • Wait for signal from first child
    • Read testo_3.txt and print content
    • Send signal back to first child or exit
  4. Parent triggers first signal, then waits for both children to finish.

📦 Headers and Libraries Used

HeaderDescriptionReference
<signal.h>Signal handlingman7.org
<unistd.h>fork, pauseman7.org
<fcntl.h>File open/readman7.org
<stdio.h>File I/O and stdoutcppreference
<stdlib.h>Exit, malloccppreference
<assert.h>Error checkingcppreference

⚙️ System Calls and Functions

FunctionRoleReference
fork()Create child processesman7.org
signal()Install handlers for inter-process signalingman7.org
pause()Wait for signalsman7.org
open(), read(), write()File I/O for childrenman7.org
kill()Send signals between childrenman7.org

🧠 Key Concepts Introduced

  • 👨‍👦 Signal-based synchronization between sibling processes
  • 📂 Coordinated file reading and stdout output
  • ⏳ Using pause() for controlled execution flow
  • ⚡ Signal-triggered child-to-child communication

🔗 Links


🧪 C-Unix-STD-Threads

Path: src/C-Unix-STD-Threads/main.c

🔍 View Code

🎯 Purpose

This example demonstrates creating multiple threads to process pairs of files concurrently. Each thread reads integers from an input file, sorts them, and writes to an output file.

The goals are to understand:

  • Thread creation, argument passing, and termination using pthread_create and pthread_join
  • How to process independent data concurrently
  • Memory management for thread arguments
  • Sorting algorithms in a multithreaded environment

🛠️ Description

  1. Parse command-line arguments as input_file output_file pairs.
  2. Allocate memory for thread IDs and thread argument structures.
  3. Create one thread per file pair, passing a structure containing input/output filenames.
  4. Each thread executes the following steps:
    • Opens the input file and reads integers into a buffer.
    • Sorts the integers using bubble sort.
    • Writes the sorted integers to the output file.
  5. The main thread waits for the last created thread using pthread_join to ensure completion.

📦 Headers and Libraries Used

HeaderDescriptionReference
<pthread.h>POSIX threads APIman7.org
<stdio.h>File I/O and stdoutcppreference
<stdlib.h>Memory allocation, exitcppreference
<string.h>String operations (strcpy, strlen)cppreference

⚙️ System Calls and Functions

FunctionRoleReference
pthread_create()Create a new threadman7.org
pthread_join()Wait for a thread to terminateman7.org
fopen(), fscanf(), fprintf()File read/write operationscppreference
Memory allocation (malloc/free)Allocate memory for thread arguments and bufferscppreference

🧠 Key Concepts Introduced

  • ⚡ Concurrent execution using threads
  • 📁 File I/O in multithreaded applications
  • 🧮 Sorting algorithms executed in parallel
  • 💾 Dynamic memory allocation for passing arguments safely to threads
  • 🔄 Synchronization by joining threads to ensure completion

🔗 Links


🧪 C-Unix-STD-Threads-Files-Assert

Path: src/C-Unix-STD-Threads-Files-Assert/main.c

🔍 View Code

🎯 Purpose

This example demonstrates multithreaded file processing with bubble sort, using assert() to guarantee correctness of read/write operations.

The goals are to understand:

  • Thread-safe processing of multiple input/output files concurrently
  • Using assertions to ensure correct file read/write
  • Implementing bubble sort algorithm inside threads

🛠️ Description

  1. Validate command-line arguments as input_file output_file pairs (odd number of arguments, at least 3).
  2. Allocate structures and thread IDs for all file pairs.
  3. Create one thread per file pair:
    • Thread reads integers from input file.
    • Thread sorts integers using bubble sort.
    • Thread writes sorted integers to output file.
    • Assertions (assert()) verify that bytes read equal bytes written.
  4. Main thread waits for the last thread to finish (pthread_join).

📦 Headers and Libraries Used

HeaderDescriptionReference
<pthread.h>POSIX threads APIman7.org
<stdio.h>File I/Ocppreference
<stdlib.h>Memory allocation, exitcppreference
<assert.h>Error checkingcppreference
<string.h>String operationscppreference

⚙️ System Calls and Functions

FunctionRoleReference
pthread_create()Create thread for each file pairman7.org
pthread_join()Wait for threads to finishman7.org
assert()Verify correctness of read/write operationscppreference
fopen()/fscanf()/fprintf()/fclose()File I/O operationscppreference
Memory allocation (malloc/free)Allocate thread arguments and bufferscppreference

🧠 Key Concepts Introduced

  • ⚡ Multithreading for concurrent file processing
  • 📁 Safe file I/O with assertion checks
  • 🧮 Bubble sort algorithm inside threads
  • 💾 Dynamic memory management for thread arguments
  • 🔄 Synchronization via pthread_join to ensure completion

🔗 Links


Next step, start to use C_Linux examples by following this getting started guideline.


Getting Started 🚀

Table of Contents

This section guides you through preparing your environment and running the C Unix & Standard Library examples presented in this collection. The steps are tailored to Linux/Unix hosts and assume a basic familiarity with compiling and executing C programs.

  • 1 - Verify Prerequisites and Dependencies
    Ensure your system has the necessary development tools and libraries:

    • GCC or Clang compiler (C99/C11 support)
    • Make for build automation (optional but recommended)
    • POSIX-compliant libraries (<unistd.h>, <pthread.h>, <fcntl.h>)
    • Standard C libraries (<stdio.h>, <stdlib.h>, <string.h>, <assert.h>)

    Reading this carefully guarantees that each example can be compiled and executed without errors.

  • 2 - Get the Source Code
    Clone or download the repository containing the examples.
    Ensure the folder structure under <code>src/</code> is preserved, as each example references specific file paths.

  • 3 - Build / Compile Examples
    Compile each example individually using GCC or your preferred compiler:
    gcc -o main main.c -lpthread
    Some examples may require the <code>-lpthread</code> flag for thread support. Others rely on standard POSIX calls and do not require additional flags.

  • 4 - Run Examples
    Execute each compiled binary from the command line.

    • Examples using fork(), exec(), or signals should be run in a terminal on a Unix-like system.
    • File-based examples require input/output files to be placed in the expected paths (<code>src/C-STD-File/file1.txt</code>, etc.).
    • Threaded examples may generate multiple output files concurrently; ensure write permissions in the folder.
  • 5 - Explore and Modify
    Feel free to adjust input files, function parameters, or the number of threads in examples to experiment and observe behavior. This is ideal for learning Unix process management, signals, and concurrent programming in C.

  • 6 - Clean Up / Uninstall
    Remove compiled binaries and temporary files safely:
    rm -f src//main
    rm -f src/
    /file*.out
    This ensures your workspace remains clean while preserving the original source files.


Following these steps guarantees that you can successfully compile, run, and experiment with all examples, from **function pointers** and **file I/O** to **Unix processes**, **signals**, and **threaded programs**.



💻 Prerequisites

Before building or running the project, make sure you satisgy the prerequisites to run the project:

  • Operating System: GNU/Linux, Windows
  • Software Dependencies: GitHub, Doxygen, GNU Make, GNU C Compiler


📦 Dependencies

Before building and generating documentation with C_Linux, make sure the following dependencies are installed on your system:

  • GitHubOptional.
    Even if you don’t have a GitHub account or Git installed, you can still generate documentation locally.
    However, having a GitHub account and using Git is recommended for project deployment and version control.

  • DoxygenMandatory.
    Used to generate documentation from source code and Markdown files.
    The project won’t build documentation without it.

  • GNU MakeMandatory.
    Required to run automated build and documentation generation tasks.
    Used in this project to simplify commands such as:

    make doc

    and

    make clean
  • GNU C Compiler (GCC)Mandatory.
    Required to compile all C examples in C_Linux.
    Supports C99 standard and POSIX APIs.



GitHub Install GitHub / Git

🐧 On GNU/Linux

sudo apt update
sudo apt install git

After installation, verify that Git is available:

git --version

To link your project to GitHub, create a free account at:
👉 https://github.com/signup

Then configure Git with your account details:

git config --global user.name "Your Name"
git config --global user.email "you@example.com"


Windows logo On Windows

  1. Download Git for Windows from:
    👉 https://git-scm.com/download/win

  2. Run the installer and follow the setup wizard (leave default options checked).

  3. After installation, open Git Bash and verify:

    git --version
    
  4. Optionally create a GitHub account at
    👉 https://github.com/signup



Doxygen Install Doxygen

🐧 On GNU/Linux

sudo apt update
sudo apt install doxygen graphviz

Verify the installation:

doxygen --version

Optionally, you can generate a sample configuration file with:

doxygen -g


Windows logo On Windows

  1. Download the Windows installer from:
    👉 https://www.doxygen.nl/download.html

  2. Run the .exe file and follow the setup wizard.

  3. After installation, open Command Prompt and check:

    doxygen --version
    
  4. To enable UML and graphs, install Graphviz as well:
    👉 https://graphviz.org/download/



GNU/Linux Install GNU Make

🐧 On GNU/Linux

GNU Make is usually preinstalled. Check it with:

make --version

If missing, install it via:

sudo apt update
sudo apt install make


Windows logo On Windows

You can install GNU Make in one of these ways:

✅ Option 1: Using MinGW

  1. Download and install MinGW from:
    👉 https://www.mingw-w64.org/
  2. During installation, select the “mingw32-make” package.
  3. Add MinGW’s bin directory to your system PATH.
  4. Verify installation:
    mingw32-make --version
    

You can then rename or alias it to make for convenience.

✅ Option 2: Using Chocolatey (recommended if available)

If you have Chocolatey package manager installed:

choco install make


GCC Install GNU C Compiler (GCC)

🐧 On GNU/Linux

Check if GCC is already installed:

gcc --version

If missing, install it via:

sudo apt update
sudo apt install gcc build-essential

Verify installation:

gcc --version

Windows logo On Windows

✅ Option 1: Using MinGW

  1. Download and install MinGW-w64 from:
    👉 https://www.mingw-w64.org/
  2. During installation, select the gcc package.
  3. Add the bin directory of MinGW to your system PATH.
  4. Verify installation:
gcc --version

✅ Option 2: Using Windows Subsystem for Linux (WSL)

  1. Install WSL with a Linux distribution, e.g., Ubuntu.
  2. Open WSL terminal and run:
sudo apt update
sudo apt install gcc build-essential
gcc --version

✅ Option 3: Using Chocolatey

If you have Chocolatey installed:

choco install mingw

Verify installation:

gcc --version

💡 Dependencies Verification

After installing all dependencies, verify them with:

git --version
doxygen --version
make --version
gcc --version

If all commands return valid version numbers, you’re ready to build and document your project 🎉

💡 Tip: You can also run the doxygen.sh script from the root directory.
It will automatically:

  • Check that Doxygen is installed. If not, the script will fail ❌
  • Generate a base Doxyfile if missing
  • Apply the custom configuration for C_Linux


⭐ Installation

To install the project follow this setps:

A. You can download the repository from GitHub: ⬇️ https://github.com/Unix69/README-Template/archive/refs/heads/main.zip

manually or by opening a terminal into your project destination directory, and running the following commands:

  mkdir project-root #create the project root directory
  cd project-root #change to the project root directory
  wget https://github.com/Unix69/C_Linux/archive/refs/heads/master.zip #make an http get request to get the project repository ** zip file ** 
  unzip master.zip #unzip the project master.zip file
  cp -R master/ ./ #copy all files recursively from the unziped master directory to your project root directory
  rm -rf master master.zip #remove the unziped master directory and master.zip file
  

B. You can clone the repository from GitHub if you have Git installed by running the following commands:

  mkdir project-root #create the project root directory
  cd project-root #change to the project root directory
  clone https://github.com/Unix69/C_Linux.git #clone the project repository 
  cp -R C_Linux/ ./ #copy all files recursively from the C_Linux directory to your project root directory
  rm -rf C_Linux #remove the C_Linux directory. 
  

⬇️ Download ZIP
🐙 View on GitHub



🛠️ Build

To build C_Linux full project you have to build singularly:

  • the example executables you want.
  • the C_Linux project documentation.

1️⃣ Build All Examples

To build the entire C Unix & Standard Library examples:

  • A. Using GNU Make

    make build
    make link_all
    

    Using make build and make link_all allows compiling and linking all C examples in src/ automatically:

    • make build – compiles all .c files in src/ into .o object files.
      • Uses $(CC) $(CFLAGS) -c $< -o $@ to compile each source file individually.
      • Prints a message: Compiling <file>... for each compilation.
      • Ensures that all object files are ready for linking in the next step.
    • make link_all – links the object files in each subfolder of src/ into a single executable per folder.
      • Finds all .o files in the folder using find $@ -maxdepth 1 -name "*.o".
      • Links them with gcc $(CFLAGS) <objects> -o <folder_name>.
      • Prints a success message: Executable created: <folder_name> if linking succeeds.
      • Creates one executable per example folder, mirroring the structure of src/.

    These targets provide a convenient alternative to using find ... -exec gcc ..., as they automatically handle compilation and linking for all examples in the project.

  • B. Using the GNU C Compiler

    find src/ -name "main.c" -exec sh -c 'gcc -Wall -O2 "$1" -o "$(dirname "$1")/main" -lpthread && echo "$(dirname "$1")/main created" || echo "Compilation failed for $1"' _ {} \;
    

    This command recursively compiles all main.c files under src/ into executables:

    • find src/ -name "main.c" – locate all main.c files.
    • -exec sh -c '...' – execute a shell command for each file, passing it as $1.
    • gcc -Wall -O2 "$1" -o "$(dirname "$1")/main" -lpthread – compile with warnings, optimization, and pthread support; output in the same folder.
    • && echo "$(dirname "$1")/main created" – prints a success message if compilation succeeds.
    • || echo "Compilation failed for $1" – prints an error message if compilation fails.

2️⃣ Build a Single Example

If you want to compile only a single example (e.g., C-Func-pointer):

  1. Open a terminal in the example folder:
cd src/C-Func-pointer
  1. Compile using GCC (add <code>-lpthread</code> if the example uses threads):
gcc -o main main.c -lpthread
  1. Run the compiled example:
./main

This approach is ideal for testing or debugging individual examples without rebuilding the entire project.


2️⃣ Build the Project Documentation


Generate the Doxyfile

To build the project documentation, first of all you have to generate a proper Doxyfile. You have multiple ways to generate the documentation resources for the C Unix & Standard Library examples. Each approach below produces a configured Doxyfile.

  • ./doxygen.sh (Custom Doxyfile) – Runs a setup script that:
    • Checks if doxygen is installed and exits with an error message if not.
    • Creates a default Doxyfile if one does not already exist in the project root.
    • Reads the project’s doxygen.ini and applies tag settings into Doxyfile automatically.
    • Adds custom aliases and configuration if missing, ensuring output directory and options are set.
    • Leaves you with a fully configured Doxyfile ready to generate docs via Doxygen.
  • make doc_build – Equivalent to running the setup script via the project’s Makefile:
    • Invokes the doxygen.sh script using the Makefile rule doc_build.
    • Prepares the Doxyfile and applies configuration automatically without manual editing.
    • This approach is ideal if you already use make for building and want documentation integrated into the same workflow.
  • doxygen -g Doxyfile (Standard Doxyfile):
    • Directly generates a **default Doxygen configuration file** named Doxyfile with all tags set to default values.
    • Useful if you prefer to edit the configuration manually, or want to start from a clean template.
    • After adjustment, run doxygen Doxyfile to generate the documentation without using the custom setup script.

In summary:

  • Use doxygen.sh or make doc_build when you want an **automated, customized Doxyfile** based on your project settings;
  • Use doxygen -g Doxyfile when you want to **manually edit a fresh configuration template** before generating docs.

Generate the Project Documentation

Once the Doxyfile is generated and configured as you wish, to make the documentation use:

  • Doxygen Open a terminal into the **root directory** and run the doxygen installed tool with your `Doxyfile`;
          doxygen Doxyfile  
        
  • make doc – Generates documentation using the configured Doxyfile:
    • Runs the doxygen command internally on the prepared Doxyfile.
    • Produces HTML output (and other formats if enabled) in the directory configured by OUTPUT_DIRECTORY (default is docs/html).
    • Copies optional assets (e.g., image resources) into the documentation output folder after generation.
    • This target completes the documentation build process started by doc_build or doxygen.sh.


⚙️ Configuration

To configure the C_Linux project, before you generate the documentation, you can:


  1. Modify Doxygen's options by:

A. Doxygen: Changing/Adding manually a row in ./doxygen.ini before run it again, like:

<code>
  DOXY_PARAMETER = "DOXY_PARAMETER-VALUE"  
</code>

B. Doxyfile: Access the Doxyfile, generated by doxygen.sh script or run the

 doxygen -g Doxyfile
command, then change Doxygen's parameters manually.

  1. Modify the default Makefile and make toolchain to customize and integrate your building behaviour.

  2. You can change the default Markdown .md files to customize your project markdown documentation. The default Markdown project of C_Linux is structured as follow:



🚀 Run

After building the project and/or the documentation, you can run both the generated documentation and the compiled examples.

📄 Run Documentation

  • ✅ The HTML documentation is available in ./docs/html/ or the path specified by the OUTPUT_DIRECTORY in your Doxyfile.
  • You can open it in a browser using a command like:
    xdg-open ./docs/html/index.html
    (Linux/Unix)
  • Or, if on macOS:
    open ./docs/html/index.html
  • 📌 All documentation is also fully available on GitHub as linked .md files. This allows you to navigate the examples directly online or integrate them with the Doxygen-generated HTML documentation via GitHub Pages or a similar static site.

🧩 Run a Single Example

Using C-Func-pointer as an example:

  • Navigate to the folder where the executable was generated:
    cd src/C-Func-pointer
  • Run the executable:
    ./main
  • If compilation was done via make build or make link_all, the executable is typically in the same folder as the main.c file.

⚙️ Run All Examples Automatically

You can run all executables in the src/ tree using a one-liner shell command:

find src/ -mindepth 1 -type f -executable -name "main" -exec sh -c './{} || echo "Execution failed for {}"' \;
  • This command:
    • Searches for all main executables inside src/ subfolders.
    • Executes each one sequentially.
    • Prints an error message if the execution fails for a specific example.

💡 Notes

  • Ensure you have built the examples first using make build and linked them with make link_all.
  • The same approach works for all examples, just replace C-Func-pointer with the desired folder.
  • Documentation can be refreshed anytime with make doc after any updates to the source code or comments.
  • GitHub provides a full integrated view of the documentation: both the Doxygen HTML pages and the .md files for examples are cross-linked, giving a convenient online browsing experience.


❌ Uninstall

To uninstall the C_Linux project and all its generated artifacts, you have multiple options: you can use the make clean target, or remove files manually using shell commands.

🛠️ Using GNU Make

The simplest way is to leverage the clean target from the Makefile:

make clean
  • This command performs the following steps automatically:
    • Removes all compiled object files (*.o) in src/.
    • Removes all executables created in the src/ subfolders.
    • Deletes the Doxygen documentation output directory (docs/).
  • It preserves your main.c, .h, .md and other source files, deleting only build artifacts and generated documentation.

⚙️ Manual Uninstallation

If you prefer to remove everything manually without using Make, you can execute the following shell commands:

# Remove object files
find src/ -name "*.o" -type f -exec rm -f {} \;

# Remove compiled executables
find src/ -mindepth 1 -type f ! -name "*.c" ! -name "*.txt" ! -name "*.h" ! -name "*.hpp" -executable -exec rm -f {} \;

# Remove generated documentation
rm -rf docs/
rm -f Doxyfile
  • The first command finds and deletes all object files (*.o) in src/ subfolders.
  • The second command removes all executables in src/ except source, header, and text files.
  • The third command deletes the documentation directory and optionally the generated Doxyfile.

💡 Notes

  • Using make clean is the recommended approach, as it ensures a consistent cleanup according to the Makefile rules.
  • Manual removal is useful if you want to selectively delete artifacts or do not have Make installed.
  • After cleaning, you can safely rebuild the project or regenerate documentation from scratch.


Licenses 📜

Table of Contents


This project is licensed under the Creative Commons Attribution 4.0 International License (CC BY 4.0) .

You are free to use, modify, and share this template — just give proper credit to Giuseppe Pedone.

© 2025 Giuseppe Pedone — GitHub: Unix69



Contributing 👋

Thank you for your interest in C_Linux!
You can freely download and use the C examples. To contribute, report bugs, or suggest improvements, follow the workflow below.



General Contribution Guidelines

  • Read the CODE_OF_CONDUCT.md
  • Understand the project structure
  • Ensure required tools are installed: GCC, Make, Doxygen

When contributing code:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/your-feature)
  3. Make changes and commit with clear messages (git commit -m "Add feature X")
  4. Push your branch to GitHub
  5. Open a Pull Request (PR)

Keep style consistent, update documentation, and run tests.



Authors 🧑‍💻

Unix69
Giuseppe Pedone (Unix69)
Roles: FO, CEO
Contributions: `FI`, `OP`, `DE`
Email: giuseppe.pedone.developer@gmail.com
Links: GitHub


Official Links 🌐



FAQ ❓

Q1: Which C standard is used?
A1: All examples are written in C99.

Q2: Supported OS?
A2: POSIX-compliant systems, mainly Linux.

Q3: Can I modify and redistribute examples?
A3: Yes! All code is under GNU GPL v3.

Q4: How to compile an example?
A4: Use gcc or run make in project root.

Q5: How to report a bug?
A5: Open a GitHub Issue describing the error, affected example, and steps to reproduce.



Forking & Pull Requests 🔀

Fork the Project

  1. Go to the main repository on GitHub
  2. Click Fork to create your personal copy
  3. Create a branch dedicated to your feature: git checkout -b feature-new-functionality
  4. Keep it synchronized with the main project

Pull Requests (PR)

  1. Ensure your branch is updated with the main branch
  2. Confirm all tests and checks pass
  3. Open a PR with:
    • Clear title (e.g., "Fix: memory leak in example")
    • Summary of changes
    • Related issue numbers (if any)
  4. Wait for maintainers review
  5. Apply requested changes and update PR if needed

PR Guidelines

  • Use concise and descriptive titles
  • Include examples or references if relevant
  • Avoid committing unrelated files


Issues ⚠️

  • Issues are for reporting bugs, requesting features, or asking questions
  • Use the Issue Template if available
  • Clearly describe:
    • Issue type: bug / feature / question
    • Steps to reproduce
    • Expected vs actual behavior
    • Environment: OS, version, configuration

All issues are tracked in the Issues section on GitHub.



Thanks 🙏

Special thanks to the Open Source Community for providing tools and frameworks such as GCC, Linux, GNU Make, and Doxygen.
Your work empowers projects like C_Linux to exist and evolve.



About

Contains examples on using C Linux system call (fork, wait, thread, kill, pause, pipe, condition variable, mutex, semaphores, ...)

Resources

License

Code of conduct

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published