pluto/src/kernel/task.zig
DrDeano fbd135c437
Move to std.log
Removed nothing to pass tests


Removed log imports

Plus some spelling
2020-07-23 20:47:56 +01:00

208 lines
6.5 KiB
Zig

const std = @import("std");
const expectEqual = std.testing.expectEqual;
const expectError = std.testing.expectError;
const builtin = @import("builtin");
const is_test = builtin.is_test;
const build_options = @import("build_options");
const mock_path = build_options.mock_path;
const arch = @import("arch.zig").internals;
const panic = if (is_test) @import(mock_path ++ "panic_mock.zig").panic else @import("panic.zig").panic;
const ComptimeBitmap = @import("bitmap.zig").ComptimeBitmap;
const Allocator = std.mem.Allocator;
/// The kernels main stack start as this is used to check for if the task being destroyed is this stack
/// as we cannot deallocate this.
extern var KERNEL_STACK_START: *u32;
/// The function type for the entry point.
const EntryPointFn = fn () void;
/// The bitmap type for the PIDs
const PidBitmap = if (is_test) ComptimeBitmap(u128) else ComptimeBitmap(u1024);
/// The list of PIDs that have been allocated.
var all_pids: PidBitmap = brk: {
var pids = PidBitmap.init();
// Set the first PID as this is for the current task running, init 0
_ = pids.setFirstFree() orelse unreachable;
break :brk pids;
};
/// The task control block for storing all the information needed to save and restore a task.
pub const Task = struct {
const Self = @This();
/// The unique task identifier
pid: PidBitmap.IndexType,
/// Pointer to the stack for the task. This will be allocated on initialisation.
stack: []u32,
/// The current stack pointer into the stack.
stack_pointer: usize,
///
/// Create a task. This will allocate a PID and the stack. The stack will be set up as a
/// kernel task. As this is a new task, the stack will need to be initialised with the CPU
/// state as described in arch.CpuState struct.
///
/// Arguments:
/// IN entry_point: EntryPointFn - The entry point into the task. This must be a function.
/// IN allocator: *Allocator - The allocator for allocating memory for a task.
///
/// Return: *Task
/// Pointer to an allocated task. This will then need to be added to the task queue.
///
/// Error: Allocator.Error
/// OutOfMemory - If there is no more memory to allocate. Any memory or PID allocated will
/// be freed on return.
///
pub fn create(entry_point: EntryPointFn, allocator: *Allocator) Allocator.Error!*Task {
var task = try allocator.create(Task);
errdefer allocator.destroy(task);
task.pid = allocatePid();
errdefer freePid(task.pid);
const task_stack = try arch.initTaskStack(@ptrToInt(entry_point), allocator);
task.stack = task_stack.stack;
task.stack_pointer = task_stack.pointer;
return task;
}
///
/// Destroy the task. This will release the allocated PID and free the stack and self.
///
/// Arguments:
/// IN/OUT self: *Self - The pointer to self.
///
pub fn destroy(self: *Self, allocator: *Allocator) void {
freePid(self.pid);
// We need to check that the the stack has been allocated as task 0 (init) won't have a
// stack allocated as this in the linker script
if (@ptrToInt(self.stack.ptr) != @ptrToInt(&KERNEL_STACK_START)) {
allocator.free(self.stack);
}
allocator.destroy(self);
}
};
///
/// Allocate a process identifier. If out of PIDs, then will panic. Is this occurs, will need to
/// increase the bitmap.
///
/// Return: u32
/// A new PID.
///
fn allocatePid() PidBitmap.IndexType {
return all_pids.setFirstFree() orelse panic(@errorReturnTrace(), "Out of PIDs\n", .{});
}
///
/// Free an allocated PID. One must be allocated to be freed. If one wasn't allocated will panic.
///
/// Arguments:
/// IN pid: u32 - The PID to free.
///
fn freePid(pid: PidBitmap.IndexType) void {
if (!all_pids.isSet(pid)) {
panic(@errorReturnTrace(), "PID {} not allocated\n", .{pid});
}
all_pids.clearEntry(pid);
}
// For testing the errdefer
const FailingAllocator = std.testing.FailingAllocator;
const testing_allocator = &std.testing.base_allocator_instance.allocator;
fn test_fn1() void {}
test "create out of memory for task" {
// Set the global allocator
var fa = FailingAllocator.init(testing_allocator, 0);
expectError(error.OutOfMemory, Task.create(test_fn1, &fa.allocator));
// Make sure any memory allocated is freed
expectEqual(fa.allocated_bytes, fa.freed_bytes);
// Make sure no PIDs were allocated
expectEqual(all_pids.bitmap, 1);
}
test "create out of memory for stack" {
// Set the global allocator
var fa = FailingAllocator.init(testing_allocator, 1);
expectError(error.OutOfMemory, Task.create(test_fn1, &fa.allocator));
// Make sure any memory allocated is freed
expectEqual(fa.allocated_bytes, fa.freed_bytes);
// Make sure no PIDs were allocated
expectEqual(all_pids.bitmap, 1);
}
test "create expected setup" {
var task = try Task.create(test_fn1, std.testing.allocator);
defer task.destroy(std.testing.allocator);
// Will allocate the first PID 1, 0 will always be allocated
expectEqual(task.pid, 1);
}
test "destroy cleans up" {
// This used the leak detector allocator in testing
// So if any alloc were not freed, this will fail the test
var fa = FailingAllocator.init(testing_allocator, 2);
var task = try Task.create(test_fn1, &fa.allocator);
task.destroy(&fa.allocator);
// Make sure any memory allocated is freed
expectEqual(fa.allocated_bytes, fa.freed_bytes);
// All PIDs were freed
expectEqual(all_pids.bitmap, 1);
}
test "Multiple create" {
var task1 = try Task.create(test_fn1, std.testing.allocator);
var task2 = try Task.create(test_fn1, std.testing.allocator);
expectEqual(task1.pid, 1);
expectEqual(task2.pid, 2);
expectEqual(all_pids.bitmap, 7);
task1.destroy(std.testing.allocator);
expectEqual(all_pids.bitmap, 5);
var task3 = try Task.create(test_fn1, std.testing.allocator);
expectEqual(task3.pid, 1);
expectEqual(all_pids.bitmap, 7);
task2.destroy(std.testing.allocator);
task3.destroy(std.testing.allocator);
}
test "allocatePid and freePid" {
expectEqual(all_pids.bitmap, 1);
var i: usize = 1;
while (i < PidBitmap.NUM_ENTRIES) : (i += 1) {
expectEqual(i, allocatePid());
}
expectEqual(all_pids.bitmap, PidBitmap.BITMAP_FULL);
i = 0;
while (i < PidBitmap.NUM_ENTRIES) : (i += 1) {
freePid(@truncate(PidBitmap.IndexType, i));
}
expectEqual(all_pids.bitmap, 0);
}