docs(api): require documented public headers
This commit is contained in:
parent
624034acb5
commit
fdb1406ba2
@ -44,6 +44,11 @@
|
||||
- 不写重复描述简单代码行为的注释。
|
||||
- 如果代码依赖硬件手册、启动协议、调用顺序或特殊寄存器状态,应写明约束。
|
||||
- 如果一个实现是临时简化,应写清楚后续替换边界,而不是写成永久接口。
|
||||
- 公共头文件 `include/tianole/*.h` 中的函数声明必须使用 Linux kernel-doc 风格块注释。
|
||||
- 公共函数注释至少说明函数职责、关键参数、返回值或副作用;不要只复述函数名。
|
||||
- 公共函数声明和前一个声明/注释块之间必须留一个空行,避免 API 挤在一起。
|
||||
- 私有 `static` 小函数不要求每个都写函数头注释;只有逻辑、数据流、锁语义或硬件约束不明显时才写。
|
||||
- 多行注释要控制行宽,优先写职责、数据流和调用约束,而不是描述每一行代码。
|
||||
|
||||
## C 格式
|
||||
|
||||
|
||||
@ -3,13 +3,63 @@
|
||||
|
||||
#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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* arch_halt_forever() - Stop execution permanently.
|
||||
*
|
||||
* Used by panic and unrecoverable paths after diagnostics have been emitted.
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* arch_timer_init() - Initialize the architecture timer backend.
|
||||
*
|
||||
* Connects the hardware timer to the generic timer and scheduler path.
|
||||
*/
|
||||
void arch_timer_init(void);
|
||||
|
||||
#endif
|
||||
|
||||
@ -3,11 +3,53 @@
|
||||
|
||||
#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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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));
|
||||
|
||||
#endif
|
||||
|
||||
@ -5,6 +5,14 @@
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
||||
@ -3,6 +3,12 @@
|
||||
|
||||
#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);
|
||||
|
||||
#endif
|
||||
|
||||
@ -15,15 +15,84 @@ typedef uint64_t virt_addr_t;
|
||||
#define PAGE_WRITABLE (1ull << 1)
|
||||
#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);
|
||||
|
||||
/**
|
||||
* alloc_page() - Allocate one physical page.
|
||||
*
|
||||
* Return: Physical page base address, or 0 when no page is available.
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* heap_init() - Initialize the kernel heap.
|
||||
*
|
||||
* Sets up kmalloc()/kfree() after page allocation and page tables are ready.
|
||||
*/
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
||||
@ -38,24 +38,127 @@ struct thread {
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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(
|
||||
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));
|
||||
|
||||
/**
|
||||
* 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));
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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(
|
||||
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,
|
||||
wait_condition_t condition,
|
||||
void *arg,
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
#endif
|
||||
|
||||
@ -12,7 +12,23 @@ struct spinlock {
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
#endif
|
||||
|
||||
@ -3,7 +3,18 @@
|
||||
|
||||
#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);
|
||||
|
||||
/**
|
||||
* timer_ticks() - Read the generic monotonic tick counter.
|
||||
*
|
||||
* Return: Number of timer ticks observed since timer initialization.
|
||||
*/
|
||||
uint64_t timer_ticks(void);
|
||||
|
||||
#endif
|
||||
|
||||
@ -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"))
|
||||
|
||||
|
||||
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]:
|
||||
return sorted(
|
||||
path
|
||||
@ -99,6 +109,108 @@ def check_no_relative_parent_includes(root: Path, files: list[Path]) -> list[str
|
||||
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]:
|
||||
errors = []
|
||||
|
||||
@ -201,6 +313,7 @@ def main() -> int:
|
||||
|
||||
errors = []
|
||||
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_makefile_source_lists(root, files, all_mode))
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user