

Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
Material Type: Notes; Professor: Corner; Class: Operating Systems; Subject: Computer Science; University: University of Massachusetts - Amherst; Term: Spring 2009;
Typology: Study notes
1 / 2
This page cannot be seen from the preview
Don't miss anything!


CMPSCI 377 Operating Systems Spring 2009
Lecturer: Mark Corner Scribes: Bruno Silva,Jim Partan
As we have discussed in previous lectures, page tables map virtual page addresses to physical page addresses. One of the advantages of using virtual addresses is that we can achieve complete separation between processes, in terms of address spaces. One drawback to this is that it is convenient to be able to share some things, for example library code which would otherwise be replicated wastefully by many different programs. We don’t want to have to load exactly the same library code into every process’ address space; we’d prefer to map the library code to its own pages, and let all processes share those pages. This will usually reduce the memory requirements for the system.
In order to do this, we need to do some common tricks with page tables.
The first important memory-sharing concept is known as Copy-On-Write, or COW. COW shares pages by default, whenever sharing is still possible. Whenever a new process is created, for example by fork(), we “clone” an old process by making a copy of its page tables and marking all referenced pages as read-only.
Then whenever either of the processes (the original one, or the clone) tries to write to one of the pages, the two processes will differ, and sharing is no longer possible. The OS allocates a new page and changes the mapping in one of the page tables. If neither of the processes ever tries to modify a memory location, however, the processes will share the same (read-only) pages forever! COW tries to maximize the amount of sharing at all times.
There are a number of status bits in page tables in addition to valid, resident, and dirty, including readable, writable, and executable. Shared libraries are readable and executable (because they include code), but are not writable. In this way, processes can share libraries without worrying that another process can corrupt their address space, because the pages used for shared libraries are not writable.
As a different type of example, interprocess communication (IPC) can use shared memory which is readable and writable as a wide and high-speed communication path between processes.
COW follows the principle of delaying work until it needs to be done, because often it turns out that, due to an error or similar condition, the work won’t have to be done after all.
Processes have valid and invalid entries on their page tables. The valid entries all point to somewhere “real” (e.g. a physical page, or some portion of disk in case of non-resident pages, etc). The entries that don’t point anywhere are the entries that we will use when allocating a new page.
The allocation of new pages can be done in two ways: either via sbrk(), or via mmap(). If you want to increase the size of the heap (i.e. the number of valid pages), you can use sbrk(). Using mmap(), on the other hand, maps a file into a process’ virtual address space. In the allocator you implemented, for example, you
17-2 Lecture 17: April 7
used mmap() to map memory addresses to the file /dev/zero. This makes it seem like you were allocating space from /dev/zero each time you called mmap(). (Remember that whenever you read something from /dev/zero, you get only zeroes for as long as you want to keep reading.) But, since /dev/zero is a read-only file and we usually call mmap() using the MAP PRIVATE flag, we follow the COW rules. When you actually try to write to the memory mmap()’d from /dev/zero, the OS intervenes and clones the corresponding page. So, instead of actually writing to /dev/zero, you end up writing to a new memory page.