aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/regions.c3
-rw-r--r--src/tcb.c2
-rw-r--r--src/uapi/mem.c7
-rw-r--r--src/vmem.c63
4 files changed, 65 insertions, 10 deletions
diff --git a/src/regions.c b/src/regions.c
index d5f431d..2db1a91 100644
--- a/src/regions.c
+++ b/src/regions.c
@@ -440,6 +440,9 @@ static vm_t __partition_region(struct mem_region_root *r, struct mem_region *m,
m->start = start;
m->flags = flags;
m->pid = pid;
+ if (m->pid == 0)
+ m->refcount = 1;
+
mark_region_used(m->flags);
__insert_used_region(r, m);
return __addr(start);
diff --git a/src/tcb.c b/src/tcb.c
index 3e4c75a..70cad5a 100644
--- a/src/tcb.c
+++ b/src/tcb.c
@@ -199,7 +199,7 @@ struct tcb *create_thread(struct tcb *p)
stat_t r = OK;
if (p) r = __init_owned_thread(p, t);
- else r = __init_free_thread(t);
+ else r = __init_free_thread(t);
if (r) {
free_page(MM_O0, bottom);
diff --git a/src/uapi/mem.c b/src/uapi/mem.c
index f7237d7..5c18797 100644
--- a/src/uapi/mem.c
+++ b/src/uapi/mem.c
@@ -29,6 +29,7 @@ SYSCALL_DEFINE2(req_mem)(struct tcb *t, sys_arg_t size, sys_arg_t flags)
if (ERR_CODE(start))
return_args1(t, start);
+ flush_tlb_all();
return_args2(t, OK, start);
}
@@ -52,6 +53,7 @@ SYSCALL_DEFINE3(req_fixmem)(struct tcb *t, sys_arg_t fixed, sys_arg_t size,
if (ERR_CODE(start))
return_args1(t, start);
+ flush_tlb_all();
return_args2(t, OK, start);
}
@@ -75,6 +77,7 @@ SYSCALL_DEFINE1(free_mem)(struct tcb *t, sys_arg_t start)
if (!(status = free_devmem(r, start)))
return_args1(t, OK);
+ flush_tlb_all();
return_args1(t, status);
}
@@ -102,6 +105,7 @@ SYSCALL_DEFINE3(req_pmem)(struct tcb *t, sys_arg_t paddr, sys_arg_t size,
if (ERR_CODE(start))
return_args1(t, start);
+ flush_tlb_all();
return_args2(t, OK, start);
}
@@ -131,6 +135,7 @@ SYSCALL_DEFINE2(req_page)(struct tcb *t, sys_arg_t size, sys_arg_t flags)
if (ERR_CODE(start))
return_args1(t, start);
+ flush_tlb_all();
return_args4(t, OK, start, addr, asize);
}
@@ -154,6 +159,7 @@ SYSCALL_DEFINE2(req_sharedmem)(struct tcb *t, sys_arg_t size, sys_arg_t flags)
if (ERR_CODE(start))
return_args1(t, start);
+ flush_tlb_all();
return_args2(t, OK, start);
}
@@ -184,5 +190,6 @@ SYSCALL_DEFINE3(ref_sharedmem)(struct tcb *t, sys_arg_t tid, sys_arg_t addr,
if (ERR_CODE(start))
return_args1(t, start);
+ flush_tlb_all();
return_args2(t, OK, start);
}
diff --git a/src/vmem.c b/src/vmem.c
index 2feff45..f4f1bf7 100644
--- a/src/vmem.c
+++ b/src/vmem.c
@@ -63,6 +63,37 @@ static stat_t __copy_mapped_region(struct tcb *d, struct tcb *s,
return res;
}
+static void reference_mem(struct tcb *d, struct tcb *s, vm_t ref, vm_t orig)
+{
+ struct mem_region *src = find_used_region(&s->uvmem.region, orig);
+ assert(src);
+
+ struct mem_region *dst = find_used_region(&d->uvmem.region, ref);
+ assert(dst);
+
+ assert(dst->pid == s->rid);
+ dst->shaddr = orig;
+ src->refcount++;
+
+ reference_thread(s);
+}
+
+static void __free_mapping(struct tcb *t, struct mem_region *m);
+
+static void unreference_mem(struct tcb *s, vm_t addr)
+{
+ struct mem_region *src = find_used_region(&s->uvmem.region, addr);
+ assert(src);
+
+ assert(src->refcount >= 1);
+ if (--src->refcount == 0) {
+ __free_mapping(s, src);
+ free_known_region(&s->uvmem.region, src);
+ }
+
+ unreference_thread(s);
+}
+
/**
* Copy shared regions to new process. In these cases, we want to both allocate
* a fixed region and map some fixed physical memory.
@@ -80,7 +111,6 @@ static stat_t __copy_shared_region(struct tcb *d, struct mem_region *m)
vm_t start = m->start * BASE_PAGE_SIZE;
vm_t end = m->end * BASE_PAGE_SIZE;
- reference_thread(s);
size_t size = end - start;
vm_t v = alloc_shared_fixed_region(&d->uvmem.region, start, size, &size,
@@ -91,8 +121,10 @@ static stat_t __copy_shared_region(struct tcb *d, struct mem_region *m)
assert(v == start);
stat_t res = clone_region(d->uvmem.vmem, s->uvmem.vmem, start, v, size,
m->flags);
- if (res == OK)
+ if (res == OK) {
+ reference_mem(d, s, v, v);
return OK;
+ }
/* cleanup on error */
free_region(&d->uvmem.region, v);
@@ -115,8 +147,6 @@ static vm_t __clone_shared_region(struct tcb *d, struct tcb *s,
vm_t start = m->start * BASE_PAGE_SIZE;
vm_t end = m->end * BASE_PAGE_SIZE;
- reference_thread(s);
-
size_t size = end - start;
vm_t v = alloc_shared_region(&d->uvmem.region, size, &size,
MR_NONBACKED | m->flags, s->rid);
@@ -125,18 +155,19 @@ static vm_t __clone_shared_region(struct tcb *d, struct tcb *s,
stat_t res = clone_region(d->uvmem.vmem, s->uvmem.vmem,
start, v, size, flags);
- if (res == OK)
+ if (res == OK) {
+ reference_mem(d, s, v, start);
return v;
+ }
/* cleanup on error */
- unreference_thread(s);
free_region(&d->uvmem.region, v);
unmap_fixed_region(d->uvmem.vmem, v, size);
return res;
}
/**
- * Unmap and free private memory region.
+ * Unmap and free memory region.
*
* @param t Current thread.
* @param m Memory region to free.
@@ -145,7 +176,7 @@ static void __free_mapping(struct tcb *t, struct mem_region *m)
{
struct tcb *owner = get_tcb(m->pid);
if (owner)
- unreference_thread(owner);
+ unreference_mem(owner, m->shaddr);
if (is_set(m->flags, MR_NONBACKED))
return;
@@ -173,6 +204,17 @@ void clear_uvmem(struct tcb *t)
if (!is_set(m->flags, MR_USED))
continue;
+ if (m->pid == 0 && m->refcount > 1) {
+ /* we own this shared region and it's used by someone
+ * else so we can't outright free it yet, but remove our
+ * 'reference' to it so the refcount reaches zero when all
+ * referees unmap it, instead of waiting for this thread to be
+ * completely destroyed.
+ * */
+ m->refcount--;
+ continue;
+ }
+
__free_mapping(t, m);
free_known_region(&t->uvmem.region, m);
}
@@ -272,7 +314,7 @@ vm_t map_shared_fixed_uvmem(struct tcb *t, pm_t start, size_t size,
assert(is_aligned(start, BASE_PAGE_SIZE));
const vm_t v = alloc_shared_region(&t->uvmem.region, size, &size, flags,
- get_rproc(t)->tid);
+ 0);
if (ERR_CODE(v))
return v;
@@ -354,6 +396,9 @@ stat_t free_uvmem(struct tcb *r, vm_t va)
if (!m)
return ERR_NF;
+ if (m->pid == 0 && m->refcount > 1)
+ return ERR_INVAL;
+
__free_mapping(r, m);
free_known_region(&r->uvmem.region, m);
return OK;