# Coding Standards Code style and conventions for ModuOS development. ## General Principles 1. **Clarity over cleverness**: Write readable code - Exception: in *safety-/correctness-critical* paths (fault handling, paging/memory management, IRQ/IDT setup, context switching, etc.), prioritize **correctness and robustness** even if the implementation is more complex or “clever”. Add comments/tests where possible (examples: `src/kernel/fault.c`, `src/kernel/memory/paging.c`, `src/arch/*/interrupts/*`). 2. **Consistency**: Follow existing patterns 3. **Documentation**: Comment complex logic 4. **Simplicity**: Keep it simple when possible ## C Code Style ### Naming Conventions **Functions**: ```c // Format: subsystem_action_object() void process_create(const char *name); int fs_mount_drive(int drive_index); uint64_t memory_allocate_page(void); // Private/internal: prefix with underscore or make static static int _internal_helper(void); ``` **Variables**: ```c // Local: lowercase with underscores int process_count; uint64_t physical_address; char *file_path; // Global: prefix with subsystem or make explicit extern int boot_drive_index; int acpi_initialized; ``` **Constants and Macros**: ```c // All uppercase with underscores #define MAX_PROCESSES 256 #define PAGE_SIZE 4096 #define MULTIBOOT_MAGIC 0x36d76289 // Function-like macros: can use lowercase #define min(a, b) ((a) < (b) ? (a) : (b)) ``` **Types**: ```c // Structs: suffix with _t typedef struct process { // fields } process_t; // Enums: suffix with _t typedef enum { STATE_READY, STATE_RUNNING } process_state_t; // Function pointers: suffix with _t typedef void (*irq_handler_t)(registers_t *regs); ``` ### Indentation and Formatting **Indentation**: - **4 spaces** (no tabs) - Align continuation lines **Braces** (K&R style): ```c // Functions: brace on same line void function_name(int arg) { // code } // Control structures: brace on same line if (condition) { // code } else { // code } for (int i = 0; i < n; i++) { // code } while (condition) { // code } ``` **Line length**: Maximum 100 characters (prefer 80) **Spaces**: ```c // After keywords if (condition) for (int i = 0; i < n; i++) while (running) // Around operators x = y + z; if (a == b) // After commas function(arg1, arg2, arg3); // No space before function call parenthesis function(arg); ``` ### Comments **File headers**: ```c // // filename.c - Brief description // // Part of ModuOS kernel // ``` **Function documentation**: ```c /** * Brief one-line description * * Longer description if needed. Explain what the function * does, any important behavior, side effects, etc. * * @param name Description of parameter * @param value Description of parameter * @return Description of return value (0 on success, negative on error) */ int function_name(const char *name, int value); ``` **Inline comments**: ```c // Explain WHY, not WHAT // Good example: cli(); // Disable interrupts to prevent race condition // Bad example: cli(); // Clear interrupt flag // Use comments to explain complex logic // Break down algorithms step-by-step ``` **Block comments**: ```c /* * Long explanation of complex algorithm or logic. * Multiple lines are okay. * Use for important sections. */ ``` ### Error Handling **Return values**: ```c // Use 0 for success, negative for errors #define SUCCESS 0 #define ERROR -1 #define ENOMEM -4 #define EINVAL -5 int function(void) { if (error_condition) { return ERROR; } return SUCCESS; } ``` **Null checks**: ```c // Always check pointers void *ptr = malloc(size); if (ptr == NULL) { return ENOMEM; } // Or use assertions for programmer errors assert(ptr != NULL); ``` ### Memory Management **Allocation**: ```c // Use kernel heap functions void *ptr = kmalloc(size); if (!ptr) { return ENOMEM; } // Zero-initialize when needed void *ptr = kzalloc(size); ``` **Deallocation**: ```c // Always free allocated memory kfree(ptr); ptr = NULL; // Prevent use-after-free ``` ## Assembly Style ### NASM Syntax **File structure**: ```nasm ; filename.asm - Brief description ; Part of ModuOS kernel section .text bits 64 global function_name extern external_function ; Function: Brief description ; Parameters: RDI = arg1, RSI = arg2 ; Returns: RAX = return value function_name: push rbp mov rbp, rsp ; Function body ; Add comments for complex operations pop rbp ret ``` **Indentation**: - Labels: No indentation - Instructions: 4 spaces - Comments: Align with code **Comments**: ```nasm ; Use semicolons for comments ; Explain register usage ; Document calling convention ``` ## Header Files ### Include Guards Either style is acceptable. Prefer consistency within a directory/module. **Traditional include guards**: ```c #ifndef FILENAME_H #define FILENAME_H // Header content #endif // FILENAME_H ``` **`#pragma once`**: ```c // FILENAME_H #pragma once // Header content ``` ### Organization**: ```c // 1. System includes #include #include // 2. Project includes #include "moduos/kernel/kernel.h" // 3. Constants #define MAX_VALUE 100 // 4. Type definitions typedef struct foo foo_t; // 5. Function declarations void init(void); ``` ## Best Practices ### Functions **Keep functions short**: Aim for < 50 lines **Single responsibility**: One function, one purpose **Descriptive names**: Name explains what it does ### Variables **Minimize scope**: Declare variables as locally as possible **Initialize**: Always initialize variables **Const correctness**: Use `const` for read-only data ### Magic Numbers **Avoid**: ```c // Bad if (status == 2) { ... } ``` **Use named constants**: ```c // Good #define STATUS_READY 2 if (status == STATUS_READY) { ... } ``` ### Pointer Usage **Null checks**: ```c if (ptr == NULL) { ... } // Or if (!ptr) { ... } ``` **Const pointers**: ```c // Pointer to const data const char *str = "hello"; // Const pointer char * const ptr = buffer; // Const pointer to const data const char * const ptr = "hello"; ``` ## Examples ### Good Code ```c /** * Create a new process * * @param name Process name * @param entry Entry point function * @param priority Priority level (0 = highest) * @return Pointer to process, or NULL on error */ process_t* process_create(const char *name, void (*entry)(void), int priority) { // Validate inputs if (!name || !entry) { return NULL; } // Find free PID int pid = find_free_pid(); if (pid < 0) { return NULL; // Process table full } // Allocate process structure process_t *proc = kzalloc(sizeof(process_t)); if (!proc) { return NULL; // Out of memory } // Initialize process proc->pid = pid; strncpy(proc->name, name, PROCESS_NAME_MAX); proc->state = PROCESS_STATE_READY; proc->priority = priority; return proc; } ``` ### Bad Code ```c // No comments, poor naming, no error handling process_t* pc(char *n,void(*e)(),int p){ process_t *p=malloc(sizeof(process_t)); p->pid=fpid(); strcpy(p->name,n); p->state=0; return p; } ``` ## Hardware Driver Guidelines ### Interrupt Initialization Order **Critical**: Always install IRQ handlers **before** enabling hardware interrupts to prevent interrupt storms and system hangs. **Incorrect** (causes hangs on real hardware): ```c void driver_init(device_t *dev) { // Reset device device_reset(dev); // Enable interrupts - WRONG! Handler not installed yet dev->regs->int_enable = INT_ALL; // Install handler - TOO LATE! irq_install_handler(dev->irq, driver_irq_handler); } ``` **Correct** (safe initialization): ```c void driver_init(device_t *dev) { // Reset device device_reset(dev); // Clear any pending interrupts from BIOS/firmware dev->regs->int_status = 0xFFFFFFFF; // W1C // Disable interrupts during initialization dev->regs->int_enable = 0; // Initialize device structures setup_dma_buffers(dev); setup_command_queues(dev); // Install IRQ handler FIRST irq_install_handler(dev->irq, driver_irq_handler); // NOW it's safe to enable interrupts dev->regs->int_status = 0xFFFFFFFF; // Clear again dev->regs->int_enable = INT_ALL; // Posted read to ensure write completes (prevents PCI write posting issues) (void)dev->regs->int_enable; } ``` **Key Rules**: 1. Clear and disable interrupts during device initialization 2. Install IRQ handler **before** enabling any hardware interrupts 3. Clear pending interrupt status **before** and **after** handler installation 4. Use posted reads after critical register writes (prevents PCI write posting races) 5. Ensure all data structures are initialized before interrupts can fire **Common Mistakes**: - Enabling global controller interrupts before all ports/channels are ready - Forgetting to clear stale interrupts left by BIOS/firmware - Not using posted reads after register writes on PCI devices - Enabling port/device-specific interrupts during probe/initialization This pattern prevents interrupt storms that cause hangs on VirtualBox, VMware, Bochs, and real hardware. ## Tools ### Code Formatting Consider using `clang-format` with these settings: ```yaml BasedOnStyle: LLVM IndentWidth: 4 ColumnLimit: 100 ``` ### Static Analysis Use compiler warnings: ```makefile CFLAGS += -Wall -Wextra -Werror ``` ## Next Steps - [Contributing](Contributing.md) - Contribution guide - [Project Structure](Project-Structure.md) - Code organization - [Building ModuOS](Building-ModuOS.md) - Build system