Youssef Ameachaq's Blog

Youssef Ameachaq

1️⃣ How Operating Systems Work


An Operating System (OS) is the software that manages a computer’s hardware and software resources. Think of it as the middleman between you (the user) and the physical computer. Without an OS, your computer would be a pile of useless hardware.

Linux is a great example of an OS. It’s widely used in servers, mobile devices (Android), embedded systems, and even supercomputers. Let’s break down how it works in simple terms.


1. The Role of an Operating System

An OS has four main responsibilities:

  1. Managing hardware (CPU, memory, disk, keyboard, mouse, etc.).
  2. Providing a user interface (like a command-line terminal or graphical desktop).
  3. Running and managing programs (applications like web browsers, text editors).
  4. Handling files and storage (reading/writing to hard drives, USBs, etc.).

Now, let’s explore these functions in detail.


2. The Core of Linux: The Kernel

The kernel is the heart of Linux. It’s a special program that sits between the hardware and everything else. The kernel does:

The Linux kernel is monolithic, meaning it includes all core OS functions in one big program. It can load extra components (modules) as needed.


3. How Linux Manages Processes

A process is any running program. The Linux OS does:

Example: If you open a browser and a text editor, Linux switches between them super-fast, making it seem like both run at the same time.

💡 Command to see running processes:

ps aux

4. Memory Management

Linux handles RAM (Random Access Memory) smartly:

💡 Command to check memory usage:

free -h

5. File System Management

Linux organizes data in a hierarchical structure (tree format). Everything is a file in Linux:

Example Linux file system structure:

/
├── home/        (User files)
├── etc/         (Configuration files)
├── var/         (Logs and temporary files)
├── bin/         (Basic system programs)
├── dev/         (Device files)

💡 Commands for file management:

ls        # List files  
cd /home  # Change directory  
rm file.txt  # Delete a file  

6. User and Permission Management

Linux is a multi-user OS. It manages:

Example permissions:

ls -l file.txt

Output:

-rw-r--r--  1 user  group  1234 Jan 1 12:34 file.txt

This means:

💡 Change permissions:

chmod 755 script.sh  # Give execute permission

7. Device Management (Drivers)

Linux treats devices (like USB drives, printers) as files in /dev/.

💡 Check connected devices:

lsblk  # Show block storage devices

8. How Linux Boots (Startup Process)

When you power on a Linux machine:

  1. BIOS/UEFI loads the bootloader (like GRUB).
  2. Bootloader loads the kernel into memory.
  3. Kernel initializes hardware and starts system services.
  4. Login screen or desktop appears.

💡 Check boot logs:

dmesg | less

9. Networking in Linux

Linux manages network connections:

💡 Check network info:

ip addr show

10. Running Programs and Installing Software

Linux uses package managers to install software easily:

💡 Install a program (e.g., VLC Media Player):

sudo apt install vlc  # Ubuntu

11. The Shell and Command Line Interface (CLI)

Linux provides a shell, a program that takes user commands and executes them. Popular shells include:

💡 Run a simple command:

echo "Hello, Linux!"

12. Security Features in Linux

Linux is secure because:

💡 Enable firewall:

sudo ufw enable

Real-World Examples in Go

Example 1: Memory Management

Go manages memory automatically using garbage collection. Here’s an example:

package main

import "fmt"

func main() {
    // Allocate memory for a slice (dynamic array)
    numbers := make([]int, 5) // Creates a slice of 5 integers
    numbers[0] = 10
    numbers[1] = 20

    fmt.Println("Slice:", numbers) // Output: Slice: [10 20 0 0 0]
}

Example 2: Process Scheduling

Go uses goroutines for lightweight concurrency. Here’s an example:

package main

import (
    "fmt"
    "time"
)

func printNumbers() {
    for i := 1; i <= 5; i++ {
        fmt.Println(i)
        time.Sleep(500 * time.Millisecond)
    }
}

func main() {
    // Start a goroutine (like a lightweight thread)
    go printNumbers()

    // Main process continues running
    time.Sleep(3 * time.Second)
    fmt.Println("Main function finished")
}

Example 3: File Systems

Go can read and write files. Here’s an example:

package main

import (
    "fmt"
    "os"
)

func main() {
    // Write to a file
    data := []byte("Hello, OS File System!")
    err := os.WriteFile("example.txt", data, 0644)
    if err != nil {
        fmt.Println("Error writing file:", err)
        return
    }

    // Read from the file
    content, err := os.ReadFile("example.txt")
    if err != nil {
        fmt.Println("Error reading file:", err)
        return
    }

    fmt.Println("File content:", string(content))
}

Example 4: POSIX Basics (stdin, stdout, stderr, pipes)

Go can handle POSIX concepts. Here’s an example:

package main

import (
    "fmt"
    "os"
    "os/exec"
)

func main() {
    // stdout example
    fmt.Println("Hello, stdout!") // Prints to standard output

    // stderr example
    fmt.Fprintln(os.Stderr, "This is an error message!") // Prints to standard error

    // Pipe example
    cmd := exec.Command("echo", "Hello, pipe!")
    output, err := cmd.Output()
    if err != nil {
        fmt.Fprintln(os.Stderr, "Error:", err)
        return
    }
    fmt.Println("Pipe output:", string(output))
}

Example 5: Threads & Concurrency

Go uses goroutines and channels for concurrency. Here’s an example:

package main

import (
    "fmt"
    "time"
)

func worker(id int, jobs <-chan int, results chan<- int) {
    for job := range jobs {
        fmt.Println("Worker", id, "started job", job)
        time.Sleep(time.Second) // Simulate work
        results <- job * 2
        fmt.Println("Worker", id, "finished job", job)
    }
}

func main() {
    jobs := make(chan int, 5)
    results := make(chan int, 5)

    // Start 3 worker goroutines
    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }

    // Send 5 jobs
    for j := 1; j <= 5; j++ {
        jobs <- j
    }
    close(jobs)

    // Collect results
    for a := 1; a <= 5; a++ {
        <-results
    }
}

Example 6: Interprocess Communication (IPC)

Go can use shared memory or sockets for IPC. Here’s an example using sockets:

package main

import (
    "fmt"
    "net"
)

func main() {
    // Start a server
    go func() {
        listener, _ := net.Listen("tcp", ":8080")
        conn, _ := listener.Accept()
        buf := make([]byte, 1024)
        n, _ := conn.Read(buf)
        fmt.Println("Server received:", string(buf[:n]))
        conn.Close()
    }()

    // Client sends a message
    conn, _ := net.Dial("tcp", "localhost:8080")
    conn.Write([]byte("Hello, IPC!"))
    conn.Close()
}