refactoring complete
This commit is contained in:
parent
d9e3e91109
commit
18830d645a
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
.idea
|
.idea
|
||||||
cmake-build-debug
|
cmake-build-debug
|
||||||
out/
|
out/
|
||||||
|
.vscode
|
||||||
|
@ -4,9 +4,9 @@ cmake_minimum_required(VERSION 3.10)
|
|||||||
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
|
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
|
||||||
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
|
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
|
||||||
|
|
||||||
project(fusion)
|
project(bond)
|
||||||
|
|
||||||
set(proj fusion)
|
set(proj bond)
|
||||||
set(INC ${CMAKE_CURRENT_SOURCE_DIR}/inc)
|
set(INC ${CMAKE_CURRENT_SOURCE_DIR}/inc)
|
||||||
set(MK ${CMAKE_CURRENT_SOURCE_DIR}/mk)
|
set(MK ${CMAKE_CURRENT_SOURCE_DIR}/mk)
|
||||||
set(arch amd64)
|
set(arch amd64)
|
||||||
@ -27,17 +27,23 @@ FOREACH(f IN LISTS TOOLCHAINS)
|
|||||||
endif()
|
endif()
|
||||||
endforeach(f)
|
endforeach(f)
|
||||||
|
|
||||||
|
set(CC_WARN_IGNORE
|
||||||
|
-Wno-gnu-statement-expression # this means we can assign the return val of the last statment in a block, useful in MAX, MIN, etc.
|
||||||
|
-Wno-gnu-zero-variadic-macro-arguments # this enables us to use __VA_ARGS__ in macros
|
||||||
|
)
|
||||||
|
|
||||||
set(CC_FLAGS
|
set(CC_FLAGS
|
||||||
-std=c17
|
-std=c17
|
||||||
-c
|
-c
|
||||||
-g
|
-g
|
||||||
-O2
|
-Og
|
||||||
-Wall
|
-Wall
|
||||||
-Wextra
|
-Wextra
|
||||||
-Wpedantic
|
-Wpedantic
|
||||||
-Werror
|
-Werror
|
||||||
|
${CC_WARN_IGNORE}
|
||||||
-ffreestanding
|
-ffreestanding
|
||||||
-I${CMAKE_CURRENT_SOURCE_DIR}/inc
|
-I${INC}
|
||||||
-fno-pic
|
-fno-pic
|
||||||
-fno-stack-protector
|
-fno-stack-protector
|
||||||
${CC_FLAGS_${ARCH}})
|
${CC_FLAGS_${ARCH}})
|
||||||
@ -64,7 +70,8 @@ set(DMP_FLAGS
|
|||||||
set(SUBMODULES
|
set(SUBMODULES
|
||||||
kern
|
kern
|
||||||
arch
|
arch
|
||||||
scripts)
|
scripts
|
||||||
|
test)
|
||||||
|
|
||||||
# process submodules
|
# process submodules
|
||||||
FOREACH(f IN LISTS SUBMODULES)
|
FOREACH(f IN LISTS SUBMODULES)
|
||||||
@ -125,8 +132,9 @@ add_custom_target(${proj}_iso ALL
|
|||||||
|
|
||||||
# hack for clion not parsing custom targets
|
# hack for clion not parsing custom targets
|
||||||
if ($ENV{CLION_IDE})
|
if ($ENV{CLION_IDE})
|
||||||
include_directories(inc)
|
include_directories(${INC})
|
||||||
add_executable(kernel ${G_CC_SRC})
|
add_executable(kernel ${G_CC_SRC})
|
||||||
|
target_compile_options(kernel PRIVATE ${CC_FLAGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
46
README.md
46
README.md
@ -1,7 +1,4 @@
|
|||||||
# Building
|
# Building
|
||||||
### Environment
|
|
||||||
All platforms where the required packages are available.
|
|
||||||
|
|
||||||
### Required packages
|
### Required packages
|
||||||
For compiling kernel only (make compile):
|
For compiling kernel only (make compile):
|
||||||
|
|
||||||
@ -24,3 +21,46 @@ Load the iso with your favorite simulator or use "-kernel" option with QEMU.
|
|||||||
|
|
||||||
For UEFI simulation, use qemu_bios.bin in the root dir with QEMU.
|
For UEFI simulation, use qemu_bios.bin in the root dir with QEMU.
|
||||||
|
|
||||||
|
# C++
|
||||||
|
I would like my kernel code to be explicit so that I can reason about performance, memory allocation/deallocation. That mostly means when I look at a statement I know exactly what it does.
|
||||||
|
The philosophy overlaps with Go's design quite a lot: https://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html.
|
||||||
|
|
||||||
|
Using fully-featured C++ is overly complicated for kernels and I'm dubious of OOP in general. With "modern" C++ sometimes I find myself struggling more with the language itself than getting work done. Although the kernel is compiled with a C++ compiler, the base is very much C and we only add few nice things we can benefit from C++:
|
||||||
|
|
||||||
|
## Stronger types
|
||||||
|
C++ is stronger typed than C. Simply compiling the kernel itself with a C++ compiler provides more type safety than C.
|
||||||
|
|
||||||
|
## C++ style casts (no dynamic_cast)
|
||||||
|
They are compile time casts so no runtime overhead. They provide a bit better type safety than C style casts. The only two casts we would need are probably const_cast and reinterpret_cast.
|
||||||
|
|
||||||
|
## template
|
||||||
|
For type safety for data structures. Linux's list.h isn't type safe. FreeBSD's queue.h tries to mimic templates with macros, which is less elegant than just using template.
|
||||||
|
|
||||||
|
## namespace
|
||||||
|
Oh boy how I wish C standard would include namespace, if it weren't for backward compaibility and stable ABI.
|
||||||
|
|
||||||
|
## Banned features worth mentioning
|
||||||
|
This list explains SOME of the banned features that might seem useful.
|
||||||
|
|
||||||
|
### Class and ctors/dtors
|
||||||
|
All data structures should be POD structs. Basically it means a struct without user-defined constructors and destructors. The reason is 1. encapsulation is pretty useless in the kernel. 2. constructors and destructors are implicitly called when declaring objects and when objects go out of scope, which violates explicitness. 3. Everything becomes easy to reason about. Now I don't need to worry about "Object obj;" implicitly invoking the allocator, acquiring a lock and querying a SQL database.
|
||||||
|
|
||||||
|
RAII which relies on ctors/dtors sure is nice but IMO Golang's defer is a much better approach being expressive as well as functionally "similar". C has the extension "cleanup" supported by GCC and Clang which does the same thing as defer. I'll investigate the latter.
|
||||||
|
|
||||||
|
### Member methods
|
||||||
|
Member methods should just be functions that take the struct as a parameter. It's what C++ does internally anyway. Adding member methods also obfuscates the PODness of structs, ergo banned.
|
||||||
|
|
||||||
|
### Inheritance
|
||||||
|
Inheritance is banned except for describing interfaces like file descriptors and other possible places that might benefit from it. Even then it shouldn't be abused - e.g. the kernel does NOT need a generic list interface with a billion implementations.
|
||||||
|
|
||||||
|
### Function overloading
|
||||||
|
Just give it an expressive enough name. Function overloading is obfuscation.
|
||||||
|
|
||||||
|
### Operator overriding
|
||||||
|
Think about what "f();" could mean in C++ and the code executed by "a + b;". Need I say more?
|
||||||
|
|
||||||
|
### References
|
||||||
|
I don't like mixing references with pointers. I don't find reference offering much more than raw pointers.
|
||||||
|
|
||||||
|
### RTTI and Exceptions
|
||||||
|
Totally useless for kernels.
|
@ -4,12 +4,12 @@ set(CC_SRC
|
|||||||
init.c
|
init.c
|
||||||
intr.c
|
intr.c
|
||||||
mem.c
|
mem.c
|
||||||
print.c)
|
print.c
|
||||||
|
brute.c)
|
||||||
|
|
||||||
set(AS_SRC
|
set(AS_SRC
|
||||||
boot.asm
|
boot.asm
|
||||||
mb_hdr.asm
|
mb_hdr.asm
|
||||||
atomic.asm
|
|
||||||
cpu.asm
|
cpu.asm
|
||||||
intr.asm)
|
intr.asm)
|
||||||
|
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
section .text
|
|
||||||
bits 64
|
|
||||||
|
|
||||||
; Performs compare and swap
|
|
||||||
; ARGS:
|
|
||||||
; 1 int32*: target ptr
|
|
||||||
; 2 int32: old value
|
|
||||||
; 3 int32: new value
|
|
||||||
; RETURNS uint32 value read
|
|
||||||
global arch_cmp_swp_32
|
|
||||||
arch_cmp_swp_32:
|
|
||||||
mov eax, esi
|
|
||||||
lock cmpxchg dword [rdi], edx
|
|
||||||
ret
|
|
||||||
|
|
||||||
; Performs fetch and add
|
|
||||||
; ARGS:
|
|
||||||
; 1 int32*: target ptr
|
|
||||||
; 2 int32: increment value
|
|
||||||
; 3 int32: new value
|
|
||||||
; RETURNS uint32 value read
|
|
||||||
global arch_fet_add_32:
|
|
||||||
arch_fet_add_32:
|
|
||||||
lock xadd dword [rdi], esi
|
|
||||||
xor rax, rax
|
|
||||||
mov eax, esi
|
|
||||||
ret
|
|
@ -82,7 +82,7 @@ arch_init_32:
|
|||||||
; switch to long mode
|
; switch to long mode
|
||||||
jmp init_gdt.code:GET_PADDR(arch_init_64)
|
jmp init_gdt.code:GET_PADDR(arch_init_64)
|
||||||
.end:
|
.end:
|
||||||
hlt
|
jmp $
|
||||||
|
|
||||||
check_long_mode:
|
check_long_mode:
|
||||||
push ebp
|
push ebp
|
||||||
@ -137,9 +137,11 @@ arch_init_64:
|
|||||||
mov gs,ax
|
mov gs,ax
|
||||||
mov ss,ax
|
mov ss,ax
|
||||||
|
|
||||||
|
; initial kernel stack, 4k
|
||||||
mov rsp, init_stack
|
mov rsp, init_stack
|
||||||
xor rdi, rdi
|
xor rdi, rdi
|
||||||
mov edi, dword [multiboot_info_ptr]
|
mov edi, dword [multiboot_info_ptr]
|
||||||
|
; init arch
|
||||||
call arch_main
|
call arch_main
|
||||||
.end:
|
.end:
|
||||||
hlt
|
hlt
|
||||||
|
6
arch/brute.c
Normal file
6
arch/brute.c
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include <arch/brute.h>
|
||||||
|
|
||||||
|
void arch_brute()
|
||||||
|
{
|
||||||
|
while(1) {}
|
||||||
|
}
|
18
arch/cpu.asm
18
arch/cpu.asm
@ -19,6 +19,22 @@ global arch_write_msr
|
|||||||
section .text
|
section .text
|
||||||
bits 64
|
bits 64
|
||||||
|
|
||||||
|
; uint64* arch_random_int64(void)
|
||||||
|
; Returns a random 64-bit integer
|
||||||
|
global arch_random_int64
|
||||||
|
arch_random_int64:
|
||||||
|
rdrand rax
|
||||||
|
ret
|
||||||
|
|
||||||
|
; uint32* arch_random_int32(void)
|
||||||
|
; Returns a random 32-bit integer
|
||||||
|
global arch_random_int32
|
||||||
|
arch_random_int32:
|
||||||
|
rdrand eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
arch_flush_gdt:
|
arch_flush_gdt:
|
||||||
push rbp
|
push rbp
|
||||||
mov rbp,rsp
|
mov rbp,rsp
|
||||||
@ -185,7 +201,6 @@ nop
|
|||||||
nop
|
nop
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
arch_read_port_8:
|
arch_read_port_8:
|
||||||
mov rdx,rdi
|
mov rdx,rdi
|
||||||
xor rax,rax
|
xor rax,rax
|
||||||
@ -204,7 +219,6 @@ nop
|
|||||||
nop
|
nop
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
arch_read_port_32:
|
arch_read_port_32:
|
||||||
mov rdx,rdi
|
mov rdx,rdi
|
||||||
xor rax,rax
|
xor rax,rax
|
||||||
|
31
arch/cpu.c
31
arch/cpu.c
@ -1,6 +1,7 @@
|
|||||||
#include <arch/cpu.h>
|
|
||||||
#include <kern/cdef.h>
|
#include <kern/cdef.h>
|
||||||
|
|
||||||
|
#include "cpu.h"
|
||||||
|
|
||||||
#define GDT_ENTRY_SIZE 8
|
#define GDT_ENTRY_SIZE 8
|
||||||
#define GDT_ENTRY_NUM 9
|
#define GDT_ENTRY_NUM 9
|
||||||
|
|
||||||
@ -21,7 +22,6 @@
|
|||||||
#define SEG_AVAILABLE (1ull << 52)
|
#define SEG_AVAILABLE (1ull << 52)
|
||||||
#define SEG_32_BITS (1ull << 54)
|
#define SEG_32_BITS (1ull << 54)
|
||||||
|
|
||||||
|
|
||||||
static uint8 _gdts[HAL_CORE_COUNT][GDT_ENTRY_NUM * GDT_ENTRY_SIZE];
|
static uint8 _gdts[HAL_CORE_COUNT][GDT_ENTRY_NUM * GDT_ENTRY_SIZE];
|
||||||
static struct hal_gdt_ptr _gdt_ptrs[HAL_CORE_COUNT];
|
static struct hal_gdt_ptr _gdt_ptrs[HAL_CORE_COUNT];
|
||||||
|
|
||||||
@ -34,8 +34,7 @@ static inline uint32 seg_selector(uint32 index, uint32 rpl)
|
|||||||
static void
|
static void
|
||||||
write_segment_descriptor(void *const gdt, uint32 const base, uint32 const limit, uint64 const attr)
|
write_segment_descriptor(void *const gdt, uint32 const base, uint32 const limit, uint64 const attr)
|
||||||
{
|
{
|
||||||
if (gdt == NULL)
|
if (gdt == NULL) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint64 const seg_desc = (((uint64) base & 0xFFFF) << 16) | ((((uint64) base >> 16) & 0xFF) << 32) |
|
uint64 const seg_desc = (((uint64) base & 0xFFFF) << 16) | ((((uint64) base >> 16) & 0xFF) << 32) |
|
||||||
@ -57,26 +56,26 @@ void hal_init_gdt(void)
|
|||||||
// get gdt ready
|
// get gdt ready
|
||||||
write_segment_descriptor((void *) &_gdts[coreid][0], 0, 0, 0);
|
write_segment_descriptor((void *) &_gdts[coreid][0], 0, 0, 0);
|
||||||
write_segment_descriptor((void *) &_gdts[coreid][8], 0, 0,
|
write_segment_descriptor((void *) &_gdts[coreid][8], 0, 0,
|
||||||
SEG_DPL_0 | SEG_CODE_DATA | SEG_PRESENT | SEG_LONG | SEG_TYPE_CODE_X);
|
SEG_DPL_0 | SEG_CODE_DATA | SEG_PRESENT | SEG_LONG | SEG_TYPE_CODE_X);
|
||||||
write_segment_descriptor((void *) &_gdts[coreid][16], 0, 0,
|
write_segment_descriptor((void *) &_gdts[coreid][16], 0, 0,
|
||||||
SEG_DPL_0 | SEG_CODE_DATA | SEG_PRESENT | SEG_LONG | SEG_TYPE_DATA_RW);
|
SEG_DPL_0 | SEG_CODE_DATA | SEG_PRESENT | SEG_LONG | SEG_TYPE_DATA_RW);
|
||||||
write_segment_descriptor((void *) &_gdts[coreid][24], 0, 0,
|
write_segment_descriptor((void *) &_gdts[coreid][24], 0, 0,
|
||||||
SEG_DPL_3 | SEG_CODE_DATA | SEG_PRESENT | SEG_LONG | SEG_TYPE_CODE_X);
|
SEG_DPL_3 | SEG_CODE_DATA | SEG_PRESENT | SEG_LONG | SEG_TYPE_CODE_X);
|
||||||
write_segment_descriptor((void *) &_gdts[coreid][32], 0, 0,
|
write_segment_descriptor((void *) &_gdts[coreid][32], 0, 0,
|
||||||
SEG_DPL_3 | SEG_CODE_DATA | SEG_PRESENT | SEG_LONG | SEG_TYPE_DATA_RW);
|
SEG_DPL_3 | SEG_CODE_DATA | SEG_PRESENT | SEG_LONG | SEG_TYPE_DATA_RW);
|
||||||
|
|
||||||
write_segment_descriptor((void *) &_gdts[coreid][40], 0, 0xFFFFF,
|
write_segment_descriptor((void *) &_gdts[coreid][40], 0, 0xFFFFF,
|
||||||
SEG_DPL_0 | SEG_GRANULARITY | SEG_CODE_DATA | SEG_PRESENT | SEG_32_BITS |
|
SEG_DPL_0 | SEG_GRANULARITY | SEG_CODE_DATA | SEG_PRESENT | SEG_32_BITS |
|
||||||
SEG_TYPE_CODE_X);
|
SEG_TYPE_CODE_X);
|
||||||
write_segment_descriptor((void *) &_gdts[coreid][48], 0, 0xFFFFF,
|
write_segment_descriptor((void *) &_gdts[coreid][48], 0, 0xFFFFF,
|
||||||
SEG_DPL_0 | SEG_GRANULARITY | SEG_CODE_DATA | SEG_PRESENT | SEG_32_BITS |
|
SEG_DPL_0 | SEG_GRANULARITY | SEG_CODE_DATA | SEG_PRESENT | SEG_32_BITS |
|
||||||
SEG_TYPE_DATA_RW);
|
SEG_TYPE_DATA_RW);
|
||||||
write_segment_descriptor((void *) &_gdts[coreid][56], 0, 0xFFFFF,
|
write_segment_descriptor((void *) &_gdts[coreid][56], 0, 0xFFFFF,
|
||||||
SEG_DPL_3 | SEG_GRANULARITY | SEG_CODE_DATA | SEG_PRESENT | SEG_32_BITS |
|
SEG_DPL_3 | SEG_GRANULARITY | SEG_CODE_DATA | SEG_PRESENT | SEG_32_BITS |
|
||||||
SEG_TYPE_CODE_X);
|
SEG_TYPE_CODE_X);
|
||||||
write_segment_descriptor((void *) &_gdts[coreid][64], 0, 0xFFFFF,
|
write_segment_descriptor((void *) &_gdts[coreid][64], 0, 0xFFFFF,
|
||||||
SEG_DPL_3 | SEG_GRANULARITY | SEG_CODE_DATA | SEG_PRESENT | SEG_32_BITS |
|
SEG_DPL_3 | SEG_GRANULARITY | SEG_CODE_DATA | SEG_PRESENT | SEG_32_BITS |
|
||||||
SEG_TYPE_DATA_RW);
|
SEG_TYPE_DATA_RW);
|
||||||
_gdt_ptrs[coreid].base = (uint64) &_gdts[coreid];
|
_gdt_ptrs[coreid].base = (uint64) &_gdts[coreid];
|
||||||
_gdt_ptrs[coreid].limit = GDT_ENTRY_NUM * GDT_ENTRY_SIZE - 1;
|
_gdt_ptrs[coreid].limit = GDT_ENTRY_NUM * GDT_ENTRY_SIZE - 1;
|
||||||
arch_flush_gdt(&_gdt_ptrs[coreid], seg_selector(1, 0), seg_selector(2, 0));
|
arch_flush_gdt(&_gdt_ptrs[coreid], seg_selector(1, 0), seg_selector(2, 0));
|
||||||
|
53
arch/cpu.h
53
arch/cpu.h
@ -2,6 +2,17 @@
|
|||||||
|
|
||||||
#include <kern/cdef.h>
|
#include <kern/cdef.h>
|
||||||
|
|
||||||
|
#define HAL_CORE_COUNT 1
|
||||||
|
struct ATTR_PACKED hal_gdt_ptr {
|
||||||
|
uint16 limit;
|
||||||
|
uint64 base;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ATTR_PACKED hal_idt_ptr {
|
||||||
|
uint16 limit;
|
||||||
|
uint64 base;
|
||||||
|
};
|
||||||
|
|
||||||
void KABI out_8(uint16 port, uint8 data);
|
void KABI out_8(uint16 port, uint8 data);
|
||||||
|
|
||||||
void KABI out_16(uint16 port, uint16 data);
|
void KABI out_16(uint16 port, uint16 data);
|
||||||
@ -38,4 +49,44 @@ uint64 KABI read_cr3();
|
|||||||
|
|
||||||
void KABI write_cr3(uint64 val);
|
void KABI write_cr3(uint64 val);
|
||||||
|
|
||||||
void KABI flush_tlb();
|
void KABI flush_tlb();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASM declaration
|
||||||
|
*/
|
||||||
|
void KABI arch_cpuid(uint32 *eax, uint32 *ebx, uint32 *ecx, uint32 *edx);
|
||||||
|
|
||||||
|
void KABI arch_halt(void);
|
||||||
|
|
||||||
|
void KABI arch_flush_gdt(struct hal_gdt_ptr *gdt_ptr, uint64 code_slct, uint64 data_slct);
|
||||||
|
|
||||||
|
void KABI arch_flush_tlb(void);
|
||||||
|
|
||||||
|
void KABI arch_flush_idt(struct hal_idt_ptr *idt_ptr);
|
||||||
|
|
||||||
|
void KABI arch_read_idt(struct hal_idt_ptr **idt_ptr);
|
||||||
|
|
||||||
|
void KABI arch_read_msr(uint32 *ecx, uint32 *edx, uint32 *eax);
|
||||||
|
|
||||||
|
void KABI arch_write_msr(uint32 *ecx, uint32 *edx, uint32 *eax);
|
||||||
|
|
||||||
|
void KABI arch_write_cr3(uint64 base);
|
||||||
|
|
||||||
|
uint64 KABI arch_read_cr3(void);
|
||||||
|
|
||||||
|
void KABI arch_write_cr8(uint64 pri);
|
||||||
|
|
||||||
|
uint64 KABI arch_read_cr8(void);
|
||||||
|
|
||||||
|
int8 KABI arch_read_port_8(uint16 port);
|
||||||
|
|
||||||
|
int16 KABI arch_read_port_16(uint16 port);
|
||||||
|
|
||||||
|
int32 KABI arch_read_port_32(uint16 port);
|
||||||
|
|
||||||
|
void KABI arch_write_port_8(uint16 port, uint8 data);
|
||||||
|
|
||||||
|
void KABI arch_write_port_16(uint16 port, uint16 data);
|
||||||
|
|
||||||
|
void KABI arch_write_port_32(uint16 port, uint32 data);
|
||||||
|
17
arch/init.c
17
arch/init.c
@ -1,20 +1,21 @@
|
|||||||
#include <kern/cdef.h>
|
#include <kern/cdef.h>
|
||||||
|
#include <kern/print.h>
|
||||||
#include <arch/print.h>
|
#include <arch/print.h>
|
||||||
|
#include <arch/brute.h>
|
||||||
|
|
||||||
// private headers
|
// private headers
|
||||||
#include "multiboot2.h"
|
#include "multiboot2.h"
|
||||||
/**
|
|
||||||
* What the heck was that?
|
void arch_main(ATTR_UNUSED void* mb_info)
|
||||||
* @param mb_info
|
|
||||||
*/
|
|
||||||
void arch_main(void* mb_info)
|
|
||||||
{
|
{
|
||||||
UNREFERENCED(mb_info);
|
/* init printf related stuff */
|
||||||
arch_print_init();
|
arch_print_init();
|
||||||
|
|
||||||
arch_printf("In arch stuff...\n");
|
kprintf("Initializing arch layer...\n");
|
||||||
|
|
||||||
|
arch_brute();
|
||||||
|
|
||||||
/* if (mb_info == NULL)
|
/* if (mb_info == NULL)
|
||||||
{
|
{
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
76
arch/intr.c
76
arch/intr.c
@ -1,48 +1,52 @@
|
|||||||
#include <arch/cpu.h>
|
|
||||||
#include <arch/intr.h>
|
#include <arch/intr.h>
|
||||||
#include <arch/mem.h>
|
#include <arch/mem.h>
|
||||||
#include <arch/print.h>
|
#include <arch/print.h>
|
||||||
|
#include <kern/print.h>
|
||||||
|
#include <kern/status.h>
|
||||||
|
#include <kern/brute.h>
|
||||||
|
|
||||||
|
#include "cpu.h"
|
||||||
|
|
||||||
|
#define HAL_CORE_COUNT 1
|
||||||
|
|
||||||
static uint8 cpu_idts[HAL_CORE_COUNT][IDT_ENTRY_NUM * IDT_ENTRY_SIZE];
|
static uint8 cpu_idts[HAL_CORE_COUNT][IDT_ENTRY_NUM * IDT_ENTRY_SIZE];
|
||||||
static struct hal_idt_ptr cpu_idt_ptrs[HAL_CORE_COUNT];
|
static struct hal_idt_ptr cpu_idt_ptrs[HAL_CORE_COUNT];
|
||||||
|
|
||||||
static void* k_intr_disps[HAL_CORE_COUNT];
|
static void *k_intr_disps[HAL_CORE_COUNT];
|
||||||
|
|
||||||
uint32
|
int
|
||||||
arch_raise_irql(uint32 irql)
|
arch_raise_irql(ATTR_UNUSED int irql)
|
||||||
{
|
{
|
||||||
UNREFERENCED(irql);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32
|
int
|
||||||
arch_lower_irql(uint32 irql)
|
arch_lower_irql(ATTR_UNUSED int irql)
|
||||||
{
|
{
|
||||||
UNREFERENCED(irql);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32
|
int
|
||||||
arch_get_irql(void)
|
arch_get_irql()
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
hal_write_gate(void *const gate, uint64 const offset, uint32 const selector, uint32 const attr)
|
hal_write_gate(void *gate, const uint64 offset, const uint32 selector, uint32 const attr)
|
||||||
{
|
{
|
||||||
((uint8 *) gate)[0] = (uint8) (offset & 0xFF);
|
((uint8 *) gate)[0] = (uint8) (offset & 0xFFu);
|
||||||
((uint8 *) gate)[1] = (uint8) ((offset >> 8) & 0xFF);
|
((uint8 *) gate)[1] = (uint8) ((offset >> 8u) & 0xFFu);
|
||||||
((uint8 *) gate)[2] = (uint8) (selector & 0xFF);
|
((uint8 *) gate)[2] = (uint8) (selector & 0xFFu);
|
||||||
((uint8 *) gate)[3] = (uint8) ((selector >> 8) & 0xFF);
|
((uint8 *) gate)[3] = (uint8) ((selector >> 8u) & 0xFFu);
|
||||||
((uint8 *) gate)[4] = (uint8) (attr & 0xFF);
|
((uint8 *) gate)[4] = (uint8) (attr & 0xFFu);
|
||||||
((uint8 *) gate)[5] = (uint8) ((attr >> 8) & 0xFF);
|
((uint8 *) gate)[5] = (uint8) ((attr >> 8u) & 0xFFu);
|
||||||
((uint8 *) gate)[6] = (uint8) ((offset >> 16) & 0xFF);
|
((uint8 *) gate)[6] = (uint8) ((offset >> 16u) & 0xFFu);
|
||||||
((uint8 *) gate)[7] = (uint8) ((offset >> 24) & 0xFF);
|
((uint8 *) gate)[7] = (uint8) ((offset >> 24u) & 0xFFu);
|
||||||
((uint8 *) gate)[8] = (uint8) ((offset >> 32) & 0xFF);
|
((uint8 *) gate)[8] = (uint8) ((offset >> 32u) & 0xFFu);
|
||||||
((uint8 *) gate)[9] = (uint8) ((offset >> 40) & 0xFF);
|
((uint8 *) gate)[9] = (uint8) ((offset >> 40u) & 0xFFu);
|
||||||
((uint8 *) gate)[10] = (uint8) ((offset >> 48) & 0xFF);
|
((uint8 *) gate)[10] = (uint8) ((offset >> 48u) & 0xFFu);
|
||||||
((uint8 *) gate)[11] = (uint8) ((offset >> 56) & 0xFF);
|
((uint8 *) gate)[11] = (uint8) ((offset >> 56u) & 0xFFu);
|
||||||
((uint8 *) gate)[12] = 0;
|
((uint8 *) gate)[12] = 0;
|
||||||
((uint8 *) gate)[13] = 0;
|
((uint8 *) gate)[13] = 0;
|
||||||
((uint8 *) gate)[14] = 0;
|
((uint8 *) gate)[14] = 0;
|
||||||
@ -53,9 +57,8 @@ void KABI
|
|||||||
hal_interrupt_dispatcher(uint64 int_vec, struct interrupt_context *context)
|
hal_interrupt_dispatcher(uint64 int_vec, struct interrupt_context *context)
|
||||||
{
|
{
|
||||||
uint32 coreid = 0;
|
uint32 coreid = 0;
|
||||||
if (k_intr_disps[coreid] == NULL)
|
if (k_intr_disps[coreid] == NULL) {
|
||||||
{
|
kprintf("Unhandled interrupt %ld at 0x%lx.\n", int_vec, context->rip);
|
||||||
arch_printf("Unhandled interrupt %d at 0x%X.\n", int_vec, context->rip);
|
|
||||||
}
|
}
|
||||||
/*else
|
/*else
|
||||||
{
|
{
|
||||||
@ -66,10 +69,10 @@ hal_interrupt_dispatcher(uint64 int_vec, struct interrupt_context *context)
|
|||||||
static void
|
static void
|
||||||
populate_idt(void)
|
populate_idt(void)
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kstatus
|
void
|
||||||
arch_intr_init(void)
|
arch_intr_init(void)
|
||||||
{
|
{
|
||||||
uint32 coreid;
|
uint32 coreid;
|
||||||
@ -81,10 +84,8 @@ arch_intr_init(void)
|
|||||||
// detect APIC first
|
// detect APIC first
|
||||||
eax = 1;
|
eax = 1;
|
||||||
arch_cpuid(&eax, &ebx, &ecx, &edx);
|
arch_cpuid(&eax, &ebx, &ecx, &edx);
|
||||||
if (!(edx & (1 << 9)))
|
if (!(edx & (1u << 9u))) {
|
||||||
{
|
BRUTE("ERROR: APIC is not present.\n");
|
||||||
arch_printf("ERROR: APIC is not present.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
coreid = 0;
|
coreid = 0;
|
||||||
@ -106,18 +107,15 @@ arch_intr_init(void)
|
|||||||
arch_write_port_8(0x21, 0xff);
|
arch_write_port_8(0x21, 0xff);
|
||||||
|
|
||||||
uint64 apic_base_reg = 0;
|
uint64 apic_base_reg = 0;
|
||||||
uint64 apic_base = 0;
|
ATTR_UNUSED uint64 apic_base = 0;
|
||||||
ecx = 0;
|
ecx = 0;
|
||||||
arch_read_msr(&ecx, &edx, &eax);
|
arch_read_msr(&ecx, &edx, &eax);
|
||||||
apic_base_reg = ((uint64) edx << 32) + (uint64) eax;
|
apic_base_reg = ((uint64) edx << 32u) + (uint64) eax;
|
||||||
apic_base = apic_base_reg & bit_field_mask(12, 35);
|
//apic_base = apic_base_reg & bit_field_mask(12, 35);
|
||||||
UNREFERENCED(apic_base);
|
|
||||||
|
|
||||||
|
|
||||||
// hardware enable APIC
|
// hardware enable APIC
|
||||||
ecx = 0;
|
ecx = 0;
|
||||||
eax = (uint32) ((apic_base_reg & bit_field_mask(0, 31)) | bit_mask(11));
|
// eax = (uint32) ((apic_base_reg & bit_field_mask(0, 31)) | (1 << 11));
|
||||||
arch_write_msr(&ecx, &edx, &eax);
|
arch_write_msr(&ecx, &edx, &eax);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
28
arch/mem.c
28
arch/mem.c
@ -1,7 +1,4 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <kern/cdef.h>
|
#include <kern/cdef.h>
|
||||||
#include <arch/cpu.h>
|
|
||||||
#include <arch/mem.h>
|
#include <arch/mem.h>
|
||||||
#include <arch/mlayout.h>
|
#include <arch/mlayout.h>
|
||||||
|
|
||||||
@ -56,21 +53,14 @@ write_page_tbl(void *base, uintptr pdpt_addr, uint64 attr)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint64 entry = (pdpt_addr & 0xFFFFFFFFFF000) | attr;
|
uint64 entry = (pdpt_addr & 0xFFFFFFFFFF000ul) | attr;
|
||||||
((uint8 *) base)[0] = (uint8) (entry & 0xFF);
|
((uint8 *) base)[0] = (uint8) (entry & 0xFFul);
|
||||||
((uint8 *) base)[1] = (uint8) ((entry >> 8) & 0xFF);
|
((uint8 *) base)[1] = (uint8) ((entry >> 8u) & 0xFFu);
|
||||||
((uint8 *) base)[2] = (uint8) ((entry >> 16) & 0xFF);
|
((uint8 *) base)[2] = (uint8) ((entry >> 16u) & 0xFFu);
|
||||||
((uint8 *) base)[3] = (uint8) ((entry >> 24) & 0xFF);
|
((uint8 *) base)[3] = (uint8) ((entry >> 24u) & 0xFFu);
|
||||||
((uint8 *) base)[4] = (uint8) ((entry >> 32) & 0xFF);
|
((uint8 *) base)[4] = (uint8) ((entry >> 32u) & 0xFFu);
|
||||||
((uint8 *) base)[5] = (uint8) ((entry >> 40) & 0xFF);
|
((uint8 *) base)[5] = (uint8) ((entry >> 40u) & 0xFFu);
|
||||||
((uint8 *) base)[6] = (uint8) ((entry >> 48) & 0xFF);
|
((uint8 *) base)[6] = (uint8) ((entry >> 48u) & 0xFFu);
|
||||||
((uint8 *) base)[7] = (uint8) ((entry >> 56) & 0xFF);
|
((uint8 *) base)[7] = (uint8) ((entry >> 56u) & 0xFFu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void*
|
|
||||||
arch_pmap_map(uintptr paddr, usize size)
|
|
||||||
{
|
|
||||||
UNREFERENCED(size);
|
|
||||||
return (void*)(paddr + KERNEL_PMAP_VADDR);
|
|
||||||
}
|
|
||||||
|
232
arch/print.c
232
arch/print.c
@ -1,218 +1,60 @@
|
|||||||
#include <kern/cdef.h>
|
#include <kern/cdef.h>
|
||||||
#include <arch/cpu.h>
|
|
||||||
#include <arch/mem.h>
|
#include <arch/mem.h>
|
||||||
#include <arch/print.h>
|
#include <kern/libkern.h>
|
||||||
#include <kern/clib.h>
|
|
||||||
#include <kern/spin_lock.h>
|
|
||||||
|
|
||||||
#define CALC_ROW(pos) ((pos) / 80)
|
|
||||||
#define CALC_POS(row, col) ((row) * 80 + (col))
|
|
||||||
#define FB_PADDR (0xb8000)
|
#define FB_PADDR (0xb8000)
|
||||||
|
#define FB_ROW (25)
|
||||||
|
#define FB_COL (80)
|
||||||
|
#define BYTE_PER_CHAR (2)
|
||||||
|
#define FB_SZ (FB_ROW * FB_COL * BYTE_PER_CHAR)
|
||||||
|
#define DEFAULT_COLOR (0x07)
|
||||||
|
|
||||||
static void *base;
|
static char *base;
|
||||||
static uint64 text_pos;
|
static uint text_pos;
|
||||||
static struct spin_lock print_lock;
|
|
||||||
|
static void
|
||||||
|
_fb_scroll()
|
||||||
|
{
|
||||||
|
memmove(base, base + FB_COL * BYTE_PER_CHAR, FB_SZ - (FB_COL * BYTE_PER_CHAR));
|
||||||
|
text_pos = FB_SZ - (FB_COL * BYTE_PER_CHAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_print_newline(void)
|
||||||
|
{
|
||||||
|
text_pos += FB_COL * BYTE_PER_CHAR - text_pos % (FB_COL * BYTE_PER_CHAR);
|
||||||
|
|
||||||
|
if (text_pos >= FB_SZ) {
|
||||||
|
_fb_scroll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
arch_print_init(void)
|
arch_print_init(void)
|
||||||
{
|
{
|
||||||
// 0 here since it doesn't matter direct mapped
|
// 0 here since it doesn't matter direct mapped
|
||||||
base = arch_pmap_map(FB_PADDR, 0);
|
base = arch_pmap_map(FB_PADDR, FB_SZ);
|
||||||
text_pos = 0;
|
text_pos = 0;
|
||||||
spin_init(&print_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
handle_scroll(void)
|
arch_cls()
|
||||||
{
|
{
|
||||||
mem_mv((void *) ((uintptr) base + CALC_POS(1, 0) * 2), (void *) ((uintptr) base + CALC_POS(0, 0) * 2),
|
memset(base, 0, FB_SZ);
|
||||||
(80 * 24) * 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
print_str(char const *str)
|
arch_putc(const char c)
|
||||||
{
|
{
|
||||||
if (str == NULL)
|
if (c == '\n') {
|
||||||
{
|
_print_newline();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (*str != 0)
|
|
||||||
{
|
|
||||||
if (*str == '\n')
|
|
||||||
{
|
|
||||||
text_pos = 80 * (CALC_ROW(text_pos) + 1);
|
|
||||||
if (text_pos > 80 * 25 - 1)
|
|
||||||
{
|
|
||||||
//can't hold
|
|
||||||
handle_scroll();
|
|
||||||
mem_set((void *) ((uintptr) base + 80 * 24 * 2), 0, 80 * 2); // clear last row
|
|
||||||
text_pos = 80 * 24;
|
|
||||||
}
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (text_pos > 80 * 25 - 1)
|
|
||||||
{
|
|
||||||
//can't hold
|
|
||||||
handle_scroll();
|
|
||||||
text_pos = 80 * 24;
|
|
||||||
}
|
|
||||||
*((char *) base + text_pos * 2) = *str;
|
|
||||||
*((char *) base + text_pos * 2 + 1) = 7;
|
|
||||||
str++;
|
|
||||||
text_pos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
if (text_pos >= FB_SZ) {
|
||||||
print_uint(uint64 number)
|
_fb_scroll();
|
||||||
{
|
|
||||||
char arr[21]; // do not need to initialize
|
|
||||||
arr[20] = 0; //zero-terminated
|
|
||||||
uint32 index = 19;
|
|
||||||
uint32 const div = 10;
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
uint64 quo = number / div;
|
|
||||||
uint64 rmd = number % div;
|
|
||||||
number = quo;
|
|
||||||
arr[index--] = (char) ('0' + rmd);
|
|
||||||
if (number == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
print_str(&(arr[index + 1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
base[text_pos++] = c;
|
||||||
print_int(int64 number)
|
base[text_pos++] = DEFAULT_COLOR;
|
||||||
{
|
|
||||||
char arr[21]; // do not need to initialize
|
|
||||||
arr[20] = 0; //zero-terminated
|
|
||||||
uint32 index = 19;
|
|
||||||
uint32 isNegative = 0;
|
|
||||||
uint32 const div = 10;
|
|
||||||
if (number < 0)
|
|
||||||
{
|
|
||||||
isNegative = 1;
|
|
||||||
number *= -1;
|
|
||||||
}
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
int64 quo = number / div;
|
|
||||||
int64 rmd = number % div;
|
|
||||||
number = quo;
|
|
||||||
arr[index--] = (char) ('0' + rmd);
|
|
||||||
if (number == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isNegative)
|
|
||||||
{
|
|
||||||
arr[index--] = '-';
|
|
||||||
}
|
|
||||||
print_str(&(arr[index + 1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
print_hex(uint64 number, uint64 capital)
|
|
||||||
{
|
|
||||||
char const lookup_table_cap[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
|
||||||
char const lookup_table[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
|
||||||
char const *const look_up = capital == 1 ? &lookup_table_cap[0] : &lookup_table[0];
|
|
||||||
char arr[17];
|
|
||||||
arr[16] = 0; //zero-terminated
|
|
||||||
uint32 index = 15;
|
|
||||||
uint32 const div = 16;
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
uint64 quo = number / div;
|
|
||||||
uint64 rmd = number % div;
|
|
||||||
number = quo;
|
|
||||||
arr[index--] = look_up[rmd];
|
|
||||||
if (number == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
print_str(&(arr[index + 1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
arch_cls(void)
|
|
||||||
{
|
|
||||||
text_pos = 0; // reset text_pos
|
|
||||||
mem_set(base, 0, 25 * 80 * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
arch_vprintf(char const *format, va_list args)
|
|
||||||
{
|
|
||||||
char buf[2];
|
|
||||||
int64 d;
|
|
||||||
uint64 u;
|
|
||||||
char *s;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
buf[1] = '\0';
|
|
||||||
for (; *format != '\0'; format++)
|
|
||||||
{
|
|
||||||
if (*format != '%')
|
|
||||||
{
|
|
||||||
buf[0] = *format;
|
|
||||||
print_str(buf);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
format++;
|
|
||||||
switch (*format)
|
|
||||||
{
|
|
||||||
case 'd':
|
|
||||||
d = va_arg(args, int64);
|
|
||||||
print_int(d);
|
|
||||||
break;
|
|
||||||
case 'u':
|
|
||||||
u = va_arg(args, uint64);
|
|
||||||
print_uint(u);
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
s = va_arg(args, char *);
|
|
||||||
print_str(s);
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
c = (char) va_arg(args, int64);
|
|
||||||
buf[0] = c;
|
|
||||||
print_str(buf);
|
|
||||||
break;
|
|
||||||
case 'x':
|
|
||||||
u = va_arg(args, uint64);
|
|
||||||
print_hex(u, 0);
|
|
||||||
break;
|
|
||||||
case 'X':
|
|
||||||
u = va_arg(args, uint64);
|
|
||||||
print_hex(u, 1);
|
|
||||||
break;
|
|
||||||
case '%':
|
|
||||||
buf[0] = '%';
|
|
||||||
print_str(buf);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
buf[0] = '%';
|
|
||||||
print_str(buf);
|
|
||||||
format--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
arch_printf(char const *format, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, format);
|
|
||||||
arch_vprintf(format, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <kern/cdef.h>
|
|
||||||
|
|
||||||
int32 KABI arch_cmp_swp_32(int32* dst, int32 old, int32 val);
|
|
||||||
|
|
||||||
int32 KABI arch_fet_add_32(int32* dst, int32 val);
|
|
||||||
|
|
3
inc/arch/brute.h
Normal file
3
inc/arch/brute.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void arch_brute();
|
@ -1,57 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <kern/cdef.h>
|
|
||||||
|
|
||||||
#define HAL_CORE_COUNT 1
|
|
||||||
|
|
||||||
struct PRAGMA_PACKED hal_gdt_ptr
|
|
||||||
{
|
|
||||||
uint16 limit;
|
|
||||||
uint64 base;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PRAGMA_PACKED hal_idt_ptr
|
|
||||||
{
|
|
||||||
uint16 limit;
|
|
||||||
uint64 base;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ASM declaration
|
|
||||||
*/
|
|
||||||
void KABI arch_cpuid(uint32 *eax, uint32 *ebx, uint32 *ecx, uint32 *edx);
|
|
||||||
|
|
||||||
void KABI arch_halt(void);
|
|
||||||
|
|
||||||
void KABI arch_flush_gdt(struct hal_gdt_ptr *gdt_ptr, uint64 code_slct, uint64 data_slct);
|
|
||||||
|
|
||||||
void KABI arch_flush_tlb(void);
|
|
||||||
|
|
||||||
void KABI arch_flush_idt(struct hal_idt_ptr *idt_ptr);
|
|
||||||
|
|
||||||
void KABI arch_read_idt(struct hal_idt_ptr **idt_ptr);
|
|
||||||
|
|
||||||
void KABI arch_read_msr(uint32 *ecx, uint32 *edx, uint32 *eax);
|
|
||||||
|
|
||||||
void KABI arch_write_msr(uint32 *ecx, uint32 *edx, uint32 *eax);
|
|
||||||
|
|
||||||
void KABI arch_write_cr3(uint64 base);
|
|
||||||
|
|
||||||
uint64 KABI arch_read_cr3(void);
|
|
||||||
|
|
||||||
void KABI arch_write_cr8(uint64 pri);
|
|
||||||
|
|
||||||
uint64 KABI arch_read_cr8(void);
|
|
||||||
|
|
||||||
int8 KABI arch_read_port_8(uint16 port);
|
|
||||||
|
|
||||||
int16 KABI arch_read_port_16(uint16 port);
|
|
||||||
|
|
||||||
int32 KABI arch_read_port_32(uint16 port);
|
|
||||||
|
|
||||||
void KABI arch_write_port_8(uint16 port, uint8 data);
|
|
||||||
|
|
||||||
void KABI arch_write_port_16(uint16 port, uint16 data);
|
|
||||||
|
|
||||||
void KABI arch_write_port_32(uint16 port, uint32 data);
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <arch/intr.h>
|
#include <arch/intr.h>
|
||||||
#include <kern/clib.h>
|
|
||||||
#include <kern/status.h>
|
#include <kern/status.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,7 +35,7 @@ struct interrupt_context
|
|||||||
/**
|
/**
|
||||||
* C declaration
|
* C declaration
|
||||||
*/
|
*/
|
||||||
kstatus
|
void
|
||||||
arch_intr_init(void);
|
arch_intr_init(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,11 +50,11 @@ arch_exc_disp(uint64 exc_vec, struct interrupt_context *context, uint32 errorcod
|
|||||||
/**
|
/**
|
||||||
* ASM declaration
|
* ASM declaration
|
||||||
*/
|
*/
|
||||||
uint32
|
int
|
||||||
arch_raise_irql(uint32 irql);
|
arch_raise_irql(int irql);
|
||||||
|
|
||||||
uint32
|
int
|
||||||
arch_lower_irql(uint32 irql);
|
arch_lower_irql(int irql);
|
||||||
|
|
||||||
uint32
|
int
|
||||||
arch_get_irql(void);
|
arch_get_irql();
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <kern/cdef.h>
|
#include <kern/cdef.h>
|
||||||
|
#include <arch/mlayout.h>
|
||||||
|
|
||||||
void *
|
static inline void *
|
||||||
arch_pmap_map(uintptr paddr, usize size);
|
arch_pmap_map(uintptr paddr, ATTR_UNUSED usize size)
|
||||||
|
{
|
||||||
|
return (void*)(paddr + KERNEL_PMAP_VADDR);
|
||||||
|
}
|
||||||
|
@ -3,13 +3,10 @@
|
|||||||
#include <arch/print.h>
|
#include <arch/print.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
arch_printf(const char *format, ...);
|
arch_cls();
|
||||||
|
|
||||||
void
|
void
|
||||||
arch_cls(void);
|
arch_print_init();
|
||||||
|
|
||||||
void
|
void
|
||||||
arch_print_init(void);
|
arch_putc(char c);
|
||||||
|
|
||||||
void
|
|
||||||
arch_vprintf(char const *format, va_list args);
|
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <kern/cdef.h>
|
|
||||||
|
|
||||||
#define KASSERT(expr) kassert_ex(#expr, __FILE__, __LINE__, expr)
|
|
||||||
|
|
||||||
void
|
|
||||||
kassert_ex(const char *expr_str, const char *file, int32 line, int32 expr);
|
|
@ -1,83 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <kern/cdef.h>
|
|
||||||
|
|
||||||
struct atree_node
|
|
||||||
{
|
|
||||||
struct atree_node *left;
|
|
||||||
struct atree_node *right;
|
|
||||||
int32 height;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A comparison function between self (yours) and treenode (tree's)
|
|
||||||
* Returns:
|
|
||||||
* < 0 if treenode < self
|
|
||||||
* = 0 if treenode = self
|
|
||||||
* > 0 if treenode > self
|
|
||||||
*/
|
|
||||||
typedef int32 (*atree_cmp_fn)(struct atree_node *tree_node, struct atree_node *self);
|
|
||||||
|
|
||||||
struct atree
|
|
||||||
{
|
|
||||||
atree_cmp_fn cmpf;
|
|
||||||
struct atree_node *root;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* init operations
|
|
||||||
*/
|
|
||||||
|
|
||||||
void
|
|
||||||
atree_init(struct atree *tree, atree_cmp_fn compare);
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
atree_empty(struct atree *tree)
|
|
||||||
{
|
|
||||||
return (tree->root == NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* tree operations
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct atree_node *
|
|
||||||
atree_search(struct atree *tree, struct atree_node *entry);
|
|
||||||
|
|
||||||
|
|
||||||
struct atree_node *
|
|
||||||
atree_insert(struct atree *tree, struct atree_node *entry);
|
|
||||||
|
|
||||||
|
|
||||||
struct atree_node *
|
|
||||||
atree_remove(struct atree *tree, struct atree_node *entry);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* traversal operations
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct atree_node *
|
|
||||||
atree_max(struct atree *tree);
|
|
||||||
|
|
||||||
struct atree_node *
|
|
||||||
atree_min(struct atree *tree);
|
|
||||||
|
|
||||||
struct atree_node *
|
|
||||||
atree_next(struct atree *tree, struct atree_node *entry);
|
|
||||||
|
|
||||||
struct atree_node *
|
|
||||||
atree_prev(struct atree *tree, struct atree_node *entry);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* internal operations (testing only)
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool
|
|
||||||
atree_validate(struct atree *tree);
|
|
||||||
|
|
||||||
uint32
|
|
||||||
atree_size(struct atree *tree);
|
|
86
inc/kern/avl_tree.h
Normal file
86
inc/kern/avl_tree.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kern/cdef.h>
|
||||||
|
|
||||||
|
struct avl_node
|
||||||
|
{
|
||||||
|
struct avl_node *left;
|
||||||
|
struct avl_node *right;
|
||||||
|
int height;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A comparison function between self (yours) and other
|
||||||
|
* Returns:
|
||||||
|
* < 0 if other < self
|
||||||
|
* = 0 if other = self
|
||||||
|
* > 0 if other > self
|
||||||
|
*/
|
||||||
|
typedef int (*avl_cmpf)(struct avl_node *tree_node, struct avl_node *self);
|
||||||
|
|
||||||
|
struct avl_root
|
||||||
|
{
|
||||||
|
avl_cmpf cmpf;
|
||||||
|
struct avl_node *root;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* init operations
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
avl_init(struct avl_root *root, avl_cmpf cmpf)
|
||||||
|
{
|
||||||
|
root->root = NULL;
|
||||||
|
root->cmpf = cmpf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
avl_empty(struct avl_root *root)
|
||||||
|
{
|
||||||
|
return (root->root == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tree operations
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct avl_node *
|
||||||
|
avl_search(struct avl_root *root, struct avl_node *node);
|
||||||
|
|
||||||
|
|
||||||
|
struct avl_node *
|
||||||
|
avl_insert(struct avl_root *root, struct avl_node *node);
|
||||||
|
|
||||||
|
|
||||||
|
struct avl_node *
|
||||||
|
avl_remove(struct avl_root *root, struct avl_node *node);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* traversal operations
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct avl_node *
|
||||||
|
avl_first(struct avl_root *root);
|
||||||
|
|
||||||
|
struct avl_node *
|
||||||
|
avl_last(struct avl_root *root);
|
||||||
|
|
||||||
|
struct avl_node *
|
||||||
|
avl_next(struct avl_root *root, struct avl_node *node);
|
||||||
|
|
||||||
|
struct avl_node *
|
||||||
|
avl_prev(struct avl_root *root, struct avl_node *node);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* internal operations (testing only)
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
avl_validate(struct avl_root *root);
|
||||||
|
|
||||||
|
usize
|
||||||
|
avl_size(struct avl_root *root);
|
@ -1,5 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <kern/cdef.h>
|
|
||||||
|
#define BITSET_DEFINE(sz)
|
||||||
|
|
||||||
|
static inline uint64
|
||||||
|
bit_mask(uint32 bit)
|
||||||
|
{
|
||||||
|
return (uint64) 1 << bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64
|
||||||
|
bit_field_mask(uint32 low, uint32 high)
|
||||||
|
{
|
||||||
|
return ~(~(uint64) 0 << high << 1) << low;
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint8* bit_byte(void* base, uint32 bit)
|
static inline uint8* bit_byte(void* base, uint32 bit)
|
||||||
{
|
{
|
16
inc/kern/brute.h
Normal file
16
inc/kern/brute.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kern/cdef.h>
|
||||||
|
#include <kern/print.h>
|
||||||
|
#include <arch/brute.h>
|
||||||
|
|
||||||
|
#define BRUTE(fmt, ...) do { \
|
||||||
|
kprintf("Kernel brute: " fmt "\n", ##__VA_ARGS__); \
|
||||||
|
arch_brute(); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define KASSERT(expr, msg, ...) do { \
|
||||||
|
if (!(expr)) { \
|
||||||
|
BRUTE("Assertion \"" #expr "\" failed at %s:%d: " msg , __FILE__, __LINE__ , ##__VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
@ -3,7 +3,10 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdatomic.h>
|
||||||
|
|
||||||
|
typedef uintmax_t uintmax;
|
||||||
|
typedef intmax_t intmax;
|
||||||
typedef uint32_t uint32;
|
typedef uint32_t uint32;
|
||||||
typedef int32_t int32;
|
typedef int32_t int32;
|
||||||
typedef uint64_t uint64;
|
typedef uint64_t uint64;
|
||||||
@ -14,25 +17,21 @@ typedef int16_t int16;
|
|||||||
typedef uint8_t uint8;
|
typedef uint8_t uint8;
|
||||||
typedef int8_t int8;
|
typedef int8_t int8;
|
||||||
typedef size_t usize;
|
typedef size_t usize;
|
||||||
|
typedef unsigned char uchar;
|
||||||
typedef _Bool bool;
|
typedef unsigned long ulong;
|
||||||
#define TRUE (1)
|
typedef unsigned int uint;
|
||||||
#define FALSE (0)
|
|
||||||
|
|
||||||
#define PRAGMA_PACKED __attribute__((packed))
|
|
||||||
|
|
||||||
#define PRAGMA_SECTION(x) __attribute__ ((section (x)))
|
|
||||||
|
|
||||||
#define PRAGMA_ALIGN(x) __attribute__ ((aligned(x)))
|
|
||||||
|
|
||||||
#define ALIGN_2(type, num, align) (((type)(num) + ((type)align - 1)) & ~((type)align - 1))
|
|
||||||
|
|
||||||
#define ALIGN(type, num, align) (((type)(num) + (type)(align) - 1) / (type)(align))
|
|
||||||
|
|
||||||
#define UNREFERENCED(x) do { \
|
|
||||||
(x) = (x); \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define KABI __attribute__((sysv_abi))
|
#define KABI __attribute__((sysv_abi))
|
||||||
|
|
||||||
|
#define STATIC_ASSERT(cond, msg) _Static_assert((cond), msg)
|
||||||
|
#define TYPEOF(type) __typeof__(type)
|
||||||
|
|
||||||
|
/* Declarations */
|
||||||
|
#define DECL_ATOMIC(type) _Atomic type
|
||||||
|
|
||||||
|
/* Attributes */
|
||||||
|
#define ATTR_PACKED __attribute__((packed))
|
||||||
|
#define ATTR_UNUSED __attribute__((unused))
|
||||||
|
#define ATTR_USED __attribute__((used))
|
||||||
|
#define ATTR_SECTION(x) __attribute__ ((section (#x)))
|
||||||
|
#define ATTR_ALIGN(x) _Alignas(x)
|
||||||
|
#define ATTR_FMT_PRINTF __attribute__((format (printf, 1, 2)))
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <kern/cdef.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Common macros, etc
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define OBTAIN_STRUCT_ADDR(member_addr, struct_name, member_name) ((struct_name*)((uintptr)(member_addr) - (uintptr)(&(((struct_name*)0)->member_name))))
|
|
||||||
|
|
||||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
||||||
|
|
||||||
#define SWAP(a, b, T) \
|
|
||||||
do { \
|
|
||||||
T temp = *(a); \
|
|
||||||
*(a) = *(b); \
|
|
||||||
*(b) = temp; \
|
|
||||||
} while(0);
|
|
||||||
|
|
||||||
uint32
|
|
||||||
krand(void);
|
|
||||||
|
|
||||||
void
|
|
||||||
ksrand(uint32 _seed);
|
|
||||||
|
|
||||||
uint64
|
|
||||||
str_len(char const *str);
|
|
||||||
|
|
||||||
|
|
||||||
uint64
|
|
||||||
str_cmp(char const *str1, char const *str2);
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
mem_cpy(void *src, void *dst, uint64 size);
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
mem_mv(void *src, void *dst, uint64 size);
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
mem_set(void *src, uint8 val, uint64 size);
|
|
||||||
|
|
||||||
|
|
||||||
static inline uint64
|
|
||||||
bit_mask(uint32 bit)
|
|
||||||
{
|
|
||||||
return (uint64) 1 << bit;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint64
|
|
||||||
bit_field_mask(uint32 low, uint32 high)
|
|
||||||
{
|
|
||||||
return ~(~(uint64) 0 << high << 1) << low;
|
|
||||||
}
|
|
33
inc/kern/kinit.h
Normal file
33
inc/kern/kinit.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kern/lds.h>
|
||||||
|
|
||||||
|
typedef void (kinitf)(void*);
|
||||||
|
|
||||||
|
struct kinit {
|
||||||
|
void* args;
|
||||||
|
kinitf* func;
|
||||||
|
int pri;
|
||||||
|
int subsys;
|
||||||
|
const char* name;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define KINIT_START (struct kinit **)LDS_START(kinit)
|
||||||
|
#define KINIT_STOP (struct kinit **)LDS_STOP(kinit)
|
||||||
|
|
||||||
|
LDS_DECL(kinit);
|
||||||
|
|
||||||
|
#define KINIT_DECL(_name, _subsys, _pri, _func, _args) \
|
||||||
|
static const struct kinit _kinit_##name = { \
|
||||||
|
.args = _args, \
|
||||||
|
.func = _func, \
|
||||||
|
.subsys = _subsys, \
|
||||||
|
.pri= _pri, \
|
||||||
|
.name = #_name \
|
||||||
|
}; \
|
||||||
|
LDS_ATTR(kinit) ATTR_USED static const struct kinit * _kinit_lds_##name = &_kinit_##name
|
||||||
|
|
||||||
|
enum {
|
||||||
|
KINIT_SUBSYS_KERN = 0,
|
||||||
|
KINIT_SUBSYS_KTEST = 1
|
||||||
|
};
|
11
inc/kern/lds.h
Normal file
11
inc/kern/lds.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kern/cdef.h>
|
||||||
|
|
||||||
|
#define LDS_DECL(name) \
|
||||||
|
extern const char __start_##name[]; \
|
||||||
|
extern const char __stop_##name[]
|
||||||
|
|
||||||
|
#define LDS_START(name) ((void*)__start_##name)
|
||||||
|
#define LDS_STOP(name) ((void*)__stop_##name)
|
||||||
|
#define LDS_ATTR(name) ATTR_SECTION(name)
|
77
inc/kern/libkern.h
Normal file
77
inc/kern/libkern.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kern/cdef.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common macros, etc
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define OBTAIN_STRUCT_ADDR(member_addr, struct_name, member_name) ((struct_name*)((uintptr)(member_addr) - (uintptr)(&(((struct_name*)0)->member_name))))
|
||||||
|
|
||||||
|
#define CEIL(num, div) \
|
||||||
|
({ __typeof__(num) _num = (num); \
|
||||||
|
__typeof__(div) _div = (div); \
|
||||||
|
((_num + _div - 1) / _div); })
|
||||||
|
|
||||||
|
#define MIN(a, b) \
|
||||||
|
({ __typeof__(a) _a = (a); \
|
||||||
|
__typeof__(b) _b = (b); \
|
||||||
|
(_a) < (_b) ? (_a) : (_b); })
|
||||||
|
|
||||||
|
#define MAX(a, b) \
|
||||||
|
({ __typeof__(a) _a = (a); \
|
||||||
|
__typeof__(b) _b = (b); \
|
||||||
|
(_a) > (_b) ? (_a) : (_b); })
|
||||||
|
|
||||||
|
#define SWAP(a, b) do { \
|
||||||
|
__typeof__(*a) temp = *(a); \
|
||||||
|
*(a) = *(b); \
|
||||||
|
*(b) = temp; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define BIT_FIELD_MASK(low, high) ((1ul >> (high)) - 1)
|
||||||
|
#define BIT_MASK(bit) (1ul >> (bit))
|
||||||
|
|
||||||
|
void
|
||||||
|
memswp(void *dst, void *src, usize size);
|
||||||
|
|
||||||
|
void *
|
||||||
|
memcpy(void *dst, const void *src, usize size);
|
||||||
|
|
||||||
|
void *
|
||||||
|
memset(void *dst, int val, usize size);
|
||||||
|
|
||||||
|
void
|
||||||
|
qsort(void *base, usize num, usize sz, int (*cmpf)(const void *, const void *));
|
||||||
|
|
||||||
|
void *
|
||||||
|
memmove(void *dst, const void *src, usize size);
|
||||||
|
|
||||||
|
static inline
|
||||||
|
int toupper(int c)
|
||||||
|
{
|
||||||
|
if (c >= 'a' && c <= 'z') {
|
||||||
|
return c - ('a' - 'A');
|
||||||
|
} else {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert a max 15 d to its character, otherwise d is returned */
|
||||||
|
static inline
|
||||||
|
uint dtoa(uint d)
|
||||||
|
{
|
||||||
|
if (d < 10) {
|
||||||
|
return d + '0';
|
||||||
|
} else if (d < 16) {
|
||||||
|
return d - 10 + 'a';
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong
|
||||||
|
krand();
|
||||||
|
|
||||||
|
void
|
||||||
|
ksrand(ulong sd);
|
||||||
|
|
@ -1,43 +1,30 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <kern/cdef.h>
|
#include <kern/cdef.h>
|
||||||
#include <kern/assert.h>
|
#include <kern/poison.h>
|
||||||
|
#include <kern/brute.h>
|
||||||
|
|
||||||
struct list_entry {
|
struct list_entry {
|
||||||
struct list_entry *next;
|
|
||||||
struct list_entry *prev;
|
struct list_entry *prev;
|
||||||
};
|
struct list_entry *next;
|
||||||
|
|
||||||
struct list {
|
|
||||||
struct list_entry *head;
|
|
||||||
struct list_entry *tail;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Init Operations
|
* Init Operations
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
list_init(struct list *list)
|
list_init(struct list_entry *head)
|
||||||
{
|
{
|
||||||
list->head = NULL;
|
head->next = head;
|
||||||
list->tail = NULL;
|
head->prev = head;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline int
|
||||||
list_entry_init(struct list_entry *ent)
|
|
||||||
{
|
|
||||||
ent->prev = NULL;
|
|
||||||
ent->next = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
list_empty(struct list_entry *ent)
|
list_empty(struct list_entry *ent)
|
||||||
{
|
{
|
||||||
return (ent->next == NULL);
|
return (ent->next == ent);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* Location Operations
|
|
||||||
*/
|
|
||||||
static inline struct list_entry *
|
static inline struct list_entry *
|
||||||
list_prev(struct list_entry *ent)
|
list_prev(struct list_entry *ent)
|
||||||
{
|
{
|
||||||
@ -50,55 +37,54 @@ list_next(struct list_entry *ent)
|
|||||||
return ent->next;
|
return ent->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct list_entry *
|
|
||||||
list_head(struct list *list)
|
|
||||||
{
|
|
||||||
return list->head;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct list_entry *
|
|
||||||
list_tail(struct list *list)
|
|
||||||
{
|
|
||||||
return list->tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Insert Operations
|
* Insert Operations
|
||||||
*/
|
*/
|
||||||
void
|
static inline void
|
||||||
list_insert(struct list *list, struct list_entry *cur, struct list_entry *ent);
|
list_insert(struct list_entry *head, struct list_entry *ent)
|
||||||
|
|
||||||
static inline void
|
|
||||||
list_insert_head(struct list *list, struct list_entry *ent)
|
|
||||||
{
|
{
|
||||||
list_insert(list, NULL, ent);
|
ent->next = head->next;
|
||||||
|
ent->prev = head;
|
||||||
|
|
||||||
|
head->next->prev = ent;
|
||||||
|
head->next = ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
list_insert_tail(struct list *list, struct list_entry *ent)
|
list_insert_before(struct list_entry *head, struct list_entry *ent)
|
||||||
{
|
{
|
||||||
list_insert(list, list_tail(list), ent);
|
list_insert(head->prev, ent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove Operations
|
* Remove Operations
|
||||||
*/
|
*/
|
||||||
void
|
|
||||||
list_remove(struct list *list, struct list_entry *ent);
|
|
||||||
|
|
||||||
|
|
||||||
static inline struct list_entry *
|
static inline struct list_entry *
|
||||||
list_remove_tail(struct list *list)
|
list_remove(struct list_entry *ent)
|
||||||
{
|
{
|
||||||
struct list_entry *ret = list_tail(list);
|
ent->next->prev = ent->prev;
|
||||||
list_remove(list, ret);
|
ent->prev->next = ent->next;
|
||||||
return ret;
|
|
||||||
|
ent->next = POISON_LIST;
|
||||||
|
ent->prev = POISON_LIST;
|
||||||
|
|
||||||
|
return ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct list_entry *
|
static inline struct list_entry *
|
||||||
list_remove_head(struct list *list)
|
list_remove_before(struct list_entry *list)
|
||||||
{
|
{
|
||||||
struct list_entry *ret = list_head(list);
|
return list_remove(list->prev);
|
||||||
list_remove(list, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct list_entry *
|
||||||
|
list_remove_after(struct list_entry *list)
|
||||||
|
{
|
||||||
|
return list_remove(list->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LIST_FOREACH(list, it) \
|
||||||
|
for (it = list_next(list); it != list; it = list_next(it))
|
||||||
|
|
||||||
|
#define LIST_FOREACH_REVERSE(list, it) \
|
||||||
|
for (it = list_prev(list); it != list; it = list_prev(it))
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <kern/cdef.h>
|
|
||||||
|
|
||||||
void
|
|
||||||
panic(uint32 reason);
|
|
9
inc/kern/poison.h
Normal file
9
inc/kern/poison.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define POISON_BASE (0xDEAD000000000000)
|
||||||
|
#define POISON_STEP (0x1000)
|
||||||
|
|
||||||
|
#define MAKE_POISON(idx) (POISON_BASE + POISON_STEP * (idx))
|
||||||
|
|
||||||
|
#define POISON_LIST ((void*)MAKE_POISON(0))
|
||||||
|
#define POISON_AVL ((void*)MAKE_POISON(1))
|
@ -3,8 +3,8 @@
|
|||||||
#include <kern/cdef.h>
|
#include <kern/cdef.h>
|
||||||
#include <kern/print.h>
|
#include <kern/print.h>
|
||||||
|
|
||||||
void
|
ATTR_FMT_PRINTF int
|
||||||
kprintf(const char *str, ...);
|
kprintf(const char *str, ...);
|
||||||
|
|
||||||
void
|
int
|
||||||
kvprintf(const char *str, va_list args);
|
kvprintf(const char *str, va_list args);
|
||||||
|
@ -2,16 +2,26 @@
|
|||||||
|
|
||||||
#include <kern/cdef.h>
|
#include <kern/cdef.h>
|
||||||
|
|
||||||
struct spin_lock
|
// implements a simple ticket lock
|
||||||
{
|
struct spin_lock {
|
||||||
int32 val;
|
// LOW 16 bits: cur ticket
|
||||||
|
// HIGH 16 bits: cur owner
|
||||||
|
DECL_ATOMIC(uint32) val;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
#define SPIN_LOCK_INITIALIZER {.val = ATOMIC_VAR_INIT(0)}
|
||||||
spin_init(struct spin_lock *lock);
|
|
||||||
|
STATIC_ASSERT(sizeof(struct spin_lock) == sizeof(uint32), "spin_lock size isn't 32 bits");
|
||||||
|
|
||||||
void
|
void
|
||||||
spin_lock(struct spin_lock *lock);
|
spin_lock_init(struct spin_lock *lock);
|
||||||
|
|
||||||
void
|
void
|
||||||
spin_unlock(struct spin_lock *lock);
|
spin_lock_acq(struct spin_lock *lock);
|
||||||
|
|
||||||
|
void
|
||||||
|
spin_lock_rel(struct spin_lock *lock);
|
||||||
|
|
||||||
|
// returns non-zero on success otherwise zero
|
||||||
|
int
|
||||||
|
spin_lock_try_acq(struct spin_lock *lock);
|
||||||
|
@ -5,11 +5,10 @@
|
|||||||
/**
|
/**
|
||||||
* Specific error codes
|
* Specific error codes
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
enum {
|
||||||
SUCCESS = 0x0,
|
S_OK = 0x0,
|
||||||
ENOMEM = 0x1,
|
S_NOMEM = 0x1,
|
||||||
EINVARG = 0x2,
|
S_INVARG = 0x2,
|
||||||
EINIT = 0x3,
|
S_INIT = 0x3,
|
||||||
EDUP = 0x4
|
S_DUP = 0x4
|
||||||
} kstatus;
|
};
|
||||||
|
|
||||||
|
36
inc/test/ktest.h
Normal file
36
inc/test/ktest.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kern/cdef.h>
|
||||||
|
#include <kern/lds.h>
|
||||||
|
|
||||||
|
LDS_DECL(ktest);
|
||||||
|
|
||||||
|
typedef void (ktestf)(void*);
|
||||||
|
|
||||||
|
struct ktest {
|
||||||
|
void* args;
|
||||||
|
ktestf* func;
|
||||||
|
int subsys;
|
||||||
|
const char* name;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define KTEST_START (struct ktest **)LDS_START(ktest)
|
||||||
|
#define KTEST_STOP (struct ktest **)LDS_STOP(ktest)
|
||||||
|
|
||||||
|
#define KTEST_DECL(_name, _subsys, _func, _args) \
|
||||||
|
static const struct ktest _ktest_##_name = { \
|
||||||
|
.args = _args, \
|
||||||
|
.func = _func, \
|
||||||
|
.subsys = _subsys, \
|
||||||
|
.name = #_name \
|
||||||
|
}; \
|
||||||
|
LDS_ATTR(ktest) ATTR_USED static const struct ktest * _ktest_lds_##_name = &_ktest_##_name
|
||||||
|
|
||||||
|
enum {
|
||||||
|
KTEST_SUBSYS_LIST = 0,
|
||||||
|
KTEST_SUBSYS_AVL = 1,
|
||||||
|
KTEST_SUBSYS_QSORT = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
ktest_begin(const char* name);
|
@ -1,13 +1,11 @@
|
|||||||
set(SUBMODULE kern)
|
set(SUBMODULE kern)
|
||||||
set(CC_SRC
|
set(CC_SRC
|
||||||
assert.c
|
avl_tree.c
|
||||||
atree.c
|
libkern.c
|
||||||
clib.c
|
kmain.c
|
||||||
main.c
|
|
||||||
panic.c
|
|
||||||
print.c
|
print.c
|
||||||
spin_lock.c
|
spin_lock.c
|
||||||
list.c )
|
)
|
||||||
|
|
||||||
include(${MK}/kern.cmake)
|
include(${MK}/kern.cmake)
|
||||||
|
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
#include <kern/cdef.h>
|
|
||||||
#include <kern/assert.h>
|
|
||||||
#include <kern/print.h>
|
|
||||||
|
|
||||||
void kassert_ex(const char *expr_str, const char *file, int32 line, int32 expr)
|
|
||||||
{
|
|
||||||
if (!expr)
|
|
||||||
{
|
|
||||||
kprintf("Assertion \"%s\" failed at %s:%d.\n", expr_str, file, line);
|
|
||||||
}
|
|
||||||
}
|
|
473
kern/atree.c
473
kern/atree.c
@ -1,473 +0,0 @@
|
|||||||
#include <kern/atree.h>
|
|
||||||
#include <kern/clib.h>
|
|
||||||
#include <kern/cdef.h>
|
|
||||||
|
|
||||||
static struct atree_node *
|
|
||||||
atree_node_max(struct atree_node *node)
|
|
||||||
{
|
|
||||||
while ((node != NULL) && (node->right != NULL)) {
|
|
||||||
node = node->right;
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct atree_node *
|
|
||||||
atree_node_min(struct atree_node *node)
|
|
||||||
{
|
|
||||||
while ((node != NULL) && (node->left != NULL)) {
|
|
||||||
node = node->left;
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
atree_node_init(struct atree_node *it)
|
|
||||||
{
|
|
||||||
if (it != NULL) {
|
|
||||||
it->height = 0;
|
|
||||||
it->left = NULL;
|
|
||||||
it->right = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int32
|
|
||||||
atree_node_get_height(struct atree_node *node)
|
|
||||||
{
|
|
||||||
return node == NULL ? -1 : node->height;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int32
|
|
||||||
atree_node_get_balance_factor(struct atree_node *node)
|
|
||||||
{
|
|
||||||
if (node == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return atree_node_get_height(node->left) - atree_node_get_height(node->right);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct atree_node *
|
|
||||||
atree_node_right_rotate(struct atree_node *node)
|
|
||||||
{
|
|
||||||
struct atree_node *lchild = node->left;
|
|
||||||
node->left = lchild->right;
|
|
||||||
lchild->right = node;
|
|
||||||
|
|
||||||
node->height = MAX(atree_node_get_height(node->left), atree_node_get_height(node->right)) + 1;
|
|
||||||
lchild->height = MAX(atree_node_get_height(lchild->left), atree_node_get_height(lchild->right)) + 1;
|
|
||||||
return lchild;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct atree_node *
|
|
||||||
atree_node_left_rotate(struct atree_node *node)
|
|
||||||
{
|
|
||||||
struct atree_node *rchild = node->right;
|
|
||||||
node->right = rchild->left;
|
|
||||||
rchild->left = node;
|
|
||||||
|
|
||||||
node->height = MAX(atree_node_get_height(node->left), atree_node_get_height(node->right)) + 1;
|
|
||||||
rchild->height = MAX(atree_node_get_height(rchild->left), atree_node_get_height(rchild->right)) + 1;
|
|
||||||
return rchild;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct atree_node *
|
|
||||||
atree_node_balance(struct atree_node *node)
|
|
||||||
{
|
|
||||||
int32 bf;
|
|
||||||
int32 cbf;
|
|
||||||
|
|
||||||
bf = atree_node_get_balance_factor(node);
|
|
||||||
|
|
||||||
if (bf > 1) {
|
|
||||||
/*
|
|
||||||
* Left double heavy
|
|
||||||
*/
|
|
||||||
cbf = atree_node_get_balance_factor(node->left);
|
|
||||||
if (cbf >= 0) {
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Left child is left heavy
|
|
||||||
* x (k) y (k-1)
|
|
||||||
* / \ RR(x) / \
|
|
||||||
* (k-1) y A (k-3) -----------> (k-2)B x (k-2)
|
|
||||||
* / \ / \
|
|
||||||
* (k-2) B C (k-3) (k-3) C A (k-3)
|
|
||||||
*/
|
|
||||||
return atree_node_right_rotate(node);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Left child is right heavy
|
|
||||||
* x (k) x (k)
|
|
||||||
* / \ / \
|
|
||||||
* (k-1) y A (k-3) LR(y) (k-1) z A (k-3)
|
|
||||||
* / \ ------------> / \
|
|
||||||
* (k-3) B z (k-2) (k-2) y D (k-4)
|
|
||||||
* / \ / \
|
|
||||||
* (k-3) C D (k-4) (k-3) B C (k-3)
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* x (k) __z__ (k-1)
|
|
||||||
* / \ / \
|
|
||||||
* (k-1) z A (k-3) (k-2) y x (k-2)
|
|
||||||
* / \ RR(x) / \ / \
|
|
||||||
* (k-2) y D (k-4) ------------> B C D A
|
|
||||||
* / \
|
|
||||||
* (k-3)B C (k-3)
|
|
||||||
*/
|
|
||||||
node->left = atree_node_left_rotate(node->left);
|
|
||||||
return atree_node_right_rotate(node);
|
|
||||||
}
|
|
||||||
} else if (bf < -1) {
|
|
||||||
{
|
|
||||||
cbf = atree_node_get_balance_factor(node->right);
|
|
||||||
if (cbf <= 0) {
|
|
||||||
// right right, see above
|
|
||||||
return atree_node_left_rotate(node);
|
|
||||||
} else {
|
|
||||||
// right left, see above
|
|
||||||
node->right = atree_node_right_rotate(node->right);
|
|
||||||
return atree_node_left_rotate(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct atree_node *
|
|
||||||
atree_node_insert(struct atree_node *node, struct atree_node *entry, atree_cmp_fn compare,
|
|
||||||
struct atree_node **overwritten)
|
|
||||||
{
|
|
||||||
if (node == NULL) {
|
|
||||||
atree_node_init(entry);
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 comp = compare(node, entry);
|
|
||||||
if (comp < 0) {
|
|
||||||
node->right = atree_node_insert(node->right, entry, compare, overwritten);
|
|
||||||
} else {
|
|
||||||
if (comp == 0) {
|
|
||||||
/*
|
|
||||||
* overwrite existing value
|
|
||||||
*/
|
|
||||||
atree_node_init(entry);
|
|
||||||
entry->right = node->right;
|
|
||||||
entry->left = node->left;
|
|
||||||
entry->height = node->height;
|
|
||||||
*overwritten = node;
|
|
||||||
return entry;
|
|
||||||
} else {
|
|
||||||
node->left = atree_node_insert(node->left, entry, compare, overwritten);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node->height = MAX(atree_node_get_height(node->left), atree_node_get_height(node->right)) + 1;
|
|
||||||
|
|
||||||
return atree_node_balance(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct atree_node *
|
|
||||||
atree_node_search(struct atree_node *node, struct atree_node *entry, atree_cmp_fn compare, struct atree_node **parent)
|
|
||||||
{
|
|
||||||
int32 comp;
|
|
||||||
struct atree_node *prev;
|
|
||||||
struct atree_node *temp;
|
|
||||||
|
|
||||||
prev = NULL;
|
|
||||||
|
|
||||||
while (node != NULL) {
|
|
||||||
comp = compare(node, entry);
|
|
||||||
temp = node;
|
|
||||||
if (comp < 0) {
|
|
||||||
node = node->right;
|
|
||||||
} else if (comp > 0) {
|
|
||||||
node = node->left;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
prev = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parent != NULL) {
|
|
||||||
*parent = prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct atree_node *
|
|
||||||
atree_node_delete(struct atree_node *node, struct atree_node *entry, atree_cmp_fn compare, struct atree_node **deleted)
|
|
||||||
{
|
|
||||||
int32 comp;
|
|
||||||
struct atree_node *succ_parent;
|
|
||||||
|
|
||||||
if (node == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
comp = compare(node, entry);
|
|
||||||
if (comp < 0) {
|
|
||||||
node->right = atree_node_delete(node->right, entry, compare, deleted);
|
|
||||||
} else if (comp > 0) {
|
|
||||||
node->left = atree_node_delete(node->left, entry, compare, deleted);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Write the deleted node first
|
|
||||||
*/
|
|
||||||
*deleted = node;
|
|
||||||
|
|
||||||
if ((node->left == NULL) || (node->right == NULL)) {
|
|
||||||
/*
|
|
||||||
* 0 or 1 child
|
|
||||||
*/
|
|
||||||
struct atree_node *child = node->left != NULL ? node->left : node->right;
|
|
||||||
|
|
||||||
if (child == NULL) {
|
|
||||||
node = NULL;
|
|
||||||
} else {
|
|
||||||
node = child;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* 2 children
|
|
||||||
* meaning that the successor must be in the right subtree
|
|
||||||
*/
|
|
||||||
struct atree_node *succ = atree_node_min(node->right);
|
|
||||||
atree_node_search(node, succ, compare, &succ_parent);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Swap the nodes
|
|
||||||
* note that after swapping, the BST property of the right subtree is preserved
|
|
||||||
*/
|
|
||||||
if (succ_parent == node) {
|
|
||||||
/*
|
|
||||||
* check special case where the successor is the right child
|
|
||||||
*/
|
|
||||||
node->right = succ->right;
|
|
||||||
succ->right = node;
|
|
||||||
} else {
|
|
||||||
if (succ_parent->left == succ) {
|
|
||||||
succ_parent->left = node;
|
|
||||||
} else {
|
|
||||||
succ_parent->right = node;
|
|
||||||
}
|
|
||||||
SWAP(&node->right, &succ->right, struct atree_node*);
|
|
||||||
}
|
|
||||||
SWAP(&node->left, &succ->left, struct atree_node*);
|
|
||||||
SWAP(&node->height, &succ->height, int32);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Delete the node from the right subtree
|
|
||||||
*/
|
|
||||||
succ->right = atree_node_delete(succ->right, node, compare, deleted);
|
|
||||||
|
|
||||||
node = succ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* balance the new head
|
|
||||||
*/
|
|
||||||
if (node != NULL) {
|
|
||||||
node->height = MAX(atree_node_get_height(node->left), atree_node_get_height(node->right)) + 1;
|
|
||||||
node = atree_node_balance(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct atree_node *
|
|
||||||
atree_min(struct atree *tree)
|
|
||||||
{
|
|
||||||
return atree_node_min(tree->root);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct atree_node *
|
|
||||||
atree_max(struct atree *tree)
|
|
||||||
{
|
|
||||||
return atree_node_max(tree->root);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct atree_node *
|
|
||||||
atree_next(struct atree *tree, struct atree_node *entry)
|
|
||||||
{
|
|
||||||
struct atree_node *succ;
|
|
||||||
struct atree_node *node;
|
|
||||||
int32 comp;
|
|
||||||
|
|
||||||
if (entry->right != NULL) {
|
|
||||||
succ = atree_node_min(entry->right);
|
|
||||||
} else {
|
|
||||||
succ = NULL;
|
|
||||||
node = tree->root;
|
|
||||||
|
|
||||||
while (node != NULL) {
|
|
||||||
comp = tree->cmpf(node, entry);
|
|
||||||
|
|
||||||
if (comp < 0) {
|
|
||||||
node = node->right;
|
|
||||||
} else if (comp > 0) {
|
|
||||||
succ = node;
|
|
||||||
node = node->left;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return succ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct atree_node *
|
|
||||||
atree_prev(struct atree *tree, struct atree_node *entry)
|
|
||||||
{
|
|
||||||
struct atree_node *prev;
|
|
||||||
struct atree_node *node;
|
|
||||||
int32 comp;
|
|
||||||
|
|
||||||
if (entry->left != NULL) {
|
|
||||||
prev = atree_node_max(entry->left);
|
|
||||||
} else {
|
|
||||||
prev = NULL;
|
|
||||||
node = tree->root;
|
|
||||||
|
|
||||||
while (node != NULL) {
|
|
||||||
comp = tree->cmpf(node, entry);
|
|
||||||
|
|
||||||
if (comp < 0) {
|
|
||||||
prev = node;
|
|
||||||
node = node->right;
|
|
||||||
} else if (comp > 0) {
|
|
||||||
node = node->left;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct atree_node *
|
|
||||||
atree_search(struct atree *tree, struct atree_node *entry)
|
|
||||||
{
|
|
||||||
return atree_node_search(tree->root, entry, tree->cmpf, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct atree_node *
|
|
||||||
atree_insert(struct atree *tree, struct atree_node *entry)
|
|
||||||
{
|
|
||||||
struct atree_node *old;
|
|
||||||
|
|
||||||
old = NULL;
|
|
||||||
tree->root = atree_node_insert(tree->root, entry, tree->cmpf, &old);
|
|
||||||
return old;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct atree_node *
|
|
||||||
atree_remove(struct atree *tree, struct atree_node *entry)
|
|
||||||
{
|
|
||||||
struct atree_node *node;
|
|
||||||
|
|
||||||
node = NULL;
|
|
||||||
tree->root = atree_node_delete(tree->root, entry, tree->cmpf, &node);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint32
|
|
||||||
atree_size(struct atree *tree)
|
|
||||||
{
|
|
||||||
uint32 size;
|
|
||||||
struct atree_node *node;
|
|
||||||
|
|
||||||
size = 0;
|
|
||||||
if (tree->root != NULL) {
|
|
||||||
node = atree_min(tree);
|
|
||||||
while (node != NULL) {
|
|
||||||
size++;
|
|
||||||
node = atree_next(tree, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
atree_init(struct atree *tree, atree_cmp_fn compare)
|
|
||||||
{
|
|
||||||
tree->cmpf = compare;
|
|
||||||
tree->root = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For tests
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int32
|
|
||||||
atree_node_calc_height(struct atree_node *tree)
|
|
||||||
{
|
|
||||||
if (tree == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return MAX(atree_node_calc_height(tree->left), atree_node_calc_height(tree->right)) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool
|
|
||||||
atree_node_test(struct atree_node *tree, atree_cmp_fn compare)
|
|
||||||
{
|
|
||||||
if (tree == NULL) {
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (atree_node_get_balance_factor(tree) < -1 || atree_node_get_balance_factor(tree) > 1 ||
|
|
||||||
atree_node_calc_height(tree) != tree->height) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tree->height == 0 && ((tree->left != NULL) || (tree->right != NULL))) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tree->right == tree || tree->left == tree || (tree->right == tree->left && tree->right != NULL)) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((tree->right != NULL && compare(tree, tree->right) > 0) ||
|
|
||||||
(tree->left != NULL && compare(tree, tree->left) < 0)) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return atree_node_test(tree->left, compare) && atree_node_test(tree->right, compare);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
atree_validate(struct atree *tree)
|
|
||||||
{
|
|
||||||
if (tree == NULL) {
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
return atree_node_test(tree->root, tree->cmpf);
|
|
||||||
}
|
|
462
kern/avl_tree.c
Normal file
462
kern/avl_tree.c
Normal file
@ -0,0 +1,462 @@
|
|||||||
|
#include <kern/avl_tree.h>
|
||||||
|
#include <kern/libkern.h>
|
||||||
|
#include <kern/poison.h>
|
||||||
|
#include <kern/cdef.h>
|
||||||
|
|
||||||
|
static inline struct avl_node *
|
||||||
|
_avl_node_max(struct avl_node *node)
|
||||||
|
{
|
||||||
|
while (node != NULL) {
|
||||||
|
node = node->right;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the minimum in the subtree with parent */
|
||||||
|
static inline struct avl_node *
|
||||||
|
_avl_node_minp(struct avl_node *node, struct avl_node **parent)
|
||||||
|
{
|
||||||
|
struct avl_node *p = NULL;
|
||||||
|
|
||||||
|
while (node != NULL) {
|
||||||
|
p = node;
|
||||||
|
node = node->left;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent != NULL) {
|
||||||
|
*parent = p;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct avl_node *
|
||||||
|
_avl_node_min(struct avl_node *node)
|
||||||
|
{
|
||||||
|
return _avl_node_minp(node, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
_avl_node_poison(struct avl_node *node)
|
||||||
|
{
|
||||||
|
node->left = POISON_AVL;
|
||||||
|
node->right = POISON_AVL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
_avl_node_height(struct avl_node *node)
|
||||||
|
{
|
||||||
|
return node == NULL ? -1 : node->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
_avl_node_bf(struct avl_node *node)
|
||||||
|
{
|
||||||
|
if (node == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return _avl_node_height(node->left) - _avl_node_height(node->right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline struct avl_node *
|
||||||
|
_avl_node_rr(struct avl_node *node)
|
||||||
|
{
|
||||||
|
struct avl_node *lchild = node->left;
|
||||||
|
node->left = lchild->right;
|
||||||
|
lchild->right = node;
|
||||||
|
|
||||||
|
node->height = MAX(_avl_node_height(node->left), _avl_node_height(node->right)) + 1;
|
||||||
|
lchild->height = MAX(_avl_node_height(lchild->left), _avl_node_height(lchild->right)) + 1;
|
||||||
|
return lchild;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline struct avl_node *
|
||||||
|
_avl_node_lr(struct avl_node *node)
|
||||||
|
{
|
||||||
|
struct avl_node *rchild = node->right;
|
||||||
|
node->right = rchild->left;
|
||||||
|
rchild->left = node;
|
||||||
|
|
||||||
|
node->height = MAX(_avl_node_height(node->left), _avl_node_height(node->right)) + 1;
|
||||||
|
rchild->height = MAX(_avl_node_height(rchild->left), _avl_node_height(rchild->right)) + 1;
|
||||||
|
return rchild;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* balances the subtree, returns the new root of the subtree */
|
||||||
|
static struct avl_node *
|
||||||
|
_avl_node_balance(struct avl_node *node)
|
||||||
|
{
|
||||||
|
int bf;
|
||||||
|
int cbf;
|
||||||
|
|
||||||
|
bf = _avl_node_bf(node);
|
||||||
|
|
||||||
|
if (bf > 1) {
|
||||||
|
/*
|
||||||
|
* Left double heavy
|
||||||
|
*/
|
||||||
|
cbf = _avl_node_bf(node->left);
|
||||||
|
if (cbf >= 0) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Left child is left heavy
|
||||||
|
* x (k) y (k-1)
|
||||||
|
* / \ RR(x) / \
|
||||||
|
* (k-1) y A (k-3) -----------> (k-2)B x (k-2)
|
||||||
|
* / \ / \
|
||||||
|
* (k-2) B C (k-3) (k-3) C A (k-3)
|
||||||
|
*/
|
||||||
|
return _avl_node_rr(node);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Left child is right heavy
|
||||||
|
* x (k) x (k)
|
||||||
|
* / \ / \
|
||||||
|
* (k-1) y A (k-3) LR(y) (k-1) z A (k-3)
|
||||||
|
* / \ ------------> / \
|
||||||
|
* (k-3) B z (k-2) (k-2) y D (k-4)
|
||||||
|
* / \ / \
|
||||||
|
* (k-3) C D (k-4) (k-3) B C (k-3)
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* x (k) __z__ (k-1)
|
||||||
|
* / \ / \
|
||||||
|
* (k-1) z A (k-3) (k-2) y x (k-2)
|
||||||
|
* / \ RR(x) / \ / \
|
||||||
|
* (k-2) y D (k-4) ------------> B C D A
|
||||||
|
* / \
|
||||||
|
* (k-3)B C (k-3)
|
||||||
|
*/
|
||||||
|
node->left = _avl_node_lr(node->left);
|
||||||
|
return _avl_node_rr(node);
|
||||||
|
}
|
||||||
|
} else if (bf < -1) {
|
||||||
|
{
|
||||||
|
cbf = _avl_node_bf(node->right);
|
||||||
|
if (cbf <= 0) {
|
||||||
|
// right right, see above
|
||||||
|
return _avl_node_lr(node);
|
||||||
|
} else {
|
||||||
|
// right left, see above
|
||||||
|
node->right = _avl_node_rr(node->right);
|
||||||
|
return _avl_node_lr(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* does not allow duplicates, returns the new root of the subtree after insertion */
|
||||||
|
static struct avl_node *
|
||||||
|
_avl_node_insert(struct avl_node *node, struct avl_node *entry, avl_cmpf cmpf, struct avl_node **out)
|
||||||
|
{
|
||||||
|
if (node == NULL) {
|
||||||
|
/* leaf */
|
||||||
|
entry->height = 0;
|
||||||
|
entry->left = NULL;
|
||||||
|
entry->right = NULL;
|
||||||
|
*out = entry;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
int comp = cmpf(node, entry);
|
||||||
|
if (comp < 0) {
|
||||||
|
node->right = _avl_node_insert(node->right, entry, cmpf, out);
|
||||||
|
} else if (comp == 0) {
|
||||||
|
/* duplicate */
|
||||||
|
*out = NULL;
|
||||||
|
return node;
|
||||||
|
} else {
|
||||||
|
node->left = _avl_node_insert(node->left, entry, cmpf, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
node->height = MAX(_avl_node_height(node->left), _avl_node_height(node->right)) + 1;
|
||||||
|
|
||||||
|
return _avl_node_balance(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find the node and its parent in the subtree */
|
||||||
|
static struct avl_node *
|
||||||
|
_avl_node_search(struct avl_node *node, struct avl_node *entry, avl_cmpf cmpf)
|
||||||
|
{
|
||||||
|
int comp;
|
||||||
|
|
||||||
|
while (node != NULL) {
|
||||||
|
comp = cmpf(node, entry);
|
||||||
|
if (comp < 0) {
|
||||||
|
node = node->right;
|
||||||
|
} else if (comp > 0) {
|
||||||
|
node = node->left;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct avl_node *
|
||||||
|
_avl_node_delete(struct avl_node *node, struct avl_node *entry, avl_cmpf cmpf, struct avl_node **deleted)
|
||||||
|
{
|
||||||
|
int comp;
|
||||||
|
struct avl_node *succ_parent;
|
||||||
|
|
||||||
|
if (node == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
comp = cmpf(node, entry);
|
||||||
|
if (comp < 0) {
|
||||||
|
node->right = _avl_node_delete(node->right, entry, cmpf, deleted);
|
||||||
|
} else if (comp > 0) {
|
||||||
|
node->left = _avl_node_delete(node->left, entry, cmpf, deleted);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Write the deleted node first
|
||||||
|
*/
|
||||||
|
*deleted = node;
|
||||||
|
|
||||||
|
if ((node->left == NULL) || (node->right == NULL)) {
|
||||||
|
/*
|
||||||
|
* 0 or 1 child
|
||||||
|
*/
|
||||||
|
struct avl_node *child = node->left != NULL ? node->left : node->right;
|
||||||
|
|
||||||
|
if (child == NULL) {
|
||||||
|
node = NULL;
|
||||||
|
} else {
|
||||||
|
node = child;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* 2 children
|
||||||
|
* meaning that the successor must be in the right subtree
|
||||||
|
*/
|
||||||
|
struct avl_node *succ = _avl_node_minp(node->right, &succ_parent);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Swap the nodes
|
||||||
|
* note that after swapping, the BST property of the right subtree is preserved
|
||||||
|
*/
|
||||||
|
if (succ_parent == node) {
|
||||||
|
/*
|
||||||
|
* check special case where the successor is the right child
|
||||||
|
*/
|
||||||
|
node->right = succ->right;
|
||||||
|
succ->right = node;
|
||||||
|
} else {
|
||||||
|
if (succ_parent->left == succ) {
|
||||||
|
succ_parent->left = node;
|
||||||
|
} else {
|
||||||
|
succ_parent->right = node;
|
||||||
|
}
|
||||||
|
SWAP(&node->right, &succ->right);
|
||||||
|
}
|
||||||
|
SWAP(&node->left, &succ->left);
|
||||||
|
SWAP(&node->height, &succ->height);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete the node from the right subtree
|
||||||
|
*/
|
||||||
|
succ->right = _avl_node_delete(succ->right, node, cmpf, deleted);
|
||||||
|
|
||||||
|
node = succ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* poison the node */
|
||||||
|
_avl_node_poison(*deleted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* balance the new head
|
||||||
|
*/
|
||||||
|
if (node != NULL) {
|
||||||
|
node->height = MAX(_avl_node_height(node->left), _avl_node_height(node->right)) + 1;
|
||||||
|
node = _avl_node_balance(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct avl_node *
|
||||||
|
avl_first(struct avl_root *root)
|
||||||
|
{
|
||||||
|
return _avl_node_min(root->root);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct avl_node *
|
||||||
|
avl_last(struct avl_root *root)
|
||||||
|
{
|
||||||
|
return _avl_node_max(root->root);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct avl_node *
|
||||||
|
avl_next(struct avl_root *root, struct avl_node *entry)
|
||||||
|
{
|
||||||
|
struct avl_node *succ;
|
||||||
|
struct avl_node *node;
|
||||||
|
int comp;
|
||||||
|
|
||||||
|
if (entry->right != NULL) {
|
||||||
|
succ = _avl_node_min(entry->right);
|
||||||
|
} else {
|
||||||
|
succ = NULL;
|
||||||
|
node = root->root;
|
||||||
|
|
||||||
|
while (node != NULL) {
|
||||||
|
comp = root->cmpf(node, entry);
|
||||||
|
|
||||||
|
if (comp < 0) {
|
||||||
|
node = node->right;
|
||||||
|
} else if (comp > 0) {
|
||||||
|
succ = node;
|
||||||
|
node = node->left;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return succ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct avl_node *
|
||||||
|
avl_prev(struct avl_root *root, struct avl_node *entry)
|
||||||
|
{
|
||||||
|
struct avl_node *prev;
|
||||||
|
struct avl_node *node;
|
||||||
|
int comp;
|
||||||
|
|
||||||
|
if (entry->left != NULL) {
|
||||||
|
prev = _avl_node_max(entry->left);
|
||||||
|
} else {
|
||||||
|
prev = NULL;
|
||||||
|
node = root->root;
|
||||||
|
|
||||||
|
while (node != NULL) {
|
||||||
|
comp = root->cmpf(node, entry);
|
||||||
|
|
||||||
|
if (comp < 0) {
|
||||||
|
prev = node;
|
||||||
|
node = node->right;
|
||||||
|
} else if (comp > 0) {
|
||||||
|
node = node->left;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct avl_node *
|
||||||
|
avl_search(struct avl_root *root, struct avl_node *entry)
|
||||||
|
{
|
||||||
|
return _avl_node_search(root->root, entry, root->cmpf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct avl_node *
|
||||||
|
avl_insert(struct avl_root *root, struct avl_node *entry)
|
||||||
|
{
|
||||||
|
struct avl_node *old;
|
||||||
|
|
||||||
|
root->root = _avl_node_insert(root->root, entry, root->cmpf, &old);
|
||||||
|
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct avl_node *
|
||||||
|
avl_remove(struct avl_root *root, struct avl_node *entry)
|
||||||
|
{
|
||||||
|
struct avl_node *node;
|
||||||
|
|
||||||
|
node = NULL;
|
||||||
|
root->root = _avl_node_delete(root->root, entry, root->cmpf, &node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
usize
|
||||||
|
avl_size(struct avl_root *root)
|
||||||
|
{
|
||||||
|
usize size;
|
||||||
|
struct avl_node *node;
|
||||||
|
|
||||||
|
if (avl_empty(root))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
size = 0;
|
||||||
|
node = _avl_node_min(root->root);
|
||||||
|
while (node != NULL) {
|
||||||
|
size++;
|
||||||
|
node = avl_next(root, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For tests
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
_avl_node_calc_height(struct avl_node *tree)
|
||||||
|
{
|
||||||
|
if (tree == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MAX(_avl_node_calc_height(tree->left), _avl_node_calc_height(tree->right)) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
_avl_node_test(struct avl_node *tree, avl_cmpf compare)
|
||||||
|
{
|
||||||
|
if (tree == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_avl_node_bf(tree) < -1 || _avl_node_bf(tree) > 1 ||
|
||||||
|
_avl_node_calc_height(tree) != tree->height) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tree->height == 0 && ((tree->left != NULL) || (tree->right != NULL))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tree->right == tree || tree->left == tree || (tree->right == tree->left && tree->right != NULL)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tree->right != NULL && compare(tree, tree->right) > 0) ||
|
||||||
|
(tree->left != NULL && compare(tree, tree->left) < 0)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _avl_node_test(tree->left, compare) && _avl_node_test(tree->right, compare);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
avl_validate(struct avl_root *root)
|
||||||
|
{
|
||||||
|
if (avl_empty(root)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _avl_node_test(root->root, root->cmpf);
|
||||||
|
}
|
115
kern/clib.c
115
kern/clib.c
@ -1,115 +0,0 @@
|
|||||||
|
|
||||||
#include <kern/cdef.h>
|
|
||||||
#include <kern/clib.h>
|
|
||||||
|
|
||||||
void
|
|
||||||
mem_cpy(void *src, void *dst, uint64 size)
|
|
||||||
{
|
|
||||||
if (src == NULL || dst == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
char *cSrc = (char *) src;
|
|
||||||
char *cDst = (char *) dst;
|
|
||||||
while (size--)
|
|
||||||
{
|
|
||||||
*(cDst++) = *(cSrc++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
mem_set(void *src, uint8 val, uint64 size)
|
|
||||||
{
|
|
||||||
if (src == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
while (size--)
|
|
||||||
{
|
|
||||||
*(uint8 *) src = val;
|
|
||||||
src = (void *) ((uintptr) src + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
mem_mv(void *src, void *dst, uint64 size)
|
|
||||||
{
|
|
||||||
if (src == NULL || dst == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (src >= dst)
|
|
||||||
{
|
|
||||||
mem_cpy(src, dst, size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
src = (void *) ((uintptr) src + size - 1);
|
|
||||||
dst = (void *) ((uintptr) dst + size - 1);
|
|
||||||
while (size--)
|
|
||||||
{
|
|
||||||
*(char *) dst = *(char *) src;
|
|
||||||
dst = (void *) ((uintptr) dst - 1);
|
|
||||||
src = (void *) ((uintptr) src - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Random Generator
|
|
||||||
//
|
|
||||||
static uint32 seed = 1;
|
|
||||||
static uint32 max = (uint32)-1;
|
|
||||||
|
|
||||||
uint32
|
|
||||||
krand(void)
|
|
||||||
{
|
|
||||||
seed = seed * 1103512986 + 29865;
|
|
||||||
return (unsigned int) (seed / 65536) % (max + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ksrand(uint32 _seed)
|
|
||||||
{
|
|
||||||
seed = _seed;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// String Library
|
|
||||||
//
|
|
||||||
|
|
||||||
uint64
|
|
||||||
str_len(char const *str)
|
|
||||||
{
|
|
||||||
uint64 length = 0;
|
|
||||||
if (str == NULL)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
while (*str != 0)
|
|
||||||
{
|
|
||||||
str++;
|
|
||||||
length++;
|
|
||||||
}
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64
|
|
||||||
str_cmp(char const *str1, char const *str2)
|
|
||||||
{
|
|
||||||
if (str1 == NULL || str2 == NULL)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
uint64 length = str_len(str1);
|
|
||||||
if (length != str_len(str2))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
while (length--)
|
|
||||||
{
|
|
||||||
if (*(str1 + length) != *(str2 + length))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
35
kern/kmain.c
Normal file
35
kern/kmain.c
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include <kern/cdef.h>
|
||||||
|
#include <kern/brute.h>
|
||||||
|
#include <kern/kinit.h>
|
||||||
|
#include <kern/libkern.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
kinit_cmpf(const void *ki1, const void *ki2)
|
||||||
|
{
|
||||||
|
const struct kinit *const *kinit1 = ki1;
|
||||||
|
const struct kinit *const *kinit2 = ki2;
|
||||||
|
|
||||||
|
return (*kinit1)->pri - (*kinit2)->pri;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_kinit()
|
||||||
|
{
|
||||||
|
qsort(KINIT_START, ((uintptr) KINIT_STOP - (uintptr) KINIT_START) / sizeof(struct kinit *), sizeof(struct kinit *),
|
||||||
|
kinit_cmpf);
|
||||||
|
for (struct kinit **it = KINIT_START; it < KINIT_STOP; it++) {
|
||||||
|
(*it)->func((*it)->args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel entry point
|
||||||
|
* @param boot_info passed by the bootloader
|
||||||
|
*/
|
||||||
|
ATTR_UNUSED void KABI
|
||||||
|
kmain(ATTR_UNUSED void *boot_info)
|
||||||
|
{
|
||||||
|
KASSERT(boot_info != NULL, "bootinfo is NULL");
|
||||||
|
init_kinit();
|
||||||
|
BRUTE("Control reached end of kmain");
|
||||||
|
}
|
147
kern/libkern.c
Normal file
147
kern/libkern.c
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
#include <kern/cdef.h>
|
||||||
|
#include <kern/libkern.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
memswp(void *dst, void *src, usize size)
|
||||||
|
{
|
||||||
|
char tmp;
|
||||||
|
char *buf1 = dst;
|
||||||
|
char *buf2 = src;
|
||||||
|
|
||||||
|
while (size--) {
|
||||||
|
tmp = *buf1;
|
||||||
|
*buf1 = *buf2;
|
||||||
|
*buf2 = tmp;
|
||||||
|
|
||||||
|
buf1++;
|
||||||
|
buf2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
memcpy(void *dst, const void *src, usize size)
|
||||||
|
{
|
||||||
|
const char *csrc = (const char *) src;
|
||||||
|
char *cdst = (char *) dst;
|
||||||
|
while (size--) {
|
||||||
|
*(cdst++) = *(csrc++);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
memset(void *dst, int val, usize size)
|
||||||
|
{
|
||||||
|
while (size--) {
|
||||||
|
*(uint8 *) dst = (uchar) val;
|
||||||
|
dst = (void *) ((uintptr) dst + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
memmove(void *dst, const void *src, usize size)
|
||||||
|
{
|
||||||
|
if (src >= dst) {
|
||||||
|
memcpy(dst, src, size);
|
||||||
|
} else {
|
||||||
|
src = (void *) ((uintptr) src + size - 1);
|
||||||
|
dst = (void *) ((uintptr) dst + size - 1);
|
||||||
|
while (size--) {
|
||||||
|
*(char *) dst = *(char *) src;
|
||||||
|
dst = (void *) ((uintptr) dst - 1);
|
||||||
|
src = (void *) ((uintptr) src - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* randoms taken from FreeBSD
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define NSHUFF (50)
|
||||||
|
|
||||||
|
static ulong seed = 937186357;
|
||||||
|
|
||||||
|
ulong
|
||||||
|
krand()
|
||||||
|
{
|
||||||
|
long x, hi, lo, t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute x[n + 1] = (7^5 * x[n]) mod (2^31 - 1).
|
||||||
|
* From "Random number generators: good ones are hard to find",
|
||||||
|
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
|
||||||
|
* October 1988, p. 1195.
|
||||||
|
*/
|
||||||
|
/* Can't be initialized with 0, so use another value. */
|
||||||
|
if ((x = seed) == 0)
|
||||||
|
x = 123459876;
|
||||||
|
hi = x / 127773;
|
||||||
|
lo = x % 127773;
|
||||||
|
t = 16807 * lo - 2836 * hi;
|
||||||
|
if (t < 0)
|
||||||
|
t += 0x7fffffff;
|
||||||
|
seed = t;
|
||||||
|
return (t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ksrand(ulong sd)
|
||||||
|
{
|
||||||
|
seed = sd;
|
||||||
|
for (int i = 0; i < NSHUFF; i++) {
|
||||||
|
krand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* quicksort
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
_qsort_partition(void *base, size_t num, size_t sz, int (*cmpf)(const void *, const void *))
|
||||||
|
{
|
||||||
|
void *smaller = base;
|
||||||
|
void *pivot = (char *)base + (num - 1) * sz;
|
||||||
|
/* number of items smaller than pivot */
|
||||||
|
int smaller_idx = 0;
|
||||||
|
|
||||||
|
/* pivot = last element */
|
||||||
|
while (base < pivot) {
|
||||||
|
if (cmpf(base, pivot) < 0) {
|
||||||
|
/* base < pivot */
|
||||||
|
|
||||||
|
/*swap smaller and base*/
|
||||||
|
if (smaller != base) {
|
||||||
|
memswp(smaller, base, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
smaller_idx++;
|
||||||
|
smaller = (char*)smaller + sz;
|
||||||
|
}
|
||||||
|
base = (char*)base + sz;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* swap the pivot to its correct position */
|
||||||
|
if (smaller != pivot) {
|
||||||
|
memswp(smaller, pivot, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
return smaller_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
qsort(void *base, size_t num, size_t sz, int (*cmpf)(const void *, const void *))
|
||||||
|
{
|
||||||
|
int pivot;
|
||||||
|
if (num > 0) {
|
||||||
|
pivot = _qsort_partition(base, num, sz, cmpf);
|
||||||
|
|
||||||
|
qsort(base, pivot, sz, cmpf);
|
||||||
|
qsort((char*)base + (pivot + 1) * sz, (num - pivot - 1), sz, cmpf);
|
||||||
|
}
|
||||||
|
}
|
58
kern/list.c
58
kern/list.c
@ -1,58 +0,0 @@
|
|||||||
#include <kern/list.h>
|
|
||||||
#include <kern/cdef.h>
|
|
||||||
|
|
||||||
void
|
|
||||||
list_insert(struct list *list, struct list_entry *cur, struct list_entry *ent)
|
|
||||||
{
|
|
||||||
struct list_entry *left_ent;
|
|
||||||
struct list_entry *right_ent;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* adjust the current entry
|
|
||||||
*/
|
|
||||||
if (cur == NULL) {
|
|
||||||
ent->next = list->head;
|
|
||||||
ent->prev = NULL;
|
|
||||||
} else {
|
|
||||||
ent->prev = cur;
|
|
||||||
ent->next = cur->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* make left and right entry point at correct things
|
|
||||||
*/
|
|
||||||
left_ent = cur;
|
|
||||||
right_ent = cur == NULL ? list->head : cur->next;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* adjust left and treenode node accordingly
|
|
||||||
*/
|
|
||||||
if (left_ent != NULL) {
|
|
||||||
left_ent->next = ent;
|
|
||||||
} else {
|
|
||||||
list->head = ent;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (right_ent != NULL) {
|
|
||||||
right_ent->prev = ent;
|
|
||||||
} else {
|
|
||||||
list->tail = ent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
list_remove(struct list *list, struct list_entry *ent)
|
|
||||||
{
|
|
||||||
if (ent->prev != NULL) {
|
|
||||||
ent->prev->next = ent->next;
|
|
||||||
} else {
|
|
||||||
list->head = ent->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ent->next != NULL) {
|
|
||||||
ent->next->prev = ent->prev;
|
|
||||||
} else {
|
|
||||||
list->tail = ent->prev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
15
kern/main.c
15
kern/main.c
@ -1,15 +0,0 @@
|
|||||||
#include <kern/cdef.h>
|
|
||||||
#include <kern/status.h>
|
|
||||||
|
|
||||||
#include <arch/cpu.h>
|
|
||||||
/**
|
|
||||||
* Kernel entry point
|
|
||||||
* @param boot_info passed by the bootloader
|
|
||||||
*/
|
|
||||||
void KABI
|
|
||||||
kmain(void *boot_info)
|
|
||||||
{
|
|
||||||
UNREFERENCED(boot_info);
|
|
||||||
arch_halt();
|
|
||||||
}
|
|
||||||
|
|
11
kern/panic.c
11
kern/panic.c
@ -1,11 +0,0 @@
|
|||||||
#include <kern/panic.h>
|
|
||||||
#include <kern/print.h>
|
|
||||||
#include <kern/cdef.h>
|
|
||||||
|
|
||||||
#include <arch/cpu.h>
|
|
||||||
|
|
||||||
void panic(uint32 reason)
|
|
||||||
{
|
|
||||||
kprintf("BugCheck: Reason - %ul\n", reason);
|
|
||||||
arch_halt();
|
|
||||||
}
|
|
159
kern/print.c
159
kern/print.c
@ -1,20 +1,159 @@
|
|||||||
#include <kern/print.h>
|
#include <kern/print.h>
|
||||||
#include <kern/assert.h>
|
|
||||||
#include <arch/print.h>
|
#include <arch/print.h>
|
||||||
|
#include <kern/libkern.h>
|
||||||
|
#include <kern/spin_lock.h>
|
||||||
|
|
||||||
void
|
/* max space needed for each byte is when printing it in binary = 8 bits */
|
||||||
kprintf(const char *str, ...)
|
#define NBUF_SZ (sizeof(uintmax) * 8)
|
||||||
|
|
||||||
|
static char nbuf[NBUF_SZ];
|
||||||
|
static struct spin_lock print_lock = SPIN_LOCK_INITIALIZER;
|
||||||
|
|
||||||
|
static int
|
||||||
|
_printu(char *buf, uintmax num, uint base, int cap)
|
||||||
{
|
{
|
||||||
|
int len;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
while (num > 0) {
|
||||||
|
c = dtoa(num % base);
|
||||||
|
if (cap) {
|
||||||
|
c = (char) toupper(c);
|
||||||
|
}
|
||||||
|
buf[len] = c;
|
||||||
|
|
||||||
|
len++;
|
||||||
|
num = num / base;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_vprintf(const char *fmt, va_list args)
|
||||||
|
{
|
||||||
|
uintmax num;
|
||||||
|
char c;
|
||||||
|
const char * s;
|
||||||
|
int base, usignf, capf, sz_ptr, sz_long, len, ret;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
for (; *fmt != '\0'; fmt++) {
|
||||||
|
if (*fmt != '%') {
|
||||||
|
arch_putc(*fmt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
base = 10;
|
||||||
|
usignf = 0;
|
||||||
|
sz_ptr = 0;
|
||||||
|
sz_long = 0;
|
||||||
|
capf = 0;
|
||||||
|
|
||||||
|
retry:
|
||||||
|
fmt++;
|
||||||
|
switch (*fmt) {
|
||||||
|
case 'p':
|
||||||
|
sz_ptr = 1;
|
||||||
|
goto pnum;
|
||||||
|
case 'd':
|
||||||
|
goto pnum;
|
||||||
|
case 'u':
|
||||||
|
usignf = 1;
|
||||||
|
goto pnum;
|
||||||
|
case 's':
|
||||||
|
s = (char*)va_arg(args, char *);
|
||||||
|
while (*s != '\0') {
|
||||||
|
arch_putc(*s);
|
||||||
|
s++;
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
c = (char) va_arg(args, int);
|
||||||
|
arch_putc(c);
|
||||||
|
ret++;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
base = 16;
|
||||||
|
usignf = 1;
|
||||||
|
goto pnum;
|
||||||
|
case 'X':
|
||||||
|
base = 16;
|
||||||
|
usignf = 1;
|
||||||
|
capf = 1;
|
||||||
|
goto pnum;
|
||||||
|
case 'l':
|
||||||
|
sz_long = 1;
|
||||||
|
goto retry;
|
||||||
|
case '%':
|
||||||
|
arch_putc('%');
|
||||||
|
ret++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* ignore */
|
||||||
|
break;
|
||||||
|
pnum:
|
||||||
|
if (usignf) {
|
||||||
|
if (sz_ptr) {
|
||||||
|
num = (uintptr) va_arg(args, uintptr);
|
||||||
|
} else if (sz_long) {
|
||||||
|
num = (ulong) va_arg(args, ulong);
|
||||||
|
} else {
|
||||||
|
num = (uint) va_arg(args, uint);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (sz_ptr) {
|
||||||
|
num = (uintptr) va_arg(args, uintptr);
|
||||||
|
} else if (sz_long) {
|
||||||
|
num = (long) va_arg(args, long);
|
||||||
|
} else {
|
||||||
|
num = (int) va_arg(args, int);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* print num */
|
||||||
|
if (!usignf && (intmax) num < 0) {
|
||||||
|
num = -(intmax)num;
|
||||||
|
arch_putc('-');
|
||||||
|
}
|
||||||
|
|
||||||
|
len = _printu(nbuf, num, base, capf);
|
||||||
|
while (len) {
|
||||||
|
arch_putc(nbuf[len]);
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
ret += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ATTR_FMT_PRINTF int
|
||||||
|
kprintf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, str);
|
va_start(args, fmt);
|
||||||
kvprintf(str, args);
|
|
||||||
|
spin_lock_acq(&print_lock);
|
||||||
|
ret = _vprintf(fmt, args);
|
||||||
|
spin_lock_rel(&print_lock);
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
kvprintf(const char *str, va_list args)
|
kvprintf(const char *fmt, va_list args)
|
||||||
{
|
{
|
||||||
UNREFERENCED(str);
|
int ret;
|
||||||
UNREFERENCED(args);
|
|
||||||
arch_vprintf(str, args);
|
spin_lock_acq(&print_lock);
|
||||||
|
ret = _vprintf(fmt, args);
|
||||||
|
spin_lock_rel(&print_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,60 @@
|
|||||||
#include <kern/cdef.h>
|
#include <kern/cdef.h>
|
||||||
#include <kern/spin_lock.h>
|
#include <kern/spin_lock.h>
|
||||||
#include <arch/atomic.h>
|
|
||||||
|
|
||||||
void
|
static inline uint32
|
||||||
spin_init(struct spin_lock *lock)
|
_spin_lock_get_ticket(uint32 val)
|
||||||
{
|
{
|
||||||
if (lock != NULL)
|
return val & 0xFFFFu;
|
||||||
{
|
|
||||||
lock->val = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint32
|
||||||
void
|
_spin_lock_get_owner(uint32 val)
|
||||||
spin_lock(struct spin_lock *lock)
|
|
||||||
{
|
{
|
||||||
if (lock != NULL)
|
return val >> 16u;
|
||||||
{
|
|
||||||
while (arch_cmp_swp_32(&lock->val, 0, 1) != 0)
|
|
||||||
{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
spin_unlock(struct spin_lock *lock)
|
spin_lock_init(struct spin_lock *lock)
|
||||||
{
|
{
|
||||||
if (lock != NULL)
|
atomic_store(&lock->val, 0);
|
||||||
{
|
}
|
||||||
lock->val = 0;
|
|
||||||
}
|
void
|
||||||
|
spin_lock_acq(struct spin_lock *lock)
|
||||||
|
{
|
||||||
|
uint32 val;
|
||||||
|
|
||||||
|
do {
|
||||||
|
val = atomic_load(&lock->val);
|
||||||
|
} while (!atomic_compare_exchange_weak(&lock->val, &val, val + (1u << 16u)));
|
||||||
|
|
||||||
|
// val now contains cur ticket and target ticket
|
||||||
|
while (_spin_lock_get_ticket(val) != _spin_lock_get_owner(val)) {
|
||||||
|
val = atomic_load(&lock->val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// owner = ticket, we've acquired the lock
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
spin_lock_rel(struct spin_lock *lock)
|
||||||
|
{
|
||||||
|
// increment ticket
|
||||||
|
atomic_fetch_add(&lock->val, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
spin_lock_try_acq(struct spin_lock *lock)
|
||||||
|
{
|
||||||
|
uint32 val;
|
||||||
|
|
||||||
|
val = atomic_load(&lock->val);
|
||||||
|
|
||||||
|
if ((_spin_lock_get_owner(val) == _spin_lock_get_ticket(val)) &&
|
||||||
|
atomic_compare_exchange_weak(&lock->val, &val, val + (1u << 16u))) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
28
mm/balloc.c
28
mm/balloc.c
@ -1,28 +0,0 @@
|
|||||||
#include <mm/balloc.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <ke/clib.h>
|
|
||||||
#include <ke/bitmap.h>
|
|
||||||
|
|
||||||
// for each size
|
|
||||||
// we have - bitmap representing each frame_size
|
|
||||||
|
|
||||||
int32 balloc_init(struct balloc_desc* desc, void* start, usize length, usize frame_size)
|
|
||||||
{
|
|
||||||
// calculate size required
|
|
||||||
// calculate the # of levels
|
|
||||||
usize aligned_len = ALIGN(usize, length, frame_size);
|
|
||||||
usize total_frames = aligned_len / frame_size;
|
|
||||||
usize levels = (usize)ceil(log2(total_frames)) + 1; // include the 0th level
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void* balloc(struct balloc_desc* desc, usize num_frames)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void bfree(struct balloc_desc* desc, uintptr ptr)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
104
mm/ssalloc.c
104
mm/ssalloc.c
@ -1,104 +0,0 @@
|
|||||||
#include "kern/cdef.h"
|
|
||||||
#include "kern/mlayout.h"
|
|
||||||
#include "lb/dlist.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simplified Slab Allocator
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define LARGE_THRESHOLD (8)
|
|
||||||
|
|
||||||
struct ssalloc_page_desc
|
|
||||||
{
|
|
||||||
struct dlist_node node;
|
|
||||||
uint32 used_obj_num;
|
|
||||||
uint8 free_list[0]; /* free list inside each slab */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ssalloc_obj_desc
|
|
||||||
{
|
|
||||||
struct dlist free_list;
|
|
||||||
struct dlist full_list;
|
|
||||||
struct dlist empty_list;
|
|
||||||
usize obj_size;
|
|
||||||
uint32 align;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ssalloc_desc
|
|
||||||
{
|
|
||||||
uint32 chunk_size;
|
|
||||||
void* malloc_chunk(void); // allocate a chunk
|
|
||||||
void* free_chunk(void); // free a chunk
|
|
||||||
};
|
|
||||||
|
|
||||||
static void* scalloc_large(struct ssalloc_desc* desc, struct ssalloc_obj_desc* obj_desc)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void scfree_large(struct ssalloc_desc* desc, struct ssalloc_obj_desc* obj_desc, void* addr)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void* scalloc_small(struct ssalloc_desc* desc, struct ssalloc_obj_desc* obj_desc)
|
|
||||||
{
|
|
||||||
// check the current free list first
|
|
||||||
if (lb_dlist_size(&obj_desc->free_list) > 0)
|
|
||||||
{
|
|
||||||
// if it exists then we grab something from the list
|
|
||||||
struct llist_node* node = lb_dlist_first(node);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void scfree_small(struct ssalloc_desc* desc, struct ssalloc_obj_desc* obj_desc, void* addr)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ssalloc_desc_init(struct ssalloc_desc* desc)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ssalloc_obj_desc_init(struct ssalloc_obj_desc* obj_desc, usize obj_size, uint32 align)
|
|
||||||
{
|
|
||||||
obj_desc->obj_size = obj_size;
|
|
||||||
obj_desc->align = align;
|
|
||||||
lb_dlist_init(&obj_desc->empty_list);
|
|
||||||
lb_dlist_init(&obj_desc->full_list);
|
|
||||||
lb_dlist_init(&obj_desc->free_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* scalloc(struct ssalloc_desc* desc, struct ssalloc_obj_desc* obj_desc)
|
|
||||||
{
|
|
||||||
void* ret = NULL;
|
|
||||||
if(obj_desc->obj_size < desc->chunk_size / LARGE_THRESHOLD)
|
|
||||||
{
|
|
||||||
ret = scalloc_small(desc, obj_desc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// large objects
|
|
||||||
ret = scalloc_large(desc, obj_desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void scfree(struct ssalloc_desc* desc, struct ssalloc_obj_desc* obj_desc, void* address)
|
|
||||||
{
|
|
||||||
if(obj_desc->obj_size < desc->chunk_size)
|
|
||||||
{
|
|
||||||
scfree_small(desc, obj_desc, address);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// large objects
|
|
||||||
scfree_large(desc, obj_desc, address);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
set timeout=0
|
set timeout=0
|
||||||
set default=0
|
set default=0
|
||||||
|
|
||||||
menuentry "fusion" {
|
menuentry "bond" {
|
||||||
multiboot2 fusion.elf
|
multiboot2 bond.elf
|
||||||
}
|
}
|
@ -11,21 +11,4 @@ SECTIONS
|
|||||||
{
|
{
|
||||||
*(.multiboot_header)
|
*(.multiboot_header)
|
||||||
}
|
}
|
||||||
|
|
||||||
.text ALIGN(KERNEL_PAGE_SIZE) : AT(ADDR(.text) - KERNEL_IMG_VADDR)
|
|
||||||
{
|
|
||||||
*(.text)
|
|
||||||
}
|
|
||||||
|
|
||||||
.data ALIGN(KERNEL_PAGE_SIZE) : AT(ADDR(.data) - KERNEL_IMG_VADDR)
|
|
||||||
{
|
|
||||||
*(.data)
|
|
||||||
*(.rodata*)
|
|
||||||
}
|
|
||||||
|
|
||||||
.bss ALIGN(KERNEL_PAGE_SIZE) : AT(ADDR(.bss) - KERNEL_IMG_VADDR)
|
|
||||||
{
|
|
||||||
*(.bss)
|
|
||||||
*(COMMON)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
10
test/CMakeLists.txt
Normal file
10
test/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
set(SUBMODULE test)
|
||||||
|
set(CC_SRC
|
||||||
|
avl_test.c
|
||||||
|
list_test.c
|
||||||
|
ktest.c
|
||||||
|
qsort_test.c
|
||||||
|
)
|
||||||
|
|
||||||
|
include(${MK}/kern.cmake)
|
||||||
|
|
1002
test/atree_test.c
1002
test/atree_test.c
File diff suppressed because it is too large
Load Diff
979
test/avl_test.c
Normal file
979
test/avl_test.c
Normal file
@ -0,0 +1,979 @@
|
|||||||
|
#include <kern/cdef.h>
|
||||||
|
#include <kern/libkern.h>
|
||||||
|
#include <kern/avl_tree.h>
|
||||||
|
#include <test/ktest.h>
|
||||||
|
#include <kern/brute.h>
|
||||||
|
|
||||||
|
struct test_node {
|
||||||
|
struct avl_node tree_entry;
|
||||||
|
int32 val;
|
||||||
|
} test_node;
|
||||||
|
|
||||||
|
#define AVL_BRUTE_TEST_NODE 1024
|
||||||
|
#define AVL_MAX_TEST_NODE (AVL_BRUTE_TEST_NODE + 512)
|
||||||
|
|
||||||
|
static struct test_node avl_alloc_nodes[AVL_MAX_TEST_NODE];
|
||||||
|
static int avl_alloc_idx = 0;
|
||||||
|
|
||||||
|
static struct test_node *
|
||||||
|
create_test_node(int val)
|
||||||
|
{
|
||||||
|
KASSERT(avl_alloc_idx < AVL_MAX_TEST_NODE, "node allocation overflow");
|
||||||
|
|
||||||
|
struct test_node *rs = &avl_alloc_nodes[avl_alloc_idx++];
|
||||||
|
rs->val = val;
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
test_node_compare(struct avl_node *root, struct avl_node *node)
|
||||||
|
{
|
||||||
|
struct test_node *tree_node = OBTAIN_STRUCT_ADDR(root, struct test_node, tree_entry);
|
||||||
|
struct test_node *self = OBTAIN_STRUCT_ADDR(node, struct test_node, tree_entry);
|
||||||
|
return tree_node->val - self->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pre_order_print(struct avl_node *node)
|
||||||
|
{
|
||||||
|
if (node == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct test_node *t_node = OBTAIN_STRUCT_ADDR(node, struct test_node, tree_entry);
|
||||||
|
kprintf("%d-", t_node->val);
|
||||||
|
pre_order_print(node->left);
|
||||||
|
pre_order_print(node->right);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ATTR_UNUSED
|
||||||
|
pre_order(struct avl_node *node)
|
||||||
|
{
|
||||||
|
pre_order_print(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_pre_order_assert(struct avl_node *node, const int *order, int size, int *counter)
|
||||||
|
{
|
||||||
|
if (node == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (*counter >= size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = 1;
|
||||||
|
struct test_node *t_node = OBTAIN_STRUCT_ADDR(node, struct test_node, tree_entry);
|
||||||
|
if (order[*counter] != t_node->val) {
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
(*counter)++;
|
||||||
|
result = result && _pre_order_assert(node->left, order, size, counter);
|
||||||
|
result = result && _pre_order_assert(node->right, order, size, counter);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pre_order_assert(struct avl_root *tree, int order[], int size)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int counter = 0;
|
||||||
|
|
||||||
|
ret = _pre_order_assert(tree->root, order, size, &counter);
|
||||||
|
#ifdef TDBG
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
printf("[AVL ASSERT] Expected: ");
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
printf("%d-", order[i]);
|
||||||
|
}
|
||||||
|
printf("\n Got:");
|
||||||
|
pre_order(tree->root);
|
||||||
|
printf("\n");
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_simple_l(void)
|
||||||
|
{
|
||||||
|
//1 2
|
||||||
|
// \ / \
|
||||||
|
// 2 == 1L ==> 1 3
|
||||||
|
// \
|
||||||
|
// 3
|
||||||
|
ktest_begin("insert_simple_l");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(1)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(2)->tree_entry);
|
||||||
|
int val1[] = {1, 2};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 2), "insert_simple_l_1");
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(3)->tree_entry);
|
||||||
|
int val2[] = {2, 1, 3};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 3), "insert_simple_l_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_simple_r(void)
|
||||||
|
{
|
||||||
|
// 3 2
|
||||||
|
// / / \
|
||||||
|
// 2 == 1R ==> 1 3
|
||||||
|
// /
|
||||||
|
//1
|
||||||
|
ktest_begin("insert_simple_r");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(3)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(2)->tree_entry);
|
||||||
|
int val1[] = {3, 2};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 2), "insert_simple_r_1");
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(1)->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {2, 1, 3};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 3), "insert_simple_r_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_simple_ll(void)
|
||||||
|
{
|
||||||
|
//2 3
|
||||||
|
// \ / \
|
||||||
|
// 4 == 2L ==> 2 4
|
||||||
|
// /
|
||||||
|
//3
|
||||||
|
ktest_begin("insert_simple_ll");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(2)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(4)->tree_entry);
|
||||||
|
int val1[] = {2, 4};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 2), "insert_simple_ll_1");
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(3)->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {3, 2, 4};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 3), "insert_simple_ll_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_simple_rr(void)
|
||||||
|
{
|
||||||
|
// 4 3
|
||||||
|
// / / \
|
||||||
|
//2 == 2R ==> 2 4
|
||||||
|
// \
|
||||||
|
// 3
|
||||||
|
ktest_begin("insert_simple_rr");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(4)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(2)->tree_entry);
|
||||||
|
int val1[] = {4, 2};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 2), "insert_simple_rr_1");
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(3)->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {3, 2, 4};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 3), "insert_simple_rr_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_complex_1(void)
|
||||||
|
{
|
||||||
|
// 20+ 20++ 20++ 9
|
||||||
|
// / \ / \ / \ / \
|
||||||
|
// 4 26 => 4- 26 => 9+ 26 => 4+ 20
|
||||||
|
// / \ / \ / \ / / \
|
||||||
|
//3 9 3 9- 4+ 15 3 15 26
|
||||||
|
// \ /
|
||||||
|
// 15 3
|
||||||
|
ktest_begin("insert_complex_1");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(20)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(4)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(26)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(3)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(9)->tree_entry);
|
||||||
|
int val1[] = {20, 4, 3, 9, 26};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 5), "insert_complex_1_1");
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(15)->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {9, 4, 3, 20, 15, 26};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 6), "insert_complex_1_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_complex_2(void)
|
||||||
|
{
|
||||||
|
// 20+ 20++ 20++ 9
|
||||||
|
// / \ / \ / \ / \
|
||||||
|
// 4 26 => 4- 26 => 9++ 26 => 4 20-
|
||||||
|
// / \ / \ / / \ \
|
||||||
|
//3 9 3 9+ 4 3 8 26
|
||||||
|
// / / \
|
||||||
|
// 8 3 8
|
||||||
|
ktest_begin("insert_complex_2");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(20)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(4)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(26)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(3)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(9)->tree_entry);
|
||||||
|
int val1[] = {20, 4, 3, 9, 26};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 5), "insert_complex_2_1");
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(8)->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {9, 4, 3, 8, 20, 26};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 6), "insert_complex_2_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_complex_3(void)
|
||||||
|
{
|
||||||
|
// __20+__ _20++_ __20++_ ___9___
|
||||||
|
// / \ / \ / \ / \
|
||||||
|
// 4 26 => 4- 26 => 9+ 26 => 4+ __20__
|
||||||
|
// / \ / \ / \ / \ / \ / \ / \ / \
|
||||||
|
// 3+ 9 21 30 3+ 9- 21 30 4+ 11- 21 30 3+ 7 11- 26
|
||||||
|
// / / \ / / \ / \ \ / \ / \
|
||||||
|
//2 7 11 2 7 11- 3+ 7 15 2 15 21 30
|
||||||
|
// \ /
|
||||||
|
// 15 2
|
||||||
|
ktest_begin("insert_complex_3");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(20)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(4)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(26)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(3)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(9)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(21)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(30)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(2)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(7)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(11)->tree_entry);
|
||||||
|
int val1[] = {20, 4, 3, 2, 9, 7, 11, 26, 21, 30};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 10), "insert_complex_3_1");
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(15)->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {9, 4, 3, 2, 7, 20, 11, 15, 26, 21, 30};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 11), "insert_complex_3_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_complex_4(void)
|
||||||
|
{
|
||||||
|
// __20+__ _20++_ __20++_ ___9___
|
||||||
|
// / \ / \ / \ / \
|
||||||
|
// 4 26 4- 26 9+ 26 4 _20-
|
||||||
|
// / \ / \ / \ / \ / \ / \ / \ / \
|
||||||
|
// 3+ 9 21 30 => 3+ 9+ 21 30 => 4 11 21 30 => 3+ 7- 11 26
|
||||||
|
// / / \ / / \ / \ / \ / \
|
||||||
|
//2 7 11 2 7- 11 3+ 7- 2 8 21 30
|
||||||
|
// \ / \
|
||||||
|
// 8 2 8
|
||||||
|
ktest_begin("insert_complex_4");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(20)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(4)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(26)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(3)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(9)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(21)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(30)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(2)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(7)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(11)->tree_entry);
|
||||||
|
int val1[] = {20, 4, 3, 2, 9, 7, 11, 26, 21, 30};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 10), "insert_complex_4_1");
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(8)->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {9, 4, 3, 2, 7, 8, 20, 11, 26, 21, 30};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 11), "insert_complex_4_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_duplicate(void)
|
||||||
|
{
|
||||||
|
// __20+__ _20++_ __20++_ ___9___
|
||||||
|
// / \ / \ / \ / \
|
||||||
|
// 4 26 4- 26 9+ 26 4 _20-
|
||||||
|
// / \ / \ / \ / \ / \ / \ / \ / \
|
||||||
|
// 3+ 9 21 30 => 3+ 9+ 21 30 => 4 11 21 30 => 3+ 7- 11 26
|
||||||
|
// / / \ / / \ / \ / \ / \
|
||||||
|
//2 7 11 2 7- 11 3+ 7- 2 8 21 30
|
||||||
|
// \ / \
|
||||||
|
// 8 2 8
|
||||||
|
ktest_begin("insert_duplicate");
|
||||||
|
struct avl_root tree;
|
||||||
|
struct test_node *temp, *temp20, *temp30, *temp7, *temp2;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
temp20 = create_test_node(20);
|
||||||
|
temp30 = create_test_node(30);
|
||||||
|
temp7 = create_test_node(7);
|
||||||
|
temp2 = create_test_node(2);
|
||||||
|
|
||||||
|
avl_insert(&tree, &temp20->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(4)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(26)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(3)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(9)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(21)->tree_entry);
|
||||||
|
avl_insert(&tree, &temp30->tree_entry);
|
||||||
|
avl_insert(&tree, &temp2->tree_entry);
|
||||||
|
avl_insert(&tree, &temp7->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(11)->tree_entry);
|
||||||
|
int val1[] = {20, 4, 3, 2, 9, 7, 11, 26, 21, 30};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 10), "insert_duplicate_1");
|
||||||
|
|
||||||
|
// should return the value being overwritten
|
||||||
|
temp = OBTAIN_STRUCT_ADDR(avl_insert(&tree, &create_test_node(20)->tree_entry), struct test_node, tree_entry);
|
||||||
|
KASSERT((temp == temp20), "insert_duplicate_2");
|
||||||
|
temp = OBTAIN_STRUCT_ADDR(avl_insert(&tree, &create_test_node(30)->tree_entry), struct test_node, tree_entry);
|
||||||
|
KASSERT((temp == temp30), "insert_duplicate_3");
|
||||||
|
temp = OBTAIN_STRUCT_ADDR(avl_insert(&tree, &create_test_node(7)->tree_entry), struct test_node, tree_entry);
|
||||||
|
KASSERT((temp == temp7), "insert_duplicate_4");
|
||||||
|
temp = OBTAIN_STRUCT_ADDR(avl_insert(&tree, &create_test_node(2)->tree_entry), struct test_node, tree_entry);
|
||||||
|
KASSERT((temp == temp2), "insert_duplicate_5");
|
||||||
|
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 10), "insert_duplicate_6");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_simple_l(void)
|
||||||
|
{
|
||||||
|
// 2 3
|
||||||
|
// x \ / \
|
||||||
|
//1 3 == 1L ==> 2 4
|
||||||
|
// \
|
||||||
|
// 4
|
||||||
|
ktest_begin("delete_simple_l");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
struct test_node *deleted = create_test_node(1);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(2)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(3)->tree_entry);
|
||||||
|
avl_insert(&tree, &deleted->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(4)->tree_entry);
|
||||||
|
int val1[] = {2, 1, 3, 4};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 4), "delete_simple_l_1");
|
||||||
|
|
||||||
|
avl_remove(&tree, &deleted->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {3, 2, 4};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 3), "delete_simple_l_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_simple_r(void)
|
||||||
|
{
|
||||||
|
// 3 2
|
||||||
|
// / x / \
|
||||||
|
// 2 4 == 1R ==> 1 3
|
||||||
|
// /
|
||||||
|
//1
|
||||||
|
ktest_begin("delete_simple_r");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
struct test_node *deleted = create_test_node(4);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(3)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(2)->tree_entry);
|
||||||
|
avl_insert(&tree, &deleted->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(1)->tree_entry);
|
||||||
|
int val1[] = {3, 2, 1, 4};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 4), "delete_simple_r_1");
|
||||||
|
|
||||||
|
avl_remove(&tree, &deleted->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {2, 1, 3};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 3), "delete_simple_r_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_simple_ll(void)
|
||||||
|
{
|
||||||
|
// 2 3
|
||||||
|
// x \ / \
|
||||||
|
//1 4 == 2L ==> 2 4
|
||||||
|
// /
|
||||||
|
// 3
|
||||||
|
ktest_begin("delete_simple_ll");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
struct test_node *deleted = create_test_node(1);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(2)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(4)->tree_entry);
|
||||||
|
avl_insert(&tree, &deleted->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(3)->tree_entry);
|
||||||
|
int val1[] = {2, 1, 4, 3};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 4), "delete_simple_ll_1");
|
||||||
|
|
||||||
|
avl_remove(&tree, &deleted->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {3, 2, 4};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 3), "delete_simple_ll_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_simple_rr(void)
|
||||||
|
{
|
||||||
|
// 3 2
|
||||||
|
// / x / \
|
||||||
|
//2 4 == 2R ==> 1 3
|
||||||
|
// \
|
||||||
|
// 1
|
||||||
|
ktest_begin("delete_simple_rr");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
struct test_node *deleted = create_test_node(4);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(3)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(2)->tree_entry);
|
||||||
|
avl_insert(&tree, &deleted->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(1)->tree_entry);
|
||||||
|
int val1[] = {3, 2, 1, 4};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 4), "delete_simple_rr_1" );
|
||||||
|
|
||||||
|
avl_remove(&tree, &deleted->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {2, 1, 3};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 3), "delete_simple_rr_2" );
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_complex_1(void)
|
||||||
|
{
|
||||||
|
// Test Case #1
|
||||||
|
// - A single node tree has its only node removed.
|
||||||
|
// Create:
|
||||||
|
// 10
|
||||||
|
//
|
||||||
|
// Call: remove(10)
|
||||||
|
//
|
||||||
|
// Result:
|
||||||
|
// empty tree
|
||||||
|
ktest_begin("delete_complex_1");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
struct test_node *deleted = create_test_node(10);
|
||||||
|
|
||||||
|
avl_insert(&tree, &deleted->tree_entry);
|
||||||
|
int val1[] = {10};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 1), "delete_complex_1_1");
|
||||||
|
|
||||||
|
avl_remove(&tree, &deleted->tree_entry);
|
||||||
|
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 0), "delete_complex_1_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_complex_2(void)
|
||||||
|
{
|
||||||
|
// Test Case #2
|
||||||
|
// - A small tree has its root removed.
|
||||||
|
// Create:
|
||||||
|
// 20
|
||||||
|
// / \
|
||||||
|
// 10 30
|
||||||
|
// / \
|
||||||
|
// 25 35
|
||||||
|
//
|
||||||
|
// Call: remove(20)
|
||||||
|
//
|
||||||
|
// Results: (simplest result with no rotations)
|
||||||
|
// (replace root with smallest value on the treenode or 25)
|
||||||
|
//
|
||||||
|
// 25
|
||||||
|
// / \
|
||||||
|
// 10 30
|
||||||
|
// \
|
||||||
|
// 35
|
||||||
|
//
|
||||||
|
ktest_begin("delete_complex_2");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
struct test_node *deleted = create_test_node(20);
|
||||||
|
|
||||||
|
avl_insert(&tree, &deleted->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(10)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(30)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(25)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(35)->tree_entry);
|
||||||
|
int val1[] = {20, 10, 30, 25, 35};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 5), "delete_complex_2_1");
|
||||||
|
|
||||||
|
avl_remove(&tree, &deleted->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {25, 10, 30, 35};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 4), "delete_complex_2_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_complex_3(void)
|
||||||
|
{
|
||||||
|
// Test Case #3
|
||||||
|
// - A small tree has a node with 2 children removed
|
||||||
|
// 20
|
||||||
|
// / \
|
||||||
|
// 10 30
|
||||||
|
// / \ /
|
||||||
|
// 5 15 25
|
||||||
|
//
|
||||||
|
// Call: remove(10)
|
||||||
|
//
|
||||||
|
// Results:
|
||||||
|
// 20
|
||||||
|
// / \
|
||||||
|
// 15 30
|
||||||
|
// / /
|
||||||
|
// 5 25
|
||||||
|
ktest_begin("delete_complex_3");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
struct test_node *deleted = create_test_node(10);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(20)->tree_entry);
|
||||||
|
avl_insert(&tree, &deleted->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(30)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(5)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(15)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(25)->tree_entry);
|
||||||
|
int val1[] = {20, 10, 5, 15, 30, 25};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 6), "delete_complex_3_1");
|
||||||
|
|
||||||
|
avl_remove(&tree, &deleted->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {20, 15, 5, 30, 25};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 5), "delete_complex_3_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_complex_4(void)
|
||||||
|
{
|
||||||
|
// Test Case #4
|
||||||
|
// - A small tree has all nodes but the root removed from the bottom up.
|
||||||
|
// Create:
|
||||||
|
// 20
|
||||||
|
// / \
|
||||||
|
// 10 30
|
||||||
|
// / \ /
|
||||||
|
// 5 15 25
|
||||||
|
//
|
||||||
|
// Call: remove(5), remove(15), remove(25), remove(10), remove(30)
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Results:
|
||||||
|
// 20
|
||||||
|
//
|
||||||
|
ktest_begin("delete_complex_4");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
struct test_node *delete5 = create_test_node(5);
|
||||||
|
struct test_node *delete10 = create_test_node(10);
|
||||||
|
struct test_node *delete15 = create_test_node(15);
|
||||||
|
struct test_node *delete25 = create_test_node(25);
|
||||||
|
struct test_node *delete30 = create_test_node(30);
|
||||||
|
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(20)->tree_entry);
|
||||||
|
avl_insert(&tree, &delete10->tree_entry);
|
||||||
|
avl_insert(&tree, &delete30->tree_entry);
|
||||||
|
avl_insert(&tree, &delete5->tree_entry);
|
||||||
|
avl_insert(&tree, &delete15->tree_entry);
|
||||||
|
avl_insert(&tree, &delete25->tree_entry);
|
||||||
|
|
||||||
|
int val1[] = {20, 10, 5, 15, 30, 25};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 6), "delete_complex_4_1");
|
||||||
|
|
||||||
|
avl_remove(&tree, &delete5->tree_entry);
|
||||||
|
avl_remove(&tree, &delete15->tree_entry);
|
||||||
|
avl_remove(&tree, &delete25->tree_entry);
|
||||||
|
avl_remove(&tree, &delete10->tree_entry);
|
||||||
|
avl_remove(&tree, &delete30->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {20};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 1), "delete_complex_4_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_complex_single_rotation(void)
|
||||||
|
{
|
||||||
|
// Test case single rotation
|
||||||
|
//
|
||||||
|
// Create:
|
||||||
|
//
|
||||||
|
// 20
|
||||||
|
// / \
|
||||||
|
// 10 30
|
||||||
|
// / \ / \
|
||||||
|
// 5 15 25 40
|
||||||
|
// / / / \
|
||||||
|
// 12 22 35 50
|
||||||
|
// /
|
||||||
|
// 31
|
||||||
|
//
|
||||||
|
// Call: remove(50)
|
||||||
|
//
|
||||||
|
// 20
|
||||||
|
// / \
|
||||||
|
// 10 30
|
||||||
|
// / \ / \
|
||||||
|
// 5 15 25 35
|
||||||
|
// / / / \
|
||||||
|
// 12 22 31 40
|
||||||
|
//
|
||||||
|
//
|
||||||
|
ktest_begin("delete_complex_single_rotation");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
struct test_node *deleted = create_test_node(50);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(20)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(10)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(30)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(5)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(15)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(25)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(40)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(12)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(22)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(35)->tree_entry);
|
||||||
|
avl_insert(&tree, &deleted->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(31)->tree_entry);
|
||||||
|
int val1[] = {20, 10, 5, 15, 12, 30, 25, 22, 40, 35, 31, 50};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 12), "delete_complex_single_rotation_1");
|
||||||
|
|
||||||
|
avl_remove(&tree, &deleted->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {20, 10, 5, 15, 12, 30, 25, 22, 35, 31, 40};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 11), "delete_complex_single_rotation_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_complex_double_rotation(void)
|
||||||
|
{
|
||||||
|
// Test case double rotation
|
||||||
|
//
|
||||||
|
// Create:
|
||||||
|
//
|
||||||
|
// 20
|
||||||
|
// / \
|
||||||
|
// 10 30
|
||||||
|
// / \ / \
|
||||||
|
// 5 15 25 40
|
||||||
|
// / / / \
|
||||||
|
// 12 22 35 50
|
||||||
|
// /
|
||||||
|
// 31
|
||||||
|
//
|
||||||
|
// Call: remove(22)
|
||||||
|
//
|
||||||
|
// 20
|
||||||
|
// / \
|
||||||
|
// 10 35
|
||||||
|
// / \ / \
|
||||||
|
// 5 15 30 40
|
||||||
|
// / / \ \
|
||||||
|
// 12 25 31 50
|
||||||
|
//
|
||||||
|
//
|
||||||
|
ktest_begin("delete_complex_double_rotation");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
struct test_node *deleted = create_test_node(22);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(20)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(10)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(30)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(5)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(15)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(25)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(40)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(12)->tree_entry);
|
||||||
|
avl_insert(&tree, &deleted->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(35)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(50)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(31)->tree_entry);
|
||||||
|
int val1[] = {20, 10, 5, 15, 12, 30, 25, 22, 40, 35, 31, 50};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 12), "delete_complex_double_rotation_1");
|
||||||
|
|
||||||
|
avl_remove(&tree, &deleted->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {20, 10, 5, 15, 12, 35, 30, 25, 31, 40, 50};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 11), "delete_complex_double_rotation_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_complex_multiple_rotation(void)
|
||||||
|
{
|
||||||
|
// Test case multiple rotation
|
||||||
|
//
|
||||||
|
// Create:
|
||||||
|
// 20
|
||||||
|
// / \
|
||||||
|
// 10 30
|
||||||
|
// / \ / \
|
||||||
|
// 5 15 25 40
|
||||||
|
// / / / \
|
||||||
|
// 12 22 35 50
|
||||||
|
// /
|
||||||
|
// 31
|
||||||
|
//
|
||||||
|
// Call: remove(5)
|
||||||
|
//
|
||||||
|
// Results:
|
||||||
|
// 30
|
||||||
|
// / \
|
||||||
|
// 20 40
|
||||||
|
// / \ / \
|
||||||
|
// 12 25 35 50
|
||||||
|
// / \ / /
|
||||||
|
// 10 15 22 31
|
||||||
|
//
|
||||||
|
//
|
||||||
|
ktest_begin("delete_complex_multiple_rotation");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
struct test_node *deleted = create_test_node(5);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(20)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(10)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(30)->tree_entry);
|
||||||
|
avl_insert(&tree, &deleted->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(15)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(25)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(40)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(12)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(22)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(35)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(50)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(31)->tree_entry);
|
||||||
|
int val1[] = {20, 10, 5, 15, 12, 30, 25, 22, 40, 35, 31, 50};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 12), "delete_complex_multiple_rotation_1");
|
||||||
|
|
||||||
|
avl_remove(&tree, &deleted->tree_entry);
|
||||||
|
|
||||||
|
int val2[] = {30, 20, 12, 10, 15, 25, 22, 40, 35, 31, 50};
|
||||||
|
KASSERT(pre_order_assert(&tree, val2, 11), "delete_complex_multiple_rotation_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_DNE(void)
|
||||||
|
{
|
||||||
|
// Test case DNE
|
||||||
|
// Delete a node that does not exist
|
||||||
|
// 20
|
||||||
|
// / \
|
||||||
|
// 10 30
|
||||||
|
// / \ /
|
||||||
|
// 5 15 25
|
||||||
|
//
|
||||||
|
// Call: remove(100), remove(24)
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Results:
|
||||||
|
// 20
|
||||||
|
// / \
|
||||||
|
// 10 30
|
||||||
|
// / \ /
|
||||||
|
// 5 15 25
|
||||||
|
//
|
||||||
|
ktest_begin("delete_DNE");
|
||||||
|
struct avl_root tree;
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
struct test_node *delete100 = create_test_node(100);
|
||||||
|
struct test_node *delete24 = create_test_node(24);
|
||||||
|
|
||||||
|
avl_insert(&tree, &create_test_node(20)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(10)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(30)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(5)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(15)->tree_entry);
|
||||||
|
avl_insert(&tree, &create_test_node(25)->tree_entry);
|
||||||
|
|
||||||
|
int val1[] = {20, 10, 5, 15, 30, 25};
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 6), "delete_DNE_1");
|
||||||
|
|
||||||
|
avl_remove(&tree, &delete24->tree_entry);
|
||||||
|
avl_remove(&tree, &delete100->tree_entry);
|
||||||
|
KASSERT(pre_order_assert(&tree, val1, 6), "delete_DNE_2");
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_apocalypse(void)
|
||||||
|
{
|
||||||
|
struct avl_root tree;
|
||||||
|
|
||||||
|
ktest_begin("test_apocalypse");
|
||||||
|
|
||||||
|
ksrand(1337523847);
|
||||||
|
|
||||||
|
avl_init(&tree, test_node_compare);
|
||||||
|
|
||||||
|
// insert test
|
||||||
|
for (int i = 0; i < AVL_BRUTE_TEST_NODE; i++) {
|
||||||
|
avl_alloc_nodes[i].val = krand();
|
||||||
|
while (avl_search(&tree, &avl_alloc_nodes[i].tree_entry) != NULL) {
|
||||||
|
avl_alloc_nodes[i].val += krand() % 32765;
|
||||||
|
}
|
||||||
|
avl_insert(&tree, &avl_alloc_nodes[i].tree_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// integrity test
|
||||||
|
KASSERT(avl_validate(&tree), "validate");
|
||||||
|
KASSERT(avl_size(&tree) == AVL_BRUTE_TEST_NODE, "test_apo_sz_1");
|
||||||
|
|
||||||
|
// smaller and bigger test
|
||||||
|
struct avl_node *entry = avl_first(&tree);
|
||||||
|
uint32 size = 0;
|
||||||
|
int32 prev = -1;
|
||||||
|
int32 cur = OBTAIN_STRUCT_ADDR(entry, struct test_node, tree_entry)->val;
|
||||||
|
while (entry != NULL) {
|
||||||
|
if (cur < prev) {
|
||||||
|
KASSERT(0, "test_apo_order_1");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
size++;
|
||||||
|
entry = avl_next(&tree, entry);
|
||||||
|
prev = cur;
|
||||||
|
if (entry != NULL) {
|
||||||
|
cur = OBTAIN_STRUCT_ADDR(entry, struct test_node, tree_entry)->val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KASSERT(size == AVL_BRUTE_TEST_NODE, "test_apo_1");
|
||||||
|
|
||||||
|
// larger test
|
||||||
|
entry = avl_last(&tree);
|
||||||
|
size = 0;
|
||||||
|
cur = OBTAIN_STRUCT_ADDR(entry, struct test_node, tree_entry)->val;
|
||||||
|
prev = cur;
|
||||||
|
while (entry != NULL) {
|
||||||
|
if (cur > prev) {
|
||||||
|
KASSERT(0, "test_apo_order_1");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
size++;
|
||||||
|
entry = avl_prev(&tree, entry);
|
||||||
|
prev = cur;
|
||||||
|
if (entry != NULL) {
|
||||||
|
cur = OBTAIN_STRUCT_ADDR(entry, struct test_node, tree_entry)->val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KASSERT(size == AVL_BRUTE_TEST_NODE, "test_apo_2");
|
||||||
|
|
||||||
|
|
||||||
|
// delete and search test
|
||||||
|
for (int i = 0; i < AVL_BRUTE_TEST_NODE; i++) {
|
||||||
|
KASSERT((avl_search(&tree, &avl_alloc_nodes[i].tree_entry) != NULL), "test_apo_search_1");
|
||||||
|
avl_remove(&tree, &avl_alloc_nodes[i].tree_entry);
|
||||||
|
KASSERT((avl_search(&tree, &avl_alloc_nodes[i].tree_entry) == NULL), "test_apo_search_2");
|
||||||
|
KASSERT(avl_validate(&tree), "test_apo_validate_2");
|
||||||
|
}
|
||||||
|
|
||||||
|
KASSERT((avl_size(&tree) == 0), "test_apo_sz_2");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
avl_tree_test(ATTR_UNUSED void *unused)
|
||||||
|
{
|
||||||
|
insert_simple_l();
|
||||||
|
insert_simple_r();
|
||||||
|
insert_simple_ll();
|
||||||
|
insert_simple_rr();
|
||||||
|
|
||||||
|
// complex ones
|
||||||
|
insert_complex_1();
|
||||||
|
insert_complex_2();
|
||||||
|
insert_complex_3();
|
||||||
|
insert_complex_4();
|
||||||
|
|
||||||
|
// insert duplicate
|
||||||
|
insert_duplicate();
|
||||||
|
|
||||||
|
// simple tests
|
||||||
|
delete_simple_l();
|
||||||
|
delete_simple_r();
|
||||||
|
delete_simple_ll();
|
||||||
|
delete_simple_rr();
|
||||||
|
|
||||||
|
// complex tests
|
||||||
|
delete_complex_1();
|
||||||
|
delete_complex_2();
|
||||||
|
delete_complex_3();
|
||||||
|
delete_complex_4();
|
||||||
|
delete_complex_single_rotation();
|
||||||
|
delete_complex_double_rotation();
|
||||||
|
delete_complex_multiple_rotation();
|
||||||
|
delete_DNE();
|
||||||
|
|
||||||
|
/* clear all memory */
|
||||||
|
test_apocalypse();
|
||||||
|
}
|
||||||
|
|
||||||
|
KTEST_DECL(avl_tree, KTEST_SUBSYS_AVL, avl_tree_test, NULL);
|
||||||
|
|
@ -1,15 +0,0 @@
|
|||||||
#ifndef TEST_TEST_H
|
|
||||||
#define TEST_TEST_H
|
|
||||||
|
|
||||||
#include "kern/cdef.h"
|
|
||||||
|
|
||||||
void
|
|
||||||
linked_list_test(void);
|
|
||||||
|
|
||||||
void
|
|
||||||
avl_tree_test(void);
|
|
||||||
|
|
||||||
void
|
|
||||||
salloc_test(void);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,18 +0,0 @@
|
|||||||
#ifndef TEST_DRIVER_H
|
|
||||||
#define TEST_DRIVER_H
|
|
||||||
|
|
||||||
#include "kern/cdef.h"
|
|
||||||
|
|
||||||
void
|
|
||||||
test_begin(char *name);
|
|
||||||
|
|
||||||
void
|
|
||||||
test_end(void);
|
|
||||||
|
|
||||||
void *
|
|
||||||
talloc(uint32 size);
|
|
||||||
|
|
||||||
void
|
|
||||||
run_case(char *name, bool result);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,73 +0,0 @@
|
|||||||
#include "kern/cdef.h"
|
|
||||||
#include "hal.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bogus implementation of HAL
|
|
||||||
*/
|
|
||||||
int32 KABI
|
|
||||||
hal_atomic_xchg_32(int32 *target, int32 val)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int32 KABI
|
|
||||||
hal_atomic_inc_32(int32 *target, int32 increment)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 KABI
|
|
||||||
hal_atomic_cmpxchg_32(int32 *target, int32 compare, int32 val)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 KABI
|
|
||||||
hal_set_irql(uint32 irql)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 KABI
|
|
||||||
hal_get_irql(void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KABI
|
|
||||||
hal_issue_intr(uint32 core, uint32 vector)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void KABI
|
|
||||||
hal_reg_intr(uint32 index, k_intr_dispatcher handler)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void KABI
|
|
||||||
hal_dereg_intr(uint32 index)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void KABI
|
|
||||||
hal_reg_exc(uint32 exc, k_exc_dispatcher handler)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void KABI
|
|
||||||
hal_dereg_exc(uint32 exc)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 KABI
|
|
||||||
hal_get_core_id(void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KABI
|
|
||||||
hal_halt(void)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
35
test/ktest.c
Normal file
35
test/ktest.c
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include <test/ktest.h>
|
||||||
|
#include <kern/cdef.h>
|
||||||
|
#include <kern/print.h>
|
||||||
|
#include <kern/kinit.h>
|
||||||
|
|
||||||
|
static uint ktest_cases = 0;
|
||||||
|
|
||||||
|
static void
|
||||||
|
ktest_reset()
|
||||||
|
{
|
||||||
|
ktest_cases = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ktest_begin(const char* name)
|
||||||
|
{
|
||||||
|
kprintf(" Running test %d: %s...", ktest_cases, name);
|
||||||
|
ktest_cases++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ktest_main(ATTR_UNUSED void* args)
|
||||||
|
{
|
||||||
|
kprintf("Running ktest test suite...\n\n");
|
||||||
|
// run all ktests XXX: we don't care about priority for now as qsort is part of the test
|
||||||
|
for(struct ktest **it = KTEST_START; it < KTEST_STOP; it++) {
|
||||||
|
ktest_reset();
|
||||||
|
kprintf("Testing subsystem %s...\n", (*it)->name);
|
||||||
|
(*it)->func((*it)->args);
|
||||||
|
kprintf("%d test cases passed.\n\n", ktest_cases);
|
||||||
|
}
|
||||||
|
kprintf("All tests completed.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
KINIT_DECL(ktest, KINIT_SUBSYS_KTEST, 0, ktest_main, NULL);
|
274
test/list_test.c
Normal file
274
test/list_test.c
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
#include <test/ktest.h>
|
||||||
|
#include <kern/cdef.h>
|
||||||
|
#include <kern/list.h>
|
||||||
|
#include <kern/libkern.h>
|
||||||
|
|
||||||
|
#define ARR_SZ(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
|
|
||||||
|
struct test_list_node {
|
||||||
|
struct list_entry lnode;
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
validate_list(struct list_entry *list)
|
||||||
|
{
|
||||||
|
if (list_empty(list)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
KASSERT(!(list->prev == NULL || list->next == NULL), "list head ptr corrupted");
|
||||||
|
|
||||||
|
struct list_entry *it;
|
||||||
|
LIST_FOREACH(list, it) {
|
||||||
|
KASSERT(it->next->prev == it && it->prev->next == it, "forward list entry ptr corrupted");
|
||||||
|
}
|
||||||
|
|
||||||
|
LIST_FOREACH_REVERSE(list, it) {
|
||||||
|
KASSERT(it->next->prev == it && it->prev->next == it, "backward list entry ptr corrupted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//static void
|
||||||
|
//print_list(struct list_entry *list)
|
||||||
|
//{
|
||||||
|
// struct list_entry *e;
|
||||||
|
//
|
||||||
|
// LIST_FOREACH(list, e) {
|
||||||
|
// struct test_list_node *enode = OBTAIN_STRUCT_ADDR(e, struct test_list_node, lnode);
|
||||||
|
// kprintf("%d->", enode->val);
|
||||||
|
// }
|
||||||
|
// kprintf("[END]\n");
|
||||||
|
//}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_list_elements(struct list_entry *list, const int *val, int size)
|
||||||
|
{
|
||||||
|
struct list_entry *node;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
LIST_FOREACH(list, node) {
|
||||||
|
struct test_list_node *enode = OBTAIN_STRUCT_ADDR(node, struct test_list_node, lnode);
|
||||||
|
KASSERT(enode->val == val[i], "check list element failed at idx %d: %d != %d", i, enode->val, val[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
KASSERT(i == size, "list size != expected size");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
assert_list(struct list_entry *list, const int *val, int size)
|
||||||
|
{
|
||||||
|
validate_list(list);
|
||||||
|
check_list_elements(list, val, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_test_front(void)
|
||||||
|
{
|
||||||
|
ktest_begin("insert_test_front");
|
||||||
|
|
||||||
|
struct list_entry list;
|
||||||
|
struct test_list_node n0 = {.val = 0};
|
||||||
|
struct test_list_node n1 = {.val = 1};
|
||||||
|
struct test_list_node n2 = {.val = 2};
|
||||||
|
struct test_list_node n3 = {.val = 3};
|
||||||
|
|
||||||
|
list_init(&list);
|
||||||
|
list_insert(&list, &n0.lnode);
|
||||||
|
list_insert(&list, &n1.lnode);
|
||||||
|
list_insert(&list, &n2.lnode);
|
||||||
|
list_insert(&list, &n3.lnode);
|
||||||
|
|
||||||
|
int val[] = {3, 2, 1, 0};
|
||||||
|
assert_list(&list, val, ARR_SZ(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_test_before(void)
|
||||||
|
{
|
||||||
|
ktest_begin("insert_test_before");
|
||||||
|
|
||||||
|
struct list_entry list;
|
||||||
|
struct test_list_node n0 = {.val = 0};
|
||||||
|
struct test_list_node n1 = {.val = 1};
|
||||||
|
struct test_list_node n2 = {.val = 2};
|
||||||
|
struct test_list_node n3 = {.val = 3};
|
||||||
|
|
||||||
|
list_init(&list);
|
||||||
|
list_insert_before(&list, &n0.lnode);
|
||||||
|
list_insert_before(&list, &n1.lnode);
|
||||||
|
list_insert_before(&list, &n2.lnode);
|
||||||
|
list_insert_before(&list, &n3.lnode);
|
||||||
|
|
||||||
|
int val[] = {0, 1, 2, 3};
|
||||||
|
assert_list(&list, val, ARR_SZ(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_test_middle(void)
|
||||||
|
{
|
||||||
|
ktest_begin("insert_test_middle");
|
||||||
|
|
||||||
|
struct list_entry list;
|
||||||
|
struct test_list_node n0 = {.val = 0};
|
||||||
|
struct test_list_node n1 = {.val = 1};
|
||||||
|
struct test_list_node n2 = {.val = 2};
|
||||||
|
struct test_list_node n4 = {.val = 4};
|
||||||
|
struct test_list_node n5 = {.val = 5};
|
||||||
|
struct test_list_node n6 = {.val = 6};
|
||||||
|
|
||||||
|
list_init(&list);
|
||||||
|
list_insert(&list, &n0.lnode);
|
||||||
|
list_insert(&list, &n1.lnode);
|
||||||
|
list_insert(&list, &n2.lnode);
|
||||||
|
|
||||||
|
list_insert(&n1.lnode, &n4.lnode);
|
||||||
|
list_insert(&n1.lnode, &n5.lnode);
|
||||||
|
list_insert_before(&n4.lnode, &n6.lnode);
|
||||||
|
|
||||||
|
int val[] = {2, 1, 5, 6, 4, 0};
|
||||||
|
assert_list(&list, val, ARR_SZ(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_test_back(void)
|
||||||
|
{
|
||||||
|
ktest_begin("insert_test_back");
|
||||||
|
|
||||||
|
struct list_entry list;
|
||||||
|
struct test_list_node n0 = {.val = 0};
|
||||||
|
struct test_list_node n1 = {.val = 1};
|
||||||
|
struct test_list_node n2 = {.val = 2};
|
||||||
|
struct test_list_node n3 = {.val = 3};
|
||||||
|
|
||||||
|
list_init(&list);
|
||||||
|
list_insert(&list, &n0.lnode);
|
||||||
|
list_insert(&n0.lnode, &n1.lnode);
|
||||||
|
list_insert(&n1.lnode, &n2.lnode);
|
||||||
|
list_insert(&n2.lnode, &n3.lnode);
|
||||||
|
|
||||||
|
int val[] = {0, 1, 2, 3};
|
||||||
|
assert_list(&list, val, ARR_SZ(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_test_front(void)
|
||||||
|
{
|
||||||
|
ktest_begin("remove_test_front");
|
||||||
|
|
||||||
|
struct list_entry list;
|
||||||
|
struct test_list_node n0 = {.val = 0};
|
||||||
|
struct test_list_node n1 = {.val = 1};
|
||||||
|
struct test_list_node n2 = {.val = 2};
|
||||||
|
struct test_list_node n3 = {.val = 3};
|
||||||
|
|
||||||
|
list_init(&list);
|
||||||
|
list_insert(&list, &n0.lnode);
|
||||||
|
list_insert(&list, &n1.lnode);
|
||||||
|
list_insert(&list, &n2.lnode);
|
||||||
|
list_insert(&list, &n3.lnode);
|
||||||
|
|
||||||
|
list_remove_after(&list);
|
||||||
|
list_remove_after(&list);
|
||||||
|
|
||||||
|
int val[] = {1, 0};
|
||||||
|
assert_list(&list, val, ARR_SZ(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_test_middle(void)
|
||||||
|
{
|
||||||
|
ktest_begin("remove_test_middle");
|
||||||
|
|
||||||
|
struct list_entry list;
|
||||||
|
struct test_list_node n0 = {.val = 0};
|
||||||
|
struct test_list_node n1 = {.val = 1};
|
||||||
|
struct test_list_node n2 = {.val = 2};
|
||||||
|
struct test_list_node n3 = {.val = 3};
|
||||||
|
|
||||||
|
list_init(&list);
|
||||||
|
list_insert(&list, &n0.lnode);
|
||||||
|
list_insert(&list, &n1.lnode);
|
||||||
|
list_insert(&list, &n2.lnode);
|
||||||
|
list_insert(&list, &n3.lnode);
|
||||||
|
|
||||||
|
list_remove(&n1.lnode);
|
||||||
|
list_remove(&n2.lnode);
|
||||||
|
|
||||||
|
int val[] = {3, 0};
|
||||||
|
assert_list(&list, val, ARR_SZ(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_test_end(void)
|
||||||
|
{
|
||||||
|
ktest_begin("remove_test_middle");
|
||||||
|
|
||||||
|
struct list_entry list;
|
||||||
|
struct test_list_node n0 = {.val = 0};
|
||||||
|
struct test_list_node n1 = {.val = 1};
|
||||||
|
struct test_list_node n2 = {.val = 2};
|
||||||
|
struct test_list_node n3 = {.val = 3};
|
||||||
|
|
||||||
|
list_init(&list);
|
||||||
|
list_insert(&list, &n0.lnode);
|
||||||
|
list_insert(&list, &n1.lnode);
|
||||||
|
list_insert(&list, &n2.lnode);
|
||||||
|
list_insert(&list, &n3.lnode);
|
||||||
|
|
||||||
|
list_remove_before(&list);
|
||||||
|
list_remove_before(&list);
|
||||||
|
|
||||||
|
int val[] = {3, 2};
|
||||||
|
assert_list(&list, val, ARR_SZ(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_test_all(void)
|
||||||
|
{
|
||||||
|
ktest_begin("remove_test_all");
|
||||||
|
|
||||||
|
struct list_entry list;
|
||||||
|
struct test_list_node n0 = {.val = 0};
|
||||||
|
struct test_list_node n1 = {.val = 1};
|
||||||
|
struct test_list_node n2 = {.val = 2};
|
||||||
|
struct test_list_node n3 = {.val = 3};
|
||||||
|
|
||||||
|
list_init(&list);
|
||||||
|
list_insert(&list, &n0.lnode);
|
||||||
|
list_insert(&list, &n1.lnode);
|
||||||
|
list_insert(&list, &n2.lnode);
|
||||||
|
list_insert(&list, &n3.lnode);
|
||||||
|
|
||||||
|
list_remove_after(&list);
|
||||||
|
list_remove_after(&list);
|
||||||
|
list_remove_after(&list);
|
||||||
|
list_remove_after(&list);
|
||||||
|
|
||||||
|
assert_list(&list, NULL, 0);
|
||||||
|
|
||||||
|
list_insert(&list, &n0.lnode);
|
||||||
|
list_insert(&list, &n1.lnode);
|
||||||
|
list_insert(&list, &n2.lnode);
|
||||||
|
list_insert(&list, &n3.lnode);
|
||||||
|
|
||||||
|
int val[] = {0, 1, 2, 3};
|
||||||
|
assert_list(&list, val, ARR_SZ(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
list_test(ATTR_UNUSED void *unused)
|
||||||
|
{
|
||||||
|
insert_test_front();
|
||||||
|
insert_test_before();
|
||||||
|
insert_test_middle();
|
||||||
|
insert_test_back();
|
||||||
|
|
||||||
|
remove_test_front();
|
||||||
|
remove_test_middle();
|
||||||
|
remove_test_end();
|
||||||
|
remove_test_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
KTEST_DECL(list, KTEST_SUBSYS_LIST, list_test, NULL);
|
@ -1,497 +0,0 @@
|
|||||||
#include "test_main.h"
|
|
||||||
#include "test_case.h"
|
|
||||||
#include "lb/dlist.h"
|
|
||||||
#include "kern/clib.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
struct test_list_node
|
|
||||||
{
|
|
||||||
struct llist_node lnode;
|
|
||||||
int32 val;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool
|
|
||||||
validate_list(struct dlist *list)
|
|
||||||
{
|
|
||||||
bool result = TRUE;
|
|
||||||
// list_head_test
|
|
||||||
if (list->head != NULL)
|
|
||||||
{
|
|
||||||
result = result && (list->head->prev == NULL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = result && (list->tail == NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (list->tail != NULL)
|
|
||||||
{
|
|
||||||
result = result && (list->tail->next == NULL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = result && (list->head == NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
print_list(struct dlist *list)
|
|
||||||
{
|
|
||||||
#ifdef TDBG
|
|
||||||
struct llist_node *node = lb_dlist_first(list);
|
|
||||||
|
|
||||||
while (node != NULL)
|
|
||||||
{
|
|
||||||
struct test_list_node *enode = OBTAIN_STRUCT_ADDR(node, struct test_list_node, lnode);
|
|
||||||
printf("%d->", enode->val);
|
|
||||||
node = lb_dlist_next(node);
|
|
||||||
}
|
|
||||||
printf("[END]\n");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
check_list_elements(struct dlist *list, int val[], int size)
|
|
||||||
{
|
|
||||||
struct llist_node *node = list->head;
|
|
||||||
bool ret = TRUE;
|
|
||||||
int i = 0;
|
|
||||||
while (node != NULL && i < size)
|
|
||||||
{
|
|
||||||
struct test_list_node *enode = OBTAIN_STRUCT_ADDR(node, struct test_list_node, lnode);
|
|
||||||
if (enode->val != val[i])
|
|
||||||
{
|
|
||||||
ret = FALSE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
node = lb_dlist_next(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ret)
|
|
||||||
{
|
|
||||||
if (i != size)
|
|
||||||
{
|
|
||||||
ret = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ret)
|
|
||||||
{
|
|
||||||
node = lb_dlist_last(list);
|
|
||||||
while (node != NULL && i >= 0)
|
|
||||||
{
|
|
||||||
struct test_list_node *enode = OBTAIN_STRUCT_ADDR(node, struct test_list_node, lnode);
|
|
||||||
if (enode->val != val[i - 1])
|
|
||||||
{
|
|
||||||
ret = FALSE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i--;
|
|
||||||
node = lb_dlist_prev(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ret)
|
|
||||||
{
|
|
||||||
ret = ret && (i == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TDBG
|
|
||||||
if (!ret)
|
|
||||||
{
|
|
||||||
printf("[LLIST ASSERT] Expected: ");
|
|
||||||
for (i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
printf("%d-", val[i]);
|
|
||||||
}
|
|
||||||
printf("\n Got:");
|
|
||||||
print_list(list);
|
|
||||||
printf("\n");
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool
|
|
||||||
assert_list(struct dlist *list, int val[], int size)
|
|
||||||
{
|
|
||||||
struct llist_node *node = lb_dlist_first(list);
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
if (!validate_list(list))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return check_list_elements(list, val, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
insert_val(struct dlist *list, int index, int val)
|
|
||||||
{
|
|
||||||
struct test_list_node *a = (struct test_list_node *) talloc(sizeof(struct test_list_node));
|
|
||||||
a->val = val;
|
|
||||||
lb_llist_insert_by_idx(list, index, &a->lnode);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
push_back_val(struct dlist *list, int val)
|
|
||||||
{
|
|
||||||
struct test_list_node *a = (struct test_list_node *) talloc(sizeof(struct test_list_node));
|
|
||||||
a->val = val;
|
|
||||||
lb_llist_push_back(list, &a->lnode);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
push_front_val(struct dlist *list, int val)
|
|
||||||
{
|
|
||||||
struct test_list_node *a = (struct test_list_node *) talloc(sizeof(struct test_list_node));
|
|
||||||
a->val = val;
|
|
||||||
lb_llist_push_front(list, &a->lnode);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool
|
|
||||||
insert_test_beginning(void)
|
|
||||||
{
|
|
||||||
struct dlist list;
|
|
||||||
lb_dlist_init(&list);
|
|
||||||
insert_val(&list, 0, 0);
|
|
||||||
insert_val(&list, 0, 1);
|
|
||||||
insert_val(&list, 0, 2);
|
|
||||||
insert_val(&list, 0, 3);
|
|
||||||
|
|
||||||
// 3210==0123
|
|
||||||
int val[4] = {3, 2, 1, 0};
|
|
||||||
return assert_list(&list, val, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
insert_test_middle(void)
|
|
||||||
{
|
|
||||||
struct dlist list;
|
|
||||||
lb_dlist_init(&list);
|
|
||||||
|
|
||||||
insert_val(&list, 0, 0);
|
|
||||||
insert_val(&list, 0, 1);
|
|
||||||
insert_val(&list, 0, 2);
|
|
||||||
|
|
||||||
insert_val(&list, 1, 4);
|
|
||||||
insert_val(&list, 1, 5);
|
|
||||||
insert_val(&list, 2, 6);
|
|
||||||
|
|
||||||
int val[] = {2, 5, 6, 4, 1, 0};
|
|
||||||
return assert_list(&list, val, 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
insert_test_end(void)
|
|
||||||
{
|
|
||||||
struct dlist list;
|
|
||||||
lb_dlist_init(&list);
|
|
||||||
|
|
||||||
insert_val(&list, 0, 0);
|
|
||||||
insert_val(&list, 1, 1);
|
|
||||||
insert_val(&list, 2, 2);
|
|
||||||
insert_val(&list, 3, 3);
|
|
||||||
|
|
||||||
int val[] = {0, 1, 2, 3};
|
|
||||||
return assert_list(&list, val, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
insert_test_invalid(void)
|
|
||||||
{
|
|
||||||
struct dlist list;
|
|
||||||
lb_dlist_init(&list);
|
|
||||||
|
|
||||||
insert_val(&list, 0, 3);
|
|
||||||
insert_val(&list, 0, 2);
|
|
||||||
insert_val(&list, 0, 1);
|
|
||||||
insert_val(&list, 0, 0);
|
|
||||||
|
|
||||||
// large index
|
|
||||||
insert_val(&list, 5, 9);
|
|
||||||
insert_val(&list, 6, 9);
|
|
||||||
insert_val(&list, 999, 9);
|
|
||||||
|
|
||||||
// small index
|
|
||||||
insert_val(&list, -1, 8);
|
|
||||||
insert_val(&list, -2, 8);
|
|
||||||
insert_val(&list, -999, 8);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Since it's kernel library
|
|
||||||
* Don't test NULL
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
insert_val(NULL, 1, 4);
|
|
||||||
lb_llist_insert_by_ref(NULL, list.head, list.tail);
|
|
||||||
lb_llist_insert_by_ref(&list, list.head, NULL);
|
|
||||||
*/
|
|
||||||
|
|
||||||
int val[] = {0, 1, 2, 3};
|
|
||||||
return assert_list(&list, val, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool
|
|
||||||
remove_test_beginning(void)
|
|
||||||
{
|
|
||||||
struct dlist list;
|
|
||||||
lb_dlist_init(&list);
|
|
||||||
insert_val(&list, 0, 0);
|
|
||||||
insert_val(&list, 0, 1);
|
|
||||||
insert_val(&list, 0, 2);
|
|
||||||
insert_val(&list, 0, 3);
|
|
||||||
|
|
||||||
lb_llist_remove_by_idx(&list, 0);
|
|
||||||
lb_llist_remove_by_idx(&list, 0);
|
|
||||||
|
|
||||||
// 10==01
|
|
||||||
int val[] = {1, 0};
|
|
||||||
return assert_list(&list, val, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
remove_test_middle(void)
|
|
||||||
{
|
|
||||||
struct dlist list;
|
|
||||||
lb_dlist_init(&list);
|
|
||||||
|
|
||||||
insert_val(&list, 0, 0);
|
|
||||||
insert_val(&list, 0, 1);
|
|
||||||
insert_val(&list, 0, 2);
|
|
||||||
|
|
||||||
insert_val(&list, 0, 3);
|
|
||||||
insert_val(&list, 0, 4);
|
|
||||||
insert_val(&list, 0, 5);
|
|
||||||
|
|
||||||
lb_llist_remove_by_idx(&list, 1);
|
|
||||||
lb_llist_remove_by_idx(&list, 2);
|
|
||||||
|
|
||||||
// 5310=====0135
|
|
||||||
int val[] = {5, 3, 1, 0};
|
|
||||||
return assert_list(&list, val, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
remove_test_end(void)
|
|
||||||
{
|
|
||||||
struct dlist list;
|
|
||||||
lb_dlist_init(&list);
|
|
||||||
|
|
||||||
insert_val(&list, 0, 0);
|
|
||||||
insert_val(&list, 1, 1);
|
|
||||||
insert_val(&list, 2, 2);
|
|
||||||
insert_val(&list, 3, 3);
|
|
||||||
|
|
||||||
lb_llist_remove_by_idx(&list, 3);
|
|
||||||
lb_llist_remove_by_idx(&list, 2);
|
|
||||||
|
|
||||||
int val[] = {0, 1};
|
|
||||||
return assert_list(&list, val, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
remove_test_all(void)
|
|
||||||
{
|
|
||||||
bool result = TRUE;
|
|
||||||
struct dlist list;
|
|
||||||
lb_dlist_init(&list);
|
|
||||||
|
|
||||||
insert_val(&list, 0, 0);
|
|
||||||
insert_val(&list, 1, 1);
|
|
||||||
insert_val(&list, 2, 2);
|
|
||||||
insert_val(&list, 3, 3);
|
|
||||||
|
|
||||||
lb_llist_remove_by_idx(&list, 0);
|
|
||||||
lb_llist_remove_by_idx(&list, 0);
|
|
||||||
lb_llist_remove_by_idx(&list, 0);
|
|
||||||
lb_llist_remove_by_idx(&list, 0);
|
|
||||||
|
|
||||||
result = result && assert_list(&list, NULL, 0);
|
|
||||||
|
|
||||||
insert_val(&list, 0, 0);
|
|
||||||
insert_val(&list, 1, 1);
|
|
||||||
insert_val(&list, 2, 2);
|
|
||||||
insert_val(&list, 3, 3);
|
|
||||||
|
|
||||||
lb_llist_remove_by_idx(&list, 3);
|
|
||||||
lb_llist_remove_by_idx(&list, 2);
|
|
||||||
lb_llist_remove_by_idx(&list, 1);
|
|
||||||
lb_llist_remove_by_idx(&list, 0);
|
|
||||||
|
|
||||||
result = result && assert_list(&list, NULL, 0);
|
|
||||||
|
|
||||||
insert_val(&list, 0, 0);
|
|
||||||
insert_val(&list, 1, 1);
|
|
||||||
insert_val(&list, 2, 2);
|
|
||||||
insert_val(&list, 3, 3);
|
|
||||||
|
|
||||||
lb_llist_remove_by_idx(&list, 1);
|
|
||||||
lb_llist_remove_by_idx(&list, 1);
|
|
||||||
lb_llist_remove_by_idx(&list, 1);
|
|
||||||
lb_llist_remove_by_idx(&list, 0);
|
|
||||||
|
|
||||||
result = result && assert_list(&list, NULL, 0);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
remove_test_invalid(void)
|
|
||||||
{
|
|
||||||
struct dlist list;
|
|
||||||
lb_dlist_init(&list);
|
|
||||||
|
|
||||||
insert_val(&list, 0, 3);
|
|
||||||
insert_val(&list, 0, 2);
|
|
||||||
insert_val(&list, 0, 1);
|
|
||||||
insert_val(&list, 0, 0);
|
|
||||||
|
|
||||||
// large index
|
|
||||||
lb_llist_remove_by_idx(&list, 5);
|
|
||||||
lb_llist_remove_by_idx(&list, 6);
|
|
||||||
lb_llist_remove_by_idx(&list, 999);
|
|
||||||
|
|
||||||
// small index
|
|
||||||
lb_llist_remove_by_idx(&list, -1);
|
|
||||||
lb_llist_remove_by_idx(&list, -2);
|
|
||||||
lb_llist_remove_by_idx(&list, -999);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Since it's kernel library
|
|
||||||
* Don't test NULL
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
lb_llist_remove_by_idx(NULL, 1);
|
|
||||||
lb_llist_remove_by_ref(NULL, list.head);
|
|
||||||
lb_llist_remove_by_ref(&list, NULL); */
|
|
||||||
|
|
||||||
// 0123=====3210
|
|
||||||
int val[] = {0, 1, 2, 3};
|
|
||||||
return assert_list(&list, val, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
size_test(void)
|
|
||||||
{
|
|
||||||
bool result = TRUE;
|
|
||||||
struct dlist list;
|
|
||||||
lb_dlist_init(&list);
|
|
||||||
struct dlist list2;
|
|
||||||
lb_dlist_init(&list2);
|
|
||||||
|
|
||||||
insert_val(&list, 0, 0);
|
|
||||||
insert_val(&list, 1, 1);
|
|
||||||
insert_val(&list, 2, 2);
|
|
||||||
insert_val(&list, 3, 3);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Since it's kernel library
|
|
||||||
* Don't test NULL
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* lb_llist_size(NULL) == -1
|
|
||||||
*/
|
|
||||||
result = result && (lb_llist_size(&list) == 4 && lb_llist_size(&list2) == 0);
|
|
||||||
|
|
||||||
lb_llist_remove_by_idx(&list, 0);
|
|
||||||
result = result && (lb_llist_size(&list) == 3);
|
|
||||||
insert_val(&list, 0, 0);
|
|
||||||
|
|
||||||
int val[] = {0, 1, 2, 3};
|
|
||||||
result = result && assert_list(&list, val, 4);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
push_pop_front_test(void)
|
|
||||||
{
|
|
||||||
struct llist_node *node;
|
|
||||||
bool result = TRUE;
|
|
||||||
struct dlist list;
|
|
||||||
lb_dlist_init(&list);
|
|
||||||
|
|
||||||
push_front_val(&list, 1);
|
|
||||||
push_front_val(&list, 2);
|
|
||||||
push_front_val(&list, 3);
|
|
||||||
push_front_val(&list, 4);
|
|
||||||
|
|
||||||
//4321==1234
|
|
||||||
int val1[] = {4, 3, 2, 1};
|
|
||||||
result = result && assert_list(&list, val1, 4);
|
|
||||||
|
|
||||||
node = lb_llist_pop_front(&list);
|
|
||||||
//321==123
|
|
||||||
int val2[] = {3, 2, 1};
|
|
||||||
result = result && assert_list(&list, val2, 3) && OBTAIN_STRUCT_ADDR(node, struct test_list_node, lnode)->val == 4;
|
|
||||||
|
|
||||||
lb_llist_pop_front(&list);
|
|
||||||
lb_llist_pop_front(&list);
|
|
||||||
node = lb_llist_pop_front(&list);
|
|
||||||
|
|
||||||
result = result && assert_list(&list, NULL, 0) && OBTAIN_STRUCT_ADDR(node, struct test_list_node, lnode)->val == 1;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
push_pop_back_test(void)
|
|
||||||
{
|
|
||||||
bool result = TRUE;
|
|
||||||
struct dlist list;
|
|
||||||
lb_dlist_init(&list);
|
|
||||||
struct llist_node *node;
|
|
||||||
|
|
||||||
push_back_val(&list, 1);
|
|
||||||
push_back_val(&list, 2);
|
|
||||||
push_back_val(&list, 3);
|
|
||||||
push_back_val(&list, 4);
|
|
||||||
|
|
||||||
//1234==4321
|
|
||||||
int val1[] = {1, 2, 3, 4};
|
|
||||||
result = result && assert_list(&list, val1, 4);
|
|
||||||
|
|
||||||
node = lb_llist_pop_back(&list);
|
|
||||||
//123==321
|
|
||||||
int val2[] = {1, 2, 3};
|
|
||||||
result = result && assert_list(&list, val2, 3) && OBTAIN_STRUCT_ADDR(node, struct test_list_node, lnode)->val == 4;
|
|
||||||
|
|
||||||
lb_llist_pop_back(&list);
|
|
||||||
node = lb_llist_pop_back(&list);
|
|
||||||
lb_llist_pop_back(&list);
|
|
||||||
|
|
||||||
result = result && assert_list(&list, NULL, 0) && OBTAIN_STRUCT_ADDR(node, struct test_list_node, lnode)->val == 2;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
linked_list_test(void)
|
|
||||||
{
|
|
||||||
test_begin("Linked list test");
|
|
||||||
run_case("insert_test_beginning", insert_test_beginning());
|
|
||||||
run_case("insert_test_middle", insert_test_middle());
|
|
||||||
run_case("insert_test_end", insert_test_end());
|
|
||||||
run_case("insert_test_invalid", insert_test_invalid());
|
|
||||||
|
|
||||||
run_case("remove_test_beginning", remove_test_beginning());
|
|
||||||
run_case("remove_test_middle", remove_test_middle());
|
|
||||||
run_case("remove_test_end", remove_test_end());
|
|
||||||
run_case("remove_test_invalid", remove_test_invalid());
|
|
||||||
|
|
||||||
run_case("size_test", size_test());
|
|
||||||
|
|
||||||
run_case("remove_test_all", remove_test_all());
|
|
||||||
|
|
||||||
run_case("push_pop_front_test", push_pop_front_test());
|
|
||||||
run_case("push_pop_back_test", push_pop_back_test());
|
|
||||||
|
|
||||||
test_end();
|
|
||||||
}
|
|
||||||
|
|
56
test/qsort_test.c
Normal file
56
test/qsort_test.c
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include <kern/cdef.h>
|
||||||
|
#include <kern/libkern.h>
|
||||||
|
#include <kern/brute.h>
|
||||||
|
#include <test/ktest.h>
|
||||||
|
|
||||||
|
#define MAX_ELE (10)
|
||||||
|
|
||||||
|
static int
|
||||||
|
int_cmp(const void* a, const void* b)
|
||||||
|
{
|
||||||
|
return *(const int*)a - *(const int*)b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
arr_assert(const int* a, const int *b, usize sz)
|
||||||
|
{
|
||||||
|
for(usize i = 0; i < sz; i++) {
|
||||||
|
KASSERT(a[i] == b[i], "element at %d not equal: %d != %d",(int)i, a[i], b[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_permutation(int *arr, int *exp, int *buf, usize start, usize sz)
|
||||||
|
{
|
||||||
|
if (start == sz) {
|
||||||
|
memcpy(buf, arr, sz * sizeof(int));
|
||||||
|
qsort(buf, sz, sizeof(int), int_cmp);
|
||||||
|
arr_assert(exp, buf, sz);
|
||||||
|
} else {
|
||||||
|
for (usize i = start; i < sz; i++) {
|
||||||
|
memswp(&arr[start], &arr[i], sizeof(int));
|
||||||
|
test_permutation(arr, exp, buf, start + 1, sz);
|
||||||
|
memswp(&arr[start], &arr[i], sizeof(int));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
qsort_test(ATTR_UNUSED void *unused)
|
||||||
|
{
|
||||||
|
int arr[MAX_ELE];
|
||||||
|
int exp[MAX_ELE];
|
||||||
|
int buf[MAX_ELE];
|
||||||
|
|
||||||
|
for(int i = 0; i < MAX_ELE; i++) {
|
||||||
|
arr[i] = i;
|
||||||
|
exp[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i <= MAX_ELE; i++) {
|
||||||
|
test_permutation(arr, exp, buf, 0, i);
|
||||||
|
memcpy(arr, exp, sizeof(int) * MAX_ELE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KTEST_DECL(qsort, KTEST_SUBSYS_QSORT, qsort_test, NULL);
|
@ -1,282 +0,0 @@
|
|||||||
#include "test_main.h"
|
|
||||||
#include "lb/salloc.h"
|
|
||||||
#include "test_case.h"
|
|
||||||
|
|
||||||
typedef union
|
|
||||||
{
|
|
||||||
uint32 size;
|
|
||||||
uint32 flags;
|
|
||||||
} salloc_header;
|
|
||||||
|
|
||||||
static const uint32 salloc_header_size = sizeof(salloc_header);
|
|
||||||
|
|
||||||
static char buffer[1024];
|
|
||||||
|
|
||||||
static bool salloc_init_test(void)
|
|
||||||
{
|
|
||||||
lb_salloc_init(buffer, 1024);
|
|
||||||
uint32 blk_size[] = {1024};
|
|
||||||
bool blk_free[] = {TRUE};
|
|
||||||
return lb_salloc_assert(buffer, blk_size, blk_free, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool salloc_basic_alloc(void)
|
|
||||||
{
|
|
||||||
bool result = TRUE;
|
|
||||||
lb_salloc_init(buffer, 1024);
|
|
||||||
result = result && (lb_salloc(buffer, 10) != NULL);
|
|
||||||
uint32 blk_size[] = {10 + salloc_header_size, 1024 - 10 - salloc_header_size};
|
|
||||||
bool blk_free[] = {FALSE, TRUE};
|
|
||||||
result = result && lb_salloc_assert(buffer, blk_size, blk_free, 2);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool salloc_full_alloc(void)
|
|
||||||
{
|
|
||||||
bool result = TRUE;
|
|
||||||
lb_salloc_init(buffer, 1024);
|
|
||||||
result = result && (lb_salloc(buffer, 1024 - salloc_header_size) != NULL);
|
|
||||||
uint32 blk_size[] = {1024};
|
|
||||||
bool blk_free[] = {FALSE};
|
|
||||||
result = result && lb_salloc_assert(buffer, blk_size, blk_free, 1);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool salloc_overflow_alloc(void)
|
|
||||||
{
|
|
||||||
bool result = TRUE;
|
|
||||||
lb_salloc_init(buffer, 1024);
|
|
||||||
result = result && (lb_salloc(buffer, 1024 - salloc_header_size + 1) == NULL);
|
|
||||||
uint32 blk_size[] = {1024};
|
|
||||||
bool blk_free[] = {TRUE};
|
|
||||||
result = result && lb_salloc_assert(buffer, blk_size, blk_free, 1);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool salloc_multiple_alloc(void)
|
|
||||||
{
|
|
||||||
bool result = TRUE;
|
|
||||||
lb_salloc_init(buffer, 1024);
|
|
||||||
result = result && (lb_salloc(buffer, 10) != NULL);
|
|
||||||
result = result && (lb_salloc(buffer, 10) != NULL);
|
|
||||||
result = result && (lb_salloc(buffer, 10) != NULL);
|
|
||||||
uint32 blk_size[] = {10 + salloc_header_size,
|
|
||||||
10 + salloc_header_size,
|
|
||||||
10 + salloc_header_size,
|
|
||||||
1024 - 3 * (10 + salloc_header_size)};
|
|
||||||
bool blk_free[] = {FALSE, FALSE, FALSE, TRUE};
|
|
||||||
result = result && lb_salloc_assert(buffer, blk_size, blk_free, 4);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool salloc_alloc_not_enough(void)
|
|
||||||
{
|
|
||||||
void *ptr;
|
|
||||||
bool result = TRUE;
|
|
||||||
lb_salloc_init(buffer, salloc_header_size + salloc_header_size + salloc_header_size - 1);
|
|
||||||
ptr = lb_salloc(buffer, salloc_header_size);
|
|
||||||
result = result && (ptr != NULL);
|
|
||||||
uint32 blk_size[] = {salloc_header_size + salloc_header_size + salloc_header_size - 1};
|
|
||||||
bool blk_free[] = {FALSE};
|
|
||||||
result = result && lb_salloc_assert(buffer, blk_size, blk_free, 1);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool salloc_basic_free(void)
|
|
||||||
{
|
|
||||||
void *ptr;
|
|
||||||
bool result = TRUE;
|
|
||||||
lb_salloc_init(buffer, 1024);
|
|
||||||
ptr = lb_salloc(buffer, 10);
|
|
||||||
result = result && (ptr != NULL);
|
|
||||||
|
|
||||||
lb_sfree(buffer, ptr);
|
|
||||||
uint32 blk_size[] = {1024};
|
|
||||||
bool blk_free[] = {TRUE};
|
|
||||||
result = result && lb_salloc_assert(buffer, blk_size, blk_free, 1);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool salloc_full_free(void)
|
|
||||||
{
|
|
||||||
void *ptr;
|
|
||||||
bool result = TRUE;
|
|
||||||
lb_salloc_init(buffer, 1024);
|
|
||||||
ptr = lb_salloc(buffer, 1024 - salloc_header_size);
|
|
||||||
result = result && (ptr != NULL);
|
|
||||||
|
|
||||||
lb_sfree(buffer, ptr);
|
|
||||||
uint32 blk_size[] = {1024};
|
|
||||||
bool blk_free[] = {TRUE};
|
|
||||||
result = result && lb_salloc_assert(buffer, blk_size, blk_free, 1);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool salloc_multiple_free(void)
|
|
||||||
{
|
|
||||||
void *ptr1, *ptr2, *ptr3, *ptr4;
|
|
||||||
bool result = TRUE;
|
|
||||||
lb_salloc_init(buffer, 1024);
|
|
||||||
ptr1 = lb_salloc(buffer, 10);
|
|
||||||
ptr2 = lb_salloc(buffer, 10);
|
|
||||||
ptr3 = lb_salloc(buffer, 10);
|
|
||||||
ptr4 = lb_salloc(buffer, 10);
|
|
||||||
result = result && (ptr1 != NULL) && (ptr2 != NULL) && (ptr3 != NULL) && (ptr4 != NULL);
|
|
||||||
lb_sfree(buffer, ptr1);
|
|
||||||
lb_sfree(buffer, ptr3);
|
|
||||||
|
|
||||||
uint32 blk_size[] = {10 + salloc_header_size,
|
|
||||||
10 + salloc_header_size,
|
|
||||||
10 + salloc_header_size,
|
|
||||||
10 + salloc_header_size,
|
|
||||||
1024 - 4 * (10 + salloc_header_size)};
|
|
||||||
bool blk_free[] = {TRUE, FALSE, TRUE, FALSE, TRUE};
|
|
||||||
result = result && lb_salloc_assert(buffer, blk_size, blk_free, 5);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool salloc_free_join_tail(void)
|
|
||||||
{
|
|
||||||
void *ptr1, *ptr2, *ptr3, *ptr4;
|
|
||||||
bool result = TRUE;
|
|
||||||
lb_salloc_init(buffer, 1024);
|
|
||||||
ptr1 = lb_salloc(buffer, 10);
|
|
||||||
ptr2 = lb_salloc(buffer, 10);
|
|
||||||
ptr3 = lb_salloc(buffer, 10);
|
|
||||||
ptr4 = lb_salloc(buffer, 10);
|
|
||||||
result = result && (ptr1 != NULL) && (ptr2 != NULL) && (ptr3 != NULL) && (ptr4 != NULL);
|
|
||||||
lb_sfree(buffer, ptr4);
|
|
||||||
|
|
||||||
uint32 blk_size[] = {10 + salloc_header_size,
|
|
||||||
10 + salloc_header_size,
|
|
||||||
10 + salloc_header_size,
|
|
||||||
1024 - 3 * (10 + salloc_header_size)};
|
|
||||||
bool blk_free[] = {FALSE, FALSE, FALSE, TRUE};
|
|
||||||
result = result && lb_salloc_assert(buffer, blk_size, blk_free, 4);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool salloc_free_join_head(void)
|
|
||||||
{
|
|
||||||
void *ptr1, *ptr2, *ptr3, *ptr4;
|
|
||||||
bool result = TRUE;
|
|
||||||
lb_salloc_init(buffer, 1024);
|
|
||||||
ptr1 = lb_salloc(buffer, 10);
|
|
||||||
ptr2 = lb_salloc(buffer, 10);
|
|
||||||
ptr3 = lb_salloc(buffer, 10);
|
|
||||||
ptr4 = lb_salloc(buffer, 10);
|
|
||||||
result = result && (ptr1 != NULL) && (ptr2 != NULL) && (ptr3 != NULL) && (ptr4 != NULL);
|
|
||||||
lb_sfree(buffer, ptr1);
|
|
||||||
lb_sfree(buffer, ptr2);
|
|
||||||
|
|
||||||
uint32 blk_size[] = {2 * (10 + salloc_header_size),
|
|
||||||
10 + salloc_header_size,
|
|
||||||
10 + salloc_header_size,
|
|
||||||
1024 - 4 * (10 + salloc_header_size)};
|
|
||||||
bool blk_free[] = {TRUE, FALSE, FALSE, TRUE};
|
|
||||||
result = result && lb_salloc_assert(buffer, blk_size, blk_free, 4);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool salloc_free_join_mid(void)
|
|
||||||
{
|
|
||||||
void *ptr1, *ptr2, *ptr3, *ptr4;
|
|
||||||
bool result = TRUE;
|
|
||||||
lb_salloc_init(buffer, 1024);
|
|
||||||
ptr1 = lb_salloc(buffer, 10);
|
|
||||||
ptr2 = lb_salloc(buffer, 10);
|
|
||||||
ptr3 = lb_salloc(buffer, 10);
|
|
||||||
ptr4 = lb_salloc(buffer, 10);
|
|
||||||
result = result && (ptr1 != NULL) && (ptr2 != NULL) && (ptr3 != NULL) && (ptr4 != NULL);
|
|
||||||
lb_sfree(buffer, ptr2);
|
|
||||||
lb_sfree(buffer, ptr3);
|
|
||||||
|
|
||||||
uint32 blk_size[] = {10 + salloc_header_size,
|
|
||||||
2 * (10 + salloc_header_size),
|
|
||||||
10 + salloc_header_size,
|
|
||||||
1024 - 4 * (10 + salloc_header_size)};
|
|
||||||
bool blk_free[] = {FALSE, TRUE, FALSE, TRUE};
|
|
||||||
result = result && lb_salloc_assert(buffer, blk_size, blk_free, 4);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool salloc_free_join_consecutive(void)
|
|
||||||
{
|
|
||||||
void *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
|
|
||||||
bool result = TRUE;
|
|
||||||
lb_salloc_init(buffer, 1024);
|
|
||||||
ptr1 = lb_salloc(buffer, 10);
|
|
||||||
ptr2 = lb_salloc(buffer, 10);
|
|
||||||
ptr3 = lb_salloc(buffer, 10);
|
|
||||||
ptr4 = lb_salloc(buffer, 10);
|
|
||||||
ptr5 = lb_salloc(buffer, 10);
|
|
||||||
result = result && (ptr1 != NULL) && (ptr2 != NULL) && (ptr3 != NULL) && (ptr4 != NULL) && (ptr5 != NULL);
|
|
||||||
lb_sfree(buffer, ptr2);
|
|
||||||
lb_sfree(buffer, ptr4);
|
|
||||||
|
|
||||||
uint32 blk_size[] = {10 + salloc_header_size,
|
|
||||||
10 + salloc_header_size,
|
|
||||||
10 + salloc_header_size,
|
|
||||||
10 + salloc_header_size,
|
|
||||||
10 + salloc_header_size,
|
|
||||||
1024 - 5 * (10 + salloc_header_size)};
|
|
||||||
bool blk_free[] = {FALSE, TRUE, FALSE, TRUE, FALSE, TRUE};
|
|
||||||
result = result && lb_salloc_assert(buffer, blk_size, blk_free, 6);
|
|
||||||
|
|
||||||
lb_sfree(buffer, ptr3);
|
|
||||||
|
|
||||||
uint32 blk_size2[] = {10 + salloc_header_size,
|
|
||||||
3 * (10 + salloc_header_size),
|
|
||||||
10 + salloc_header_size,
|
|
||||||
1024 - 5 * (10 + salloc_header_size)};
|
|
||||||
bool blk_free2[] = {FALSE, TRUE, FALSE, TRUE};
|
|
||||||
result = result && lb_salloc_assert(buffer, blk_size2, blk_free2, 4);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool salloc_free_all(void)
|
|
||||||
{
|
|
||||||
void *ptr1, *ptr2, *ptr3, *ptr4;
|
|
||||||
bool result = TRUE;
|
|
||||||
lb_salloc_init(buffer, 1024);
|
|
||||||
ptr1 = lb_salloc(buffer, 10);
|
|
||||||
ptr2 = lb_salloc(buffer, 10);
|
|
||||||
ptr3 = lb_salloc(buffer, 10);
|
|
||||||
ptr4 = lb_salloc(buffer, 10);
|
|
||||||
result = result && (ptr1 != NULL) && (ptr2 != NULL) && (ptr3 != NULL) && (ptr4 != NULL);
|
|
||||||
lb_sfree(buffer, ptr1);
|
|
||||||
lb_sfree(buffer, ptr2);
|
|
||||||
lb_sfree(buffer, ptr3);
|
|
||||||
lb_sfree(buffer, ptr4);
|
|
||||||
|
|
||||||
uint32 blk_size[] = {1024};
|
|
||||||
bool blk_free[] = {TRUE};
|
|
||||||
result = result && lb_salloc_assert(buffer, blk_size, blk_free, 1);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void salloc_test(void)
|
|
||||||
{
|
|
||||||
test_begin("salloc test");
|
|
||||||
|
|
||||||
run_case("salloc_init_test", salloc_init_test());
|
|
||||||
|
|
||||||
run_case("salloc_basic_alloc", salloc_basic_alloc());
|
|
||||||
run_case("salloc_full_alloc", salloc_full_alloc());
|
|
||||||
run_case("salloc_overflow_alloc", salloc_overflow_alloc());
|
|
||||||
run_case("salloc_multiple_alloc", salloc_multiple_alloc());
|
|
||||||
run_case("salloc_alloc_not_enough", salloc_alloc_not_enough());
|
|
||||||
|
|
||||||
run_case("salloc_basic_free", salloc_basic_free());
|
|
||||||
run_case("salloc_full_free", salloc_full_free());
|
|
||||||
run_case("salloc_multiple_free", salloc_multiple_free());
|
|
||||||
run_case("salloc_free_join_tail", salloc_free_join_tail());
|
|
||||||
run_case("salloc_free_join_head", salloc_free_join_head());
|
|
||||||
run_case("salloc_free_join_mid", salloc_free_join_mid());
|
|
||||||
run_case("salloc_free_join_consecutive", salloc_free_join_consecutive());
|
|
||||||
run_case("salloc_free_all", salloc_free_all());
|
|
||||||
|
|
||||||
test_end();
|
|
||||||
}
|
|
172
test/test_main.c
172
test/test_main.c
@ -1,172 +0,0 @@
|
|||||||
#include "test_main.h"
|
|
||||||
#include "test_case.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#define GAT_SIZE 256
|
|
||||||
#define CASE_NUM 32
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
char *case_name;
|
|
||||||
bool success;
|
|
||||||
bool used;
|
|
||||||
} case_info;
|
|
||||||
|
|
||||||
static case_info ginfo[CASE_NUM];
|
|
||||||
static void *gat[GAT_SIZE];
|
|
||||||
static char *test_name;
|
|
||||||
|
|
||||||
static void test_info(void)
|
|
||||||
{
|
|
||||||
printf("[TD-INFO][%s] - ", test_name);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_warning(void)
|
|
||||||
{
|
|
||||||
printf("[TD-WARN][%s] - ", test_name);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_error(void)
|
|
||||||
{
|
|
||||||
printf("[TD-ERR][%s] - ", test_name);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gat_push(void *ptr)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < GAT_SIZE; i++)
|
|
||||||
{
|
|
||||||
if (gat[i] == NULL)
|
|
||||||
{
|
|
||||||
gat[i] = ptr;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool gat_full(void)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < GAT_SIZE; i++)
|
|
||||||
{
|
|
||||||
if (gat[i] == NULL)
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gat_free(void)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < GAT_SIZE; i++)
|
|
||||||
{
|
|
||||||
if (gat[i] != NULL)
|
|
||||||
{
|
|
||||||
free(gat[i]);
|
|
||||||
gat[i] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ginfo_push(char *case_name, bool success)
|
|
||||||
{
|
|
||||||
char *r_case_name = (case_name == NULL ? "Anonymous Case" : case_name);
|
|
||||||
for (int i = 0; i < CASE_NUM; i++)
|
|
||||||
{
|
|
||||||
if (!ginfo[i].used)
|
|
||||||
{
|
|
||||||
ginfo[i].case_name = r_case_name;
|
|
||||||
ginfo[i].success = success;
|
|
||||||
ginfo[i].used = TRUE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
test_warning();
|
|
||||||
printf("GINFO full, [%s] result not recorded.\n", r_case_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_begin(char *name)
|
|
||||||
{
|
|
||||||
test_name = (name == NULL ? "Anonymous Test" : name);
|
|
||||||
for (int i = 0; i < GAT_SIZE; i++)
|
|
||||||
{
|
|
||||||
gat[i] = NULL;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < CASE_NUM; i++)
|
|
||||||
{
|
|
||||||
ginfo[i].used = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_end(void)
|
|
||||||
{
|
|
||||||
gat_free();
|
|
||||||
int32 total = 0, failed = 0, success = 0;
|
|
||||||
for (int i = 0; i < CASE_NUM; i++)
|
|
||||||
{
|
|
||||||
if (ginfo[i].used)
|
|
||||||
{
|
|
||||||
total++;
|
|
||||||
if (ginfo[i].success)
|
|
||||||
{
|
|
||||||
success++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
failed++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
test_info();
|
|
||||||
printf("%s\n", failed > 0 ? "FAIL" : "PASS");
|
|
||||||
printf(" %d cases executed. S: %d. F: %d.\n", total, success, failed);
|
|
||||||
if (failed > 0)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < CASE_NUM; i++)
|
|
||||||
{
|
|
||||||
if (ginfo[i].used && !ginfo[i].success)
|
|
||||||
{
|
|
||||||
printf(" %s FAILED\n", ginfo[i].case_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 0; i < CASE_NUM; i++)
|
|
||||||
{
|
|
||||||
ginfo[i].used = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *talloc(uint32 size)
|
|
||||||
{
|
|
||||||
if (!gat_full())
|
|
||||||
{
|
|
||||||
void *result = malloc(size);
|
|
||||||
gat_push(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
test_error();
|
|
||||||
printf("GAT full, rejecting further allocations.\n");
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void run_case(char *name, bool result)
|
|
||||||
{
|
|
||||||
ginfo_push(name, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
linked_list_test();
|
|
||||||
salloc_test();
|
|
||||||
avl_tree_test();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user