-
Notifications
You must be signed in to change notification settings - Fork 0
Coding Standards
Code style and conventions for ModuOS development.
-
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/*).
- 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:
- Consistency: Follow existing patterns
- Documentation: Comment complex logic
- Simplicity: Keep it simple when possible
Functions:
// 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:
// 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:
// 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:
// 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:
- 4 spaces (no tabs)
- Align continuation lines
Braces (K&R style):
// 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:
// 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);File headers:
//
// filename.c - Brief description
//
// Part of ModuOS kernel
//Function documentation:
/**
* 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:
// 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-stepBlock comments:
/*
* Long explanation of complex algorithm or logic.
* Multiple lines are okay.
* Use for important sections.
*/Return values:
// 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:
// Always check pointers
void *ptr = malloc(size);
if (ptr == NULL) {
return ENOMEM;
}
// Or use assertions for programmer errors
assert(ptr != NULL);Allocation:
// Use kernel heap functions
void *ptr = kmalloc(size);
if (!ptr) {
return ENOMEM;
}
// Zero-initialize when needed
void *ptr = kzalloc(size);Deallocation:
// Always free allocated memory
kfree(ptr);
ptr = NULL; // Prevent use-after-freeFile structure:
; 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
retIndentation:
- Labels: No indentation
- Instructions: 4 spaces
- Comments: Align with code
Comments:
; Use semicolons for comments
; Explain register usage
; Document calling conventionEither style is acceptable. Prefer consistency within a directory/module.
Traditional include guards:
#ifndef FILENAME_H
#define FILENAME_H
// Header content
#endif // FILENAME_H#pragma once:
// FILENAME_H
#pragma once
// Header content// 1. System includes
#include <stdint.h>
#include <stddef.h>
// 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);Keep functions short: Aim for < 50 lines Single responsibility: One function, one purpose Descriptive names: Name explains what it does
Minimize scope: Declare variables as locally as possible
Initialize: Always initialize variables
Const correctness: Use const for read-only data
Avoid:
// Bad
if (status == 2) { ... }Use named constants:
// Good
#define STATUS_READY 2
if (status == STATUS_READY) { ... }Null checks:
if (ptr == NULL) { ... }
// Or
if (!ptr) { ... }Const pointers:
// Pointer to const data
const char *str = "hello";
// Const pointer
char * const ptr = buffer;
// Const pointer to const data
const char * const ptr = "hello";/**
* 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;
}// 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;
}Critical: Always install IRQ handlers before enabling hardware interrupts to prevent interrupt storms and system hangs.
Incorrect (causes hangs on real hardware):
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):
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:
- Clear and disable interrupts during device initialization
- Install IRQ handler before enabling any hardware interrupts
- Clear pending interrupt status before and after handler installation
- Use posted reads after critical register writes (prevents PCI write posting races)
- 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.
Consider using clang-format with these settings:
BasedOnStyle: LLVM
IndentWidth: 4
ColumnLimit: 100Use compiler warnings:
CFLAGS += -Wall -Wextra -Werror- Contributing - Contribution guide
- Project Structure - Code organization
- Building ModuOS - Build system