Commit 61093179 authored by Léo Grange's avatar Léo Grange

add mem_area_resize() with ability to remove unused pages

parent 100dfe86
......@@ -106,6 +106,38 @@ int mem_area_insert(struct process *proc, struct mem_area *area) {
}
int mem_area_resize(struct mem_area *area, size_t new_size, struct process *proc) {
int ret = 0;
size_t old_size = area->max_size;
// first, call area-specific resize callback if any
if(area->ops != NULL && area->ops->area_resize != NULL)
ret = area->ops->area_resize(area, new_size);
else
area->max_size = new_size;
new_size = area->max_size;
// if no error occurs and decreasing the size of the area, release uneeded
// pages
if(ret == 0 && area->max_size < old_size) {
void *old_last_page = MEM_PAGE_BEGINING(area->address + old_size);
void *new_last_page = MEM_PAGE_BEGINING(area->address + new_size);
union pm_page *page;
for( ; new_last_page < old_last_page; new_last_page += 1024) {
printk(LOG_DEBUG, "mem_area: release page @%p\n", new_last_page);
page = mem_find_page(proc->dir_list, new_last_page);
if(page != NULL) {
mem_release_page(page);
}
}
}
return ret;
}
size_t mem_area_fill_partial_page(struct mem_area *area, size_t offset, void *dest) {
size_t readsize = PM_PAGE_BYTES;
......
......@@ -88,7 +88,7 @@ struct mem_area_ops {
* Any page which is out of the area after decreasing size will be removed
* from the corresponding process address space by the caller.
*/
int (*area_resize)(struct mem_area *area, const struct mem_area *new_area);
int (*area_resize)(struct mem_area *area, size_t new_size);
/**
......@@ -136,7 +136,7 @@ int mem_area_insert(struct process *proc, struct mem_area *area);
/**
* Generic function call when a page fault occurs, inside a given area address
* Generic function called when a page fault occurs, inside a given area address
* range.
* The implementation specific operation is called to set the corresponding page.
*/
......@@ -152,6 +152,16 @@ extern inline union pm_page mem_area_pagefault(struct mem_area *area,
}
}
/**
* Resize an area to the given new_size.
* If size is decreased and some memory pages associated with corresponding
* process are excluded of the given area, each one is released.
* TODO the design is not so good, process should be implicit?
* Return 0 for success, negative value else.
*/
int mem_area_resize(struct mem_area *area, size_t new_size, struct process *proc);
/**
* Helper for filesystem implementations, to handle MEM_AREA_PARTIAL.
* Check for a given page to fill with 0 when needed, and return the number of
......
......@@ -55,6 +55,11 @@ union pm_page {
( ((uint32)(addr) >> (PM_PAGE_ORDER)) & (MEM_DIRECTORY_PAGES - 1))
// get the first byte's address of the physical page of the given address
#define MEM_PAGE_BEGINING(addr) \
(void*)((uint32)(addr) & ~(PM_PAGE_BYTES-1))
/**
* Process address space is managed by a linked list of "pages directory".
* Each directory describe a set of sequential virtual pages, and the virtual
......
......@@ -574,55 +574,12 @@ void *sys_sbrk(int incr) {
// heap area exists (maybe just created)
if(heap != NULL) {
void *ret;
ret = heap->address;
void *ret = heap->address;
size_t new_size;
printk(LOG_DEBUG, "sbrk: incr=%d\n", incr);
// add or remove the given size
if(incr > 0) {
// just resize the heap area, allocation is done on page fault
// FIXME need a check to ensure no area are overlayed by the heap!
heap->max_size += incr;
}
else if(incr < 0) {
// remove pages if possible
int curalign;
void *current_brk;
// impossible to reduce the size beyond the original heap begin addr
current_brk = heap->address + heap->max_size;
incr = heap->max_size > -incr ? incr : -(heap->max_size);
curalign = (((unsigned int) current_brk) - 1) % PM_PAGE_BYTES;
if(curalign + incr < 0 ) {
union pm_page *page;
void *curvm;
int nbpages;
nbpages = (-incr - ((unsigned int)(current_brk) % PM_PAGE_BYTES)
-1) / PM_PAGE_BYTES + 1;
curvm = current_brk - ((unsigned int)(current_brk)
% PM_PAGE_BYTES);
while(nbpages > 0) {
printk(LOG_DEBUG, "sbrk: remove page @%p\n", curvm);
page = mem_find_page(cur->dir_list, curvm);
if(page != NULL) {
mem_release_page(page);
}
nbpages--;
curvm -= PM_PAGE_BYTES;
}
}
// resize heap memory area
heap->max_size += incr;
}
new_size = -incr > heap->max_size ? 0 : heap->max_size + incr;
mem_area_resize(heap, new_size, cur);
return ret;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment