/* Copyright (C) 2021,2022 fef . All rights reserved. */ #pragma once #include #include #include #include #include #include /** * @brief Print an error message and halt the system immediately. * * @param fmt printf style format string */ void panic(const char *fmt, ...) __noreturn __printflike(1, 2); #define panic_if(condition, msg, ...) do { \ if (__predict_false(condition)) \ panic(msg, ##__VA_ARGS__); \ } while (0) void print_regs(const trap_frame_t *ctx); #ifdef DEBUG /** * @brief Assert that statement `x` is true. * If it is not and debugging is enabled, the kernel panics. */ #define KASSERT(x) do { \ if ( __predict_false(!(x)) ) { \ panic("Assertion \"%s\" failed!\n" \ " in function %s()\n" \ " in file %s, line %u\n", \ #x, __func__, __FILENAME__, __LINE__); \ } \ } while (0) #else #define KASSERT(x) do { } while (0) #endif /** * @brief Enter a critical section, meaning preemption gets disabled. * Critical sections should be kept as short as possible for performance. * Cannot be called from irq context because irqs always run atomically. * * @see `critical_leave()` */ static inline void critical_enter(void) { KASSERT(!in_irq()); struct task *tsk = current; tsk->critnest++; } /** * @brief Leave a critical section. * Cannot be called from irq context. * * @see `critical_enter()` */ static inline void critical_leave(void) { KASSERT(!in_irq()); struct task *tsk = current; tsk->critnest--; KASSERT(tsk->critnest >= 0); } static inline bool in_critical(void) { if (in_irq() || !intr_enabled()) return true; return current->critnest > 0; }