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

add mem_area_resize() with ability to remove unused pages

parent 100dfe86
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -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;
+12 −2
Original line number Diff line number Diff line
@@ -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
+5 −0
Original line number Diff line number Diff line
@@ -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
+4 −47
Original line number Diff line number Diff line
@@ -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;
	}