Solution:
Under round-robin scheduling the utilization increases
with the time quantum, so let us assume that the time quantum is larger
than 50msec. After loading (and running) the first two processes, running
the third and fourth require swapping out the first process to make room
available in memory. After the first round, we need to bring in the 1st
process from the swap space. Because process 4 is still performing an I/O,
it cannot be swapped out, and therefore it is the second process that has
enough space to allow the first process to get in, thus the second process
gets swapped out. But then, it will get swapped in again soon, instead
of processes 3 and 4 (process 1 cannot be swapped out because its address
space has to remain in memory while the I/O operation takes place). So,
in steady state a time window will look like:
Process 2 swapped out, process 1 swapped in, process 1 runs, processes 3 & 4 swapped out, process 2 swapped in, process 2 runs, process 1 swapped out, process 3 swapped in, process 3 runs, process 4 swapped in (note: we do not need to swap anybody out to get process 4 in), process 4 runs, and loop. The memory will look like:
Process 1: red, Process 2: blue, Process 3: yellow, Process 4: Green
Now, to compute the utilization under this model:
In each iteration, we have each process running for 50msec. The time wasted
for swapping
is: 64 * 20/8 (2 out) + 64 * 20/8 (1 in) + (32
+ 16) * 20/8 (3 & 4 out) + 64 * 20/8 (2 in) + 64 * 20/8 (1 out) + 32
* 20/8 (3 in) + 16 * 20/8
(4 in) = 880 msec. Utilization is 200 / ( 200
+ 880) = 18.5%
A better solution is to run the available processes
in memory for a few time slices, then swap them out and swap in other
processes, run them for a while, and so on.
For example:
Micro-level scheduling: round-robin. Macro-level
scheduling: each process is swapped out after 10 time slices. In this case,
the scenario would be, in steady state Processes 3 & 4 swapped out,
processes 1 & 2 swapped in, processes 1 & 2 run for 10 time slices
each, get swapped out, processes 3 & 4 swapped in, processes 3 &
4 run for 10 time slices, and so on...
Time wasted for swapping: 48 * 20/8 + 128 * 20/8
+ 128 * 20/8 + 48 * 20/8 = 880, while the utilization would be:
10 * 100 / (10 * 100 + 880) = 53.2%
This scheme could be optimized further by swapping out a process as soon as it finishes its 10th time slice, but the difference in utilization is not substantial.
Solution:
Solution:
This is a nice trick, but it ignores a small problem. What happens if
the binary file changes while the program is running in main memory? If
the operating system evicts the code pages (during swapping out) but does
not save them on the swap space, and just brings them from the binary file
(during swapping in), then we are loading a different program into the
process. We can have the situation then that pages belonging to two different
programs be in the process's text segment. The results of such a disastrous
mix are undefined at best. Operating systems that wish to play this trick
lock the binary file so that it cannot be modified while there is a process
that runs the code. A user who is trying to recompile a program that is
currently running in a process will get a message like "text file busy"
or some such.
Solution:
mmap() is used to
remap physical memory and files into a process's virtual address space. It is
widely used when linking shared libraries, since they don't have to be loaded
into process' memory. mmap can also be used to map a file on the disk to the
virtual
address space of several processes. When a file is accessed by one of the
processes, it will be loaded into the physical memory and it will not be loaded
twice when other processes need it, since those processes can access the files
through their virtual memory mappings.
mprotect controls access permissions to a section of memory.
Here is the detailed information about these functions copied from the man pages.
The prot argument describes the desired memory protection. It has bits:
The munmap system call deletes the mappings for the specified address range, and causes further references to addresses within the range to generate invalid memory references.
prot is a bitwise-or of the following values:
As seen from the man page descriptions, to be able to use mmap and mprotect we need to know a file descriptor and the length of file section we want to map starting from the offset. For our purposes, the offset from the file is going to be 0 and the length of the section we want to access is as large as the file itself. In order to get the file descriptor, we can use open() system call and, for finding out the length of the file we can use fstat(). You can find the detailed descriptions of these system calls in man pages. I'll give a brief summary of these system calls here:
#include <sys/types.h> #include <sys/stat.h>
#include <fcntl.h>
int open(const char * pathname , int flags );
open attempts to
open a file and return a file descriptor (a small, non-negative integer for use
in read , write , etc.)
flags is one of
O_RDONLY , O_WRONLY or O_RDWR which request opening the file read-only,
write-only or read/write, respectively.
#include <sys/stat.h>
#include <unistd.h>
fstat(int filedes , struct stat * buf );
stats the file pointed to by filedes and fills in buf
struct stat { dev_t st_dev; /* device */ ino_t st_ino; /* inode */ mode_t st_mode; /* protection */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ dev_t st_rdev; /* device type (if inode device) */ off_t st_size; /* total size, in bytes */ unsigned long st_blksize; /* blocksize for filesystem IO */ unsigned long st_blocks; /* number of blocks allocated */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of last change */ };Now we can write pseudo code for the brokers and the manager assuming that mentioned file is Stock.data.
Broker() {
//open the file in read only mode and get the file descriptor
int fd = open( "Stock.data", O_RDONLY );
//get the information about the file
struct stat* this_file = new struct stat;
fstat( fd, this_file);
//now let's map the file into the process' virtual memory space
void* addr = (void*)mmap( Null, this_file->off_t,PROT_READ,MAP_SHARED, fd, 0);
/* DO SOMETHING*/
munmap(addr, this_file->off_t );
return;
}
Manager() {
//open the file in read only mode and get the file descriptor
int fd = open( "Stock.data", O_RDWR
//get the information about the file
struct stat* this_file = new struct stat;
stat( fd, this_file);
//now let's map the file into the process' virtual memory space
void* addr = mmap( Null, this_file->off_t,PROT_READ | PROT_WRITE,MAP_SHARED, fd, 0);
/* DO SOMETHING*/
/* WRITE*/
/* DO SOMETHING*/
munmap(addr, this_file->off_t );
return;
}
The disk controller needs a physical memory address, not a virtual address. Ben Bitdiddle proposes that when the user does a write system call, the operating system should check that the user's virtual address is valid, translate it into a physical address, and pass that address and the length (also checked for validity) to the disk hardware.
This won't quite work. In no more than two sentences, what did Ben forget?
Solution:
Need solution