docs(api): require documented public headers

This commit is contained in:
Microindole 2026-05-12 17:50:17 +08:00
parent 624034acb5
commit fdb1406ba2
No known key found for this signature in database
GPG Key ID: 22FB34CD2133ACA1
10 changed files with 423 additions and 0 deletions

View File

@ -44,6 +44,11 @@
- 不写重复描述简单代码行为的注释。 - 不写重复描述简单代码行为的注释。
- 如果代码依赖硬件手册、启动协议、调用顺序或特殊寄存器状态,应写明约束。 - 如果代码依赖硬件手册、启动协议、调用顺序或特殊寄存器状态,应写明约束。
- 如果一个实现是临时简化,应写清楚后续替换边界,而不是写成永久接口。 - 如果一个实现是临时简化,应写清楚后续替换边界,而不是写成永久接口。
- 公共头文件 `include/tianole/*.h` 中的函数声明必须使用 Linux kernel-doc 风格块注释。
- 公共函数注释至少说明函数职责、关键参数、返回值或副作用;不要只复述函数名。
- 公共函数声明和前一个声明/注释块之间必须留一个空行,避免 API 挤在一起。
- 私有 `static` 小函数不要求每个都写函数头注释;只有逻辑、数据流、锁语义或硬件约束不明显时才写。
- 多行注释要控制行宽,优先写职责、数据流和调用约束,而不是描述每一行代码。
## C 格式 ## C 格式

View File

@ -3,13 +3,63 @@
#include <stdint.h> #include <stdint.h>
/**
* arch_early_log_init() - Initialize architecture early log devices.
*
* Provides the backend setup used by the generic early log front end.
*/
void arch_early_log_init(void); void arch_early_log_init(void);
/**
* arch_early_log_putc() - Emit one character through arch early log devices.
* @ch: Character to write.
*
* This keeps port I/O and other architecture details out of generic logging.
*/
void arch_early_log_putc(char ch); void arch_early_log_putc(char ch);
/**
* arch_halt_forever() - Stop execution permanently.
*
* Used by panic and unrecoverable paths after diagnostics have been emitted.
*/
void arch_halt_forever(void) __attribute__((noreturn)); void arch_halt_forever(void) __attribute__((noreturn));
/**
* arch_irq_save() - Save interrupt state and disable maskable interrupts.
*
* Return: Architecture flags needed by arch_irq_restore().
*/
uint64_t arch_irq_save(void); uint64_t arch_irq_save(void);
/**
* arch_irq_restore() - Restore a previously saved interrupt state.
* @flags: Value returned by arch_irq_save().
*
* This is the backend for interrupt-safe spinlocks on the current CPU.
*/
void arch_irq_restore(uint64_t flags); void arch_irq_restore(uint64_t flags);
/**
* arch_page_table_uses_page() - Check whether a page backs page tables.
* @page: Physical page base address.
*
* Return: Non-zero if the architecture page-table layer owns the page.
*/
int arch_page_table_uses_page(uint64_t page); int arch_page_table_uses_page(uint64_t page);
/**
* arch_traps_init() - Initialize architecture trap and IRQ entry tables.
*
* Sets up descriptor tables and entry points before devices enable IRQs.
*/
void arch_traps_init(void); void arch_traps_init(void);
/**
* arch_timer_init() - Initialize the architecture timer backend.
*
* Connects the hardware timer to the generic timer and scheduler path.
*/
void arch_timer_init(void); void arch_timer_init(void);
#endif #endif

View File

@ -3,11 +3,53 @@
#include <stdint.h> #include <stdint.h>
/**
* early_log_init() - Initialize early logging backends.
*
* Sets up the architecture-provided early output path. This must be usable
* before heap, scheduler, VFS or normal drivers exist.
*/
void early_log_init(void); void early_log_init(void);
/**
* early_log_putc() - Write one character to every early log backend.
* @ch: Character to emit.
*
* This is the byte-level output path used by the string and number helpers.
*/
void early_log_putc(char ch); void early_log_putc(char ch);
/**
* early_log_puts() - Write a NUL-terminated string to early logs.
* @text: String to emit. A NULL pointer is ignored by callers only if they
* explicitly check before calling.
*
* The function does not allocate memory and is safe for early boot diagnostics.
*/
void early_log_puts(const char *text); void early_log_puts(const char *text);
/**
* early_log_u64_hex() - Write a 64-bit value in hexadecimal form.
* @value: Value to print.
*
* Used by trap, memory and boot diagnostics where libc formatting is absent.
*/
void early_log_u64_hex(uint64_t value); void early_log_u64_hex(uint64_t value);
/**
* early_log_u64_decimal() - Write a 64-bit value in decimal form.
* @value: Value to print.
*
* Used for counters and boot statistics without depending on printf support.
*/
void early_log_u64_decimal(uint64_t value); void early_log_u64_decimal(uint64_t value);
/**
* panic() - Print a fatal error and stop the machine.
* @message: Panic reason to include in the early log.
*
* This path must work even when normal kernel services are not initialized.
*/
void panic(const char *message) __attribute__((noreturn)); void panic(const char *message) __attribute__((noreturn));
#endif #endif

View File

@ -5,6 +5,14 @@
typedef void (*irq_handler_t)(uint8_t irq, void *data); typedef void (*irq_handler_t)(uint8_t irq, void *data);
/**
* irq_register() - Register a handler for an external IRQ line.
* @irq: IRQ line number in the generic IRQ namespace.
* @handler: Function called when the IRQ is dispatched.
* @data: Opaque handler data passed back during dispatch.
*
* Return: 0 on success, negative value on failure.
*/
int irq_register(uint8_t irq, irq_handler_t handler, void *data); int irq_register(uint8_t irq, irq_handler_t handler, void *data);
#endif #endif

View File

@ -3,6 +3,12 @@
#include <tianole/boot_info.h> #include <tianole/boot_info.h>
/**
* kernel_report_boot_state() - Log the boot handoff state.
* @boot_info: Firmware-independent boot data passed to the kernel.
*
* Prints early diagnostics used to verify the bootloader-to-kernel contract.
*/
void kernel_report_boot_state(const boot_info_t *boot_info); void kernel_report_boot_state(const boot_info_t *boot_info);
#endif #endif

View File

@ -15,15 +15,84 @@ typedef uint64_t virt_addr_t;
#define PAGE_WRITABLE (1ull << 1) #define PAGE_WRITABLE (1ull << 1)
#define PAGE_NO_EXECUTE (1ull << 63) #define PAGE_NO_EXECUTE (1ull << 63)
/**
* mm_init() - Initialize the generic memory manager.
* @boot_info: Bootloader-provided memory map and handoff data.
*
* Converts boot memory information into Tianole-owned page allocator state.
*/
void mm_init(const boot_info_t *boot_info); void mm_init(const boot_info_t *boot_info);
/**
* alloc_page() - Allocate one physical page.
*
* Return: Physical page base address, or 0 when no page is available.
*/
phys_addr_t alloc_page(void); phys_addr_t alloc_page(void);
/**
* free_page() - Return one physical page to the allocator.
* @page: Physical page base address previously returned by alloc_page().
*
* The page must not still be mapped or owned by another subsystem.
*/
void free_page(phys_addr_t page); void free_page(phys_addr_t page);
/**
* kmalloc() - Allocate small kernel heap memory.
* @size: Number of bytes requested.
*
* Return: Kernel virtual pointer, or NULL when allocation fails.
*/
void *kmalloc(size_t size); void *kmalloc(size_t size);
/**
* kfree() - Free memory allocated by kmalloc().
* @ptr: Pointer returned by kmalloc(), or NULL.
*
* Releases the allocation back to the kernel heap.
*/
void kfree(void *ptr); void kfree(void *ptr);
/**
* map_page() - Map one virtual page to one physical page.
* @virt: Virtual page address.
* @phys: Physical page address.
* @flags: Generic page flags such as PAGE_WRITABLE.
*
* Return: 0 on success, negative value on failure.
*/
int map_page(virt_addr_t virt, phys_addr_t phys, uint64_t flags); int map_page(virt_addr_t virt, phys_addr_t phys, uint64_t flags);
/**
* unmap_page() - Remove one virtual page mapping.
* @virt: Virtual page address to unmap.
*
* Return: 0 on success, negative value on failure.
*/
int unmap_page(virt_addr_t virt); int unmap_page(virt_addr_t virt);
/**
* virt_to_phys() - Resolve a virtual address to a physical address.
* @virt: Virtual address to query.
* @phys: Output storage for the resolved physical address.
*
* Return: 0 when a mapping exists, negative value otherwise.
*/
int virt_to_phys(virt_addr_t virt, phys_addr_t *phys); int virt_to_phys(virt_addr_t virt, phys_addr_t *phys);
/**
* heap_init() - Initialize the kernel heap.
*
* Sets up kmalloc()/kfree() after page allocation and page tables are ready.
*/
void heap_init(void); void heap_init(void);
/**
* page_table_selftest() - Run boot-time page table checks.
*
* Verifies map, unmap and address translation behavior during early boot.
*/
void page_table_selftest(void); void page_table_selftest(void);
#endif #endif

View File

@ -38,24 +38,127 @@ struct thread {
char name[32]; char name[32];
}; };
/**
* sched_init() - Initialize scheduler core state.
*
* Creates scheduler data structures and runs scheduler selftests before
* threads are started.
*/
void sched_init(void); void sched_init(void);
/**
* kernel_thread_create() - Create a kernel thread.
* @name: Human-readable thread name used by diagnostics.
* @entry: Thread entry point.
* @arg: Opaque argument passed to @entry.
*
* Return: Thread object on success, or NULL when allocation fails.
*/
struct thread *kernel_thread_create( struct thread *kernel_thread_create(
const char *name, kernel_thread_entry_t entry, void *arg); const char *name, kernel_thread_entry_t entry, void *arg);
/**
* kernel_thread_exit() - Terminate the current kernel thread.
*
* Marks the current thread dead and yields forever until the scheduler
* switches away and later reclaims it from a safe context.
*/
void kernel_thread_exit(void) __attribute__((noreturn)); void kernel_thread_exit(void) __attribute__((noreturn));
/**
* sched_start() - Start scheduler demo threads and enter scheduling.
*
* Creates the idle thread and current boot-stage scheduler demonstration.
*/
void sched_start(void) __attribute__((noreturn)); void sched_start(void) __attribute__((noreturn));
/**
* sched_tick() - Notify the scheduler about a timer tick.
* @tick: Current generic timer tick.
*
* Wakes sleeping threads whose deadlines expired and requests rescheduling.
*/
void sched_tick(uint64_t tick); void sched_tick(uint64_t tick);
/**
* sched_irq_exit() - Consume pending reschedule work after IRQ handling.
*
* Keeps timer IRQ handling short by moving the actual scheduling decision to
* a common interrupt-exit boundary.
*/
void sched_irq_exit(void); void sched_irq_exit(void);
/**
* sched_yield() - Yield the CPU to another runnable kernel thread.
*
* Performs cooperative scheduling and context switching when another runnable
* thread is available.
*/
void sched_yield(void); void sched_yield(void);
/**
* sched_sleep() - Sleep the current thread for a number of ticks.
* @ticks: Number of timer ticks to sleep.
*
* Marks the current thread sleeping and yields until the timer path wakes it.
*/
void sched_sleep(uint64_t ticks); void sched_sleep(uint64_t ticks);
/**
* wait_queue_init() - Initialize a wait queue.
* @queue: Wait queue storage owned by the caller.
*
* Resets queue links and the internal interrupt-safe lock.
*/
void wait_queue_init(struct wait_queue *queue); void wait_queue_init(struct wait_queue *queue);
/**
* wait_queue_sleep() - Sleep until another thread wakes the queue.
* @queue: Queue to sleep on.
*
* Enqueues the current thread, marks it waiting and yields until wakeup.
*/
void wait_queue_sleep(struct wait_queue *queue); void wait_queue_sleep(struct wait_queue *queue);
/**
* wait_queue_wait() - Sleep until a condition becomes true.
* @queue: Queue used for wakeups.
* @condition: Predicate checked before and after sleeping.
* @arg: Opaque predicate argument.
*
* Return: 0 when the condition is true, negative value on invalid input.
*/
int wait_queue_wait( int wait_queue_wait(
struct wait_queue *queue, wait_condition_t condition, void *arg); struct wait_queue *queue, wait_condition_t condition, void *arg);
/**
* wait_queue_wait_timeout() - Sleep until a condition or timeout.
* @queue: Queue used for wakeups.
* @condition: Predicate checked before and after sleeping.
* @arg: Opaque predicate argument.
* @ticks: Maximum number of timer ticks to wait.
*
* Return: 0 when the condition is true, negative value on timeout or error.
*/
int wait_queue_wait_timeout(struct wait_queue *queue, int wait_queue_wait_timeout(struct wait_queue *queue,
wait_condition_t condition, wait_condition_t condition,
void *arg, void *arg,
uint64_t ticks); uint64_t ticks);
/**
* wait_queue_wake_one() - Wake one thread from a wait queue.
* @queue: Queue containing waiting threads.
*
* Removes the oldest waiter and marks it ready if it is still waitable.
*/
void wait_queue_wake_one(struct wait_queue *queue); void wait_queue_wake_one(struct wait_queue *queue);
/**
* wait_queue_wake_all() - Wake every thread from a wait queue.
* @queue: Queue containing waiting threads.
*
* Drains the queue and marks every waitable thread ready.
*/
void wait_queue_wake_all(struct wait_queue *queue); void wait_queue_wake_all(struct wait_queue *queue);
#endif #endif

View File

@ -12,7 +12,23 @@ struct spinlock {
0 \ 0 \
} }
/**
* spin_lock_irqsave() - Acquire a single-CPU interrupt-safe spinlock.
* @lock: Lock to acquire.
* @flags: Storage for the previous interrupt state.
*
* Disables interrupts before taking the lock so IRQ and thread context can
* share early kernel data structures.
*/
void spin_lock_irqsave(struct spinlock *lock, uint64_t *flags); void spin_lock_irqsave(struct spinlock *lock, uint64_t *flags);
/**
* spin_unlock_irqrestore() - Release an interrupt-safe spinlock.
* @lock: Lock to release.
* @flags: Interrupt state returned by spin_lock_irqsave().
*
* Restores the caller's original interrupt state after releasing the lock.
*/
void spin_unlock_irqrestore(struct spinlock *lock, uint64_t flags); void spin_unlock_irqrestore(struct spinlock *lock, uint64_t flags);
#endif #endif

View File

@ -3,7 +3,18 @@
#include <stdint.h> #include <stdint.h>
/**
* timer_tick() - Advance generic timer state by one hardware tick.
*
* Called by the architecture timer IRQ handler before scheduler tick handling.
*/
void timer_tick(void); void timer_tick(void);
/**
* timer_ticks() - Read the generic monotonic tick counter.
*
* Return: Number of timer ticks observed since timer initialization.
*/
uint64_t timer_ticks(void); uint64_t timer_ticks(void);
#endif #endif

View File

@ -72,6 +72,16 @@ def source_files(files: set[Path]) -> list[Path]:
return sorted(path for path in files if path.suffix in (".c", ".h")) return sorted(path for path in files if path.suffix in (".c", ".h"))
def public_headers(files: set[Path]) -> list[Path]:
return sorted(
path
for path in files
if path.suffix == ".h"
and len(path.parts) == 3
and path.parts[:2] == ("include", "tianole")
)
def c_files(files: set[Path]) -> list[Path]: def c_files(files: set[Path]) -> list[Path]:
return sorted( return sorted(
path path
@ -99,6 +109,108 @@ def check_no_relative_parent_includes(root: Path, files: list[Path]) -> list[str
return errors return errors
def is_function_declaration_start(line: str) -> bool:
stripped = line.strip()
if stripped == "" or stripped.startswith("#"):
return False
if stripped.startswith(("typedef ", "struct ", "enum ", "union ")):
return False
if "(" not in stripped or stripped.startswith("*"):
return False
if "(*" in stripped or stripped.endswith("{"):
return False
return True
def collect_function_declarations(lines: list[str]) -> list[tuple[int, int, str]]:
decls = []
index = 0
while index < len(lines):
if not is_function_declaration_start(lines[index]):
index += 1
continue
start = index
text = lines[index].strip()
while ";" not in lines[index]:
index += 1
if index >= len(lines):
break
text += " " + lines[index].strip()
if index < len(lines):
decls.append((start, index, text))
index += 1
return decls
def has_kernel_doc_before(lines: list[str], start: int) -> bool:
index = start - 1
while index >= 0 and lines[index].strip() == "":
index -= 1
if index < 0 or lines[index].strip() != "*/":
return False
while index >= 0:
if lines[index].strip().startswith("/**"):
return True
index -= 1
return False
def has_blank_line_before_doc(lines: list[str], start: int) -> bool:
index = start - 1
while index >= 0 and lines[index].strip() == "":
index -= 1
if index < 0 or lines[index].strip() != "*/":
return True
while index >= 0 and not lines[index].strip().startswith("/**"):
index -= 1
if index <= 0:
return True
return lines[index - 1].strip() == ""
def check_public_header_function_docs(root: Path, files: list[Path]) -> list[str]:
errors = []
for path in files:
lines = read_text(root, path).splitlines()
for start, _end, text in collect_function_declarations(lines):
line_no = start + 1
name = text.split("(", 1)[0].split()[-1].lstrip("*")
if not has_kernel_doc_before(lines, start):
errors.append(
f"{path}:{line_no}: public function '{name}' needs "
"a kernel-doc comment immediately before it"
)
continue
if not has_blank_line_before_doc(lines, start):
errors.append(
f"{path}:{line_no}: public function '{name}' "
"comment block must be separated by a blank line"
)
return errors
def check_selftests_are_centralized(files: list[Path]) -> list[str]: def check_selftests_are_centralized(files: list[Path]) -> list[str]:
errors = [] errors = []
@ -201,6 +313,7 @@ def main() -> int:
errors = [] errors = []
errors.extend(check_no_relative_parent_includes(root, source_files(files))) errors.extend(check_no_relative_parent_includes(root, source_files(files)))
errors.extend(check_public_header_function_docs(root, public_headers(files)))
errors.extend(check_selftests_are_centralized(c_files(files))) errors.extend(check_selftests_are_centralized(c_files(files)))
errors.extend(check_makefile_source_lists(root, files, all_mode)) errors.extend(check_makefile_source_lists(root, files, all_mode))