Redesign List as a mixin template

This commit is contained in:
Josh Holtrop 2023-11-27 15:30:09 -05:00
parent db2814596b
commit 3c8587acf5
6 changed files with 144 additions and 153 deletions

View File

@ -6,14 +6,14 @@ module hulk.acpi;
import hulk.hurl;
import hulk.klog;
import hulk.memory;
import hulk.list;
import hulk.hurl.a1;
struct Acpi
{
/**
* List of ACPI tables.
*/
private static __gshared List!(Header *) tables;
private static __gshared Header *[] tables;
enum uint XSDT_SIGNATURE = signature("XSDT");
@ -65,6 +65,8 @@ struct Acpi
map_table(acpi_xsdt_phys, xsdt.header.length);
}
size_t n_entries = (xsdt.header.length - xsdt.header.sizeof) / xsdt.tables[0].sizeof;
Header ** table_pointers = cast(Header **)A1.allocate(n_entries * (Header *).sizeof);
tables = table_pointers[0..n_entries];
for (size_t i = 0u; i < n_entries; i++)
{
ulong address = xsdt.tables[i];
@ -75,7 +77,7 @@ struct Acpi
{
map_table(address, length);
}
tables.add(header);
tables[i] = header;
uint signature = header.signature;
Klog.writefln("Found ACPI table '%c%c%c%c' at %p",
signature & 0xFFu,

View File

@ -3,125 +3,97 @@
*/
module hulk.list;
import hulk.hurl.a1;
/**
* Linked list structure.
* Linked list mixin.
*/
struct List(T)
mixin template List(T)
{
struct Node
/**
* Next item in linked list.
*/
T * list_next;
/**
* Previous item in linked list.
*/
T * list_prev;
/**
* Initialize linked list fields.
*/
public void list_init()
{
/**
* Linked list node.
*/
T item;
alias item this;
/**
* Next node.
*/
Node * next;
/**
* Previous node.
*/
Node * prev;
list_next = &this;
list_prev = &this;
}
/**
* Head node.
* Add this item after another in a list.
*/
public Node * head;
/**
* Tail node.
*/
public Node * tail;
/**
* Add an item to this linked list.
*/
public void add(T)(auto ref T item)
public void list_insert_after(T * item)
{
Node * new_node = A1.allocate!Node();
new_node.item = item;
new_node.next = null;
new_node.prev = tail;
if (tail != null)
{
tail.next = new_node;
}
tail = new_node;
if (head == null)
{
head = new_node;
}
list_next = item.list_next;
list_prev = item;
item.list_next = &this;
list_next.list_prev = &this;
}
/**
* Remove an item from this linked list.
* Add this item before another in a list.
*/
public void remove(ref Node node)
public void list_insert_before(T * item)
{
if (node.prev != null)
{
node.prev.next = node.next;
}
else
{
/* Removing the first list node. */
head = node.next;
}
if (node.next != null)
{
node.next.prev = node.prev;
}
else
{
/* Removing the last list node. */
tail = node.prev;
}
list_next = item;
list_prev = item.list_prev;
item.list_prev = &this;
list_prev.list_next = &this;
}
/**
* Remove an item from this linked list.
* Remove this item from the list.
*/
public void remove(Node * node)
public void list_remove()
{
remove(*node);
list_next.list_prev = list_prev;
list_prev.list_next = list_next;
list_init();
}
/**
* Get the number of nodes in this list.
* Get the number of items in this list.
*/
public @property size_t count() const
public @property size_t list_count() const
{
size_t count;
const(Node) * node = head;
while (node != null)
size_t count = 1;
const(T) * item = &this;
while (item.list_next != &this)
{
count++;
node = node.next;
item = item.list_next;
}
return count;
}
/**
* Allow foreach iteration across a List.
* Allow foreach iteration through this linked list.
*/
public int opApply(scope int delegate(ref Node) dg)
public int opApply(scope int delegate(T *) dg)
{
Node * node = head;
while (node != null)
T * item = &this;
T * last = item.list_prev;
for (;;)
{
Node * current = node;
node = node.next;
int result = dg(*current);
T * next = item.list_next;
int result = dg(item);
if (result != 0)
{
return result;
}
if (item == last)
{
break;
}
item = next;
}
return 0;
}

View File

@ -148,8 +148,11 @@ struct Pci
bool multifunction;
Range[6] memory_ranges;
mixin List!Device;
void initialize(Address address, Configuration * config)
{
list_init();
this.config = config;
this.address = address;
type = Type(config.class_id, config.subclass_id, config.interface_id);
@ -233,9 +236,9 @@ struct Pci
}
/**
* Store a list of discovered PCI devices.
* Device list.
*/
public static __gshared List!(Device *) devices;
public static __gshared Device * devices;
private static uint read_config_register(Address address, uint register_id)
{
@ -402,7 +405,14 @@ struct Pci
if (config.vendor_id != 0xFFFFu)
{
Device * device = A1.allocate!Device();
devices.add(device);
if (devices == null)
{
devices = devices;
}
else
{
device.list_insert_before(devices);
}
device.initialize(Address(bus_nr, device_nr, function_nr), config);
if (device.multifunction)
{

View File

@ -6,6 +6,7 @@ module hulk.test;
import hulk.klog;
import hulk.list;
import hulk.time;
import hulk.hurl.a1;
struct Test
{
@ -33,30 +34,45 @@ struct Test
private static void test_list()
{
Klog.writefln("Testing list...");
List!ulong list;
assert_eq(null, list.head);
assert_eq(null, list.tail);
ulong v = 33;
list.add(42);
assert_neq(null, list.head);
assert_neq(null, list.tail);
list.add(v);
list.add(0xFFFF);
v = 55;
struct S
{
size_t v;
mixin List!S;
void initialize()
{
list_init();
}
}
S * s1 = A1.allocate!S();
s1.initialize();
s1.v = 33;
assert_eq(1, s1.list_count);
S * s2 = A1.allocate!S();
s2.initialize();
s2.v = 42;
s2.list_insert_after(s1);
S * s3 = A1.allocate!S();
s3.initialize();
s3.v = 55;
s3.list_insert_before(s1);
size_t count;
assert_eq(3, list.count);
foreach (entry; list)
assert_eq(3, s1.list_count);
assert_eq(3, s2.list_count);
assert_eq(3, s3.list_count);
foreach (entry; *s1)
{
switch (count)
{
case 0:
assert_eq(42, entry);
assert_eq(33, entry.v);
break;
case 1:
assert_eq(33, entry);
assert_eq(42, entry.v);
break;
case 2:
assert_eq(0xFFFF, entry);
assert_eq(55, entry.v);
break;
case 3:
assert_eq(0, 1);
@ -66,24 +82,24 @@ struct Test
}
count++;
}
foreach (entry; list)
foreach (entry; *s3)
{
if (entry == 33)
if (entry.v == 33)
{
list.remove(entry);
entry.list_remove();
}
}
assert_eq(2, list.count);
assert_eq(2, s3.list_count);
count = 0;
foreach (entry; list)
foreach (entry; *s3)
{
switch (count)
{
case 0:
assert_eq(42, entry);
assert_eq(55, entry.v);
break;
case 1:
assert_eq(0xFFFF, entry);
assert_eq(42, entry.v);
break;
case 2:
assert_eq(0, 1);
@ -93,51 +109,30 @@ struct Test
}
count++;
}
foreach (entry; list)
foreach (entry; *s2)
{
if (entry == 42)
if (entry.v == 42)
{
list.remove(entry);
entry.list_remove();
}
}
assert_eq(1, list.count);
count = 0;
foreach (entry; list)
{
switch (count)
{
case 0:
assert_eq(0xFFFF, entry);
break;
case 1:
assert_eq(0, 1);
break;
default:
break;
}
count++;
}
assert_neq(null, list.head);
assert_neq(null, list.tail);
list.remove(list.head);
assert_eq(0, list.count);
assert_eq(null, list.head);
assert_eq(null, list.tail);
assert_eq(1, s2.list_count);
assert_eq(1, s3.list_count);
}
private static void assert_eq(T)(T first, T second)
private static void assert_eq(T)(T first, T second, size_t line_number = __LINE__)
{
if (first != second)
{
Klog.fatal_error("Assertion failed! %x != %x", first, second);
Klog.fatal_error("Assertion failed! %x != %x (line %u)", first, second, line_number);
}
}
private static void assert_neq(T)(T first, T second)
private static void assert_neq(T)(T first, T second, size_t line_number = __LINE__)
{
if (first == second)
{
Klog.fatal_error("Assertion failed! %x == %x", first, second);
Klog.fatal_error("Assertion failed! %x == %x (line %u)", first, second, line_number);
}
}
}

View File

@ -16,19 +16,6 @@ struct Thread
/* TODO: currently kernel thread stack size is fixed. */
enum STACK_SIZE = 16 * 1024;
/** List of all kernel threads. */
private static __gshared List!Thread threads;
/** Currently executing kernel thread. */
static __gshared Thread * current_thread;
/** Current kernel thread stack pointer. */
ulong * stack_pointer;
static assert(stack_pointer.offsetof == 0);
/** Base address of kernel thread stack. */
void * stack_addr;
/** Interrupt stack template. */
static immutable __gshared ulong[Idt.ISF_COUNT] interrupt_stack_template = [
0x16161616_16161616u, /* RBP */
@ -54,11 +41,31 @@ struct Thread
Gdt.SELECTOR_KERNEL_DATA, /* SS */
];
/** List of all kernel threads. */
private static __gshared Thread * threads;
/** Currently executing kernel thread. */
static __gshared Thread * current_thread;
/** Current kernel thread stack pointer. */
ulong * stack_pointer;
static assert(stack_pointer.offsetof == 0);
/** Base address of kernel thread stack. */
void * stack_addr;
mixin List!Thread;
/**
* Initialize a kernel thread.
*/
public void initialize(void function() fn)
{
list_init();
if (threads == null)
{
threads = &this;
}
stack_addr = A1.allocate(STACK_SIZE);
ulong * stack_top = cast(ulong *)(stack_addr + STACK_SIZE);
stack_pointer = stack_top - Idt.ISF_COUNT;
@ -73,6 +80,11 @@ struct Thread
*/
public void initialize_main_thread()
{
list_init();
if (threads == null)
{
threads = &this;
}
stack_addr = cast(void *)(Hurl.HULK_STACK_TOP - STACK_SIZE);
}

View File

@ -13,7 +13,7 @@ struct Usb
{
Klog.writefln("\a3Initializing USB");
foreach (pci_device; Pci.devices)
foreach (pci_device; *Pci.devices)
{
if (pci_device.type == Pci.XHCI_CONTROLLER)
{