aboutsummaryrefslogtreecommitdiff
path: root/kernel/l0/region.c
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2014-12-07 11:24:06 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2014-12-07 11:24:06 +0100
commit26b68c108664cb54089613bdbc54624ed66f7fda (patch)
treecafbab0b0c9c1db1869e4346cebc96b2d6f53570 /kernel/l0/region.c
parentacc786cb5805d057932ada3e7c571bb8e901cd67 (diff)
downloadkogata-26b68c108664cb54089613bdbc54624ed66f7fda.tar.gz
kogata-26b68c108664cb54089613bdbc54624ed66f7fda.zip
Make L0 thread-safe (mostly).
Diffstat (limited to 'kernel/l0/region.c')
-rw-r--r--kernel/l0/region.c58
1 files changed, 43 insertions, 15 deletions
diff --git a/kernel/l0/region.c b/kernel/l0/region.c
index 8d59b49..aa73a22 100644
--- a/kernel/l0/region.c
+++ b/kernel/l0/region.c
@@ -1,6 +1,7 @@
#include <region.h>
#include <dbglog.h>
#include <frame.h>
+#include <mutex.h>
typedef union region_descriptor {
struct {
@@ -28,6 +29,8 @@ uint32_t n_unused_descriptors;
static descriptor_t *first_free_region_by_addr, *first_free_region_by_size;
static descriptor_t *first_used_region;
+STATIC_MUTEX(ra_mutex); // region allocator mutex
+
// ========================================================= //
// HELPER FUNCTIONS FOR THE MANIPULATION OF THE REGION LISTS //
// ========================================================= //
@@ -218,6 +221,23 @@ void region_allocator_init(void* kernel_data_end) {
first_used_region = u0;
}
+static void region_free_inner(void* addr) {
+ descriptor_t *d = find_used_region(addr);
+ if (d == 0) return;
+
+ region_info_t i = d->used.i;
+
+ remove_used_region(d);
+ d->free.addr = i.addr;
+ d->free.size = i.size;
+ add_free_region(d);
+}
+void region_free(void* addr) {
+ mutex_lock(&ra_mutex);
+ region_free_inner(addr);
+ mutex_unlock(&ra_mutex);
+}
+
static void* region_alloc_inner(size_t size, uint32_t type, page_fault_handler_t pf, bool use_reserve) {
size = PAGE_ALIGN_UP(size);
@@ -263,9 +283,12 @@ static void* region_alloc_inner(size_t size, uint32_t type, page_fault_handler_t
}
void* region_alloc(size_t size, uint32_t type, page_fault_handler_t pf) {
+ void* result = 0;
+ mutex_lock(&ra_mutex);
+
if (n_unused_descriptors <= N_RESERVE_DESCRIPTORS) {
uint32_t frame = frame_alloc(1);
- if (frame == 0) return 0;
+ if (frame == 0) goto try_anyway;
void* descriptor_region = region_alloc_inner(PAGE_SIZE, REGION_T_DESCRIPTORS, 0, true);
ASSERT(descriptor_region != 0);
@@ -275,7 +298,8 @@ void* region_alloc(size_t size, uint32_t type, page_fault_handler_t pf) {
// this can happen if we weren't able to allocate a frame for
// a new pagetable
frame_free(frame, 1);
- return 0;
+ region_free_inner(descriptor_region);
+ goto try_anyway;
}
for (descriptor_t *d = (descriptor_t*)descriptor_region;
@@ -284,25 +308,25 @@ void* region_alloc(size_t size, uint32_t type, page_fault_handler_t pf) {
add_unused_descriptor(d);
}
}
- return region_alloc_inner(size, type, pf, false);
+ try_anyway:
+ // even if we don't have enough unused descriptors, we might find
+ // a free region that has exactly the right size and therefore
+ // does not require splitting, so we try the allocation in all cases
+ result = region_alloc_inner(size, type, pf, false);
+
+ mutex_unlock(&ra_mutex);
+ return result;
}
region_info_t *find_region(void* addr) {
- descriptor_t *d = find_used_region(addr);
- if (d == 0) return 0;
- return &d->used.i;
-}
+ region_info_t *r = 0;
+ mutex_lock(&ra_mutex);
-void region_free(void* addr) {
descriptor_t *d = find_used_region(addr);
- if (d == 0) return;
-
- region_info_t i = d->used.i;
+ if (d != 0) r = &d->used.i;
- remove_used_region(d);
- d->free.addr = i.addr;
- d->free.size = i.size;
- add_free_region(d);
+ mutex_unlock(&ra_mutex);
+ return r;
}
// ========================================================= //
@@ -357,6 +381,8 @@ void region_free_unmap(void* ptr) {
// =========================== //
void dbg_print_region_stats() {
+ mutex_lock(&ra_mutex);
+
dbg_printf("/ Free kernel regions, by address:\n");
for (descriptor_t *d = first_free_region_by_addr; d != 0; d = d->free.next_by_addr) {
dbg_printf("| 0x%p - 0x%p\n", d->free.addr, d->free.addr + d->free.size);
@@ -382,6 +408,8 @@ void dbg_print_region_stats() {
ASSERT(d != d->used.next_by_addr);
}
dbg_printf("\\\n");
+
+ mutex_unlock(&ra_mutex);
}
/* vim: set ts=4 sw=4 tw=0 noet :*/