In Project 3, you'll want to create an array of void pointers (void *) for your table. In the .cc file, you'll probably initialize it like this:
content = new void *[maxsize];
where maxsize is a parameter. So how do you declare content in your *.h file? Like this:
Let's break this down. Remember that when you have a pointer to an array, the variable points to the first array elmt. So content is that pointer. If you dereference content, that is *content, what you should get is the first (void *) in the array. That's why there are 2 asterisks. content is a pointer to a void pointer.
NoffMagic is just a magic # that Nachos puts on every Nachos object file to identify it as such. It's defined in bin/noff.h
Including Halt, there are 11. They are listed in userprog/syscall.h. In that file, each system call is associated with a number that is used to denote the type of call it is (like SC_Halt is zero). This is what is being read from register 2 in the ExceptionHandler function in exception.cc
It refers to the way the computer stores the bytes of a multiple-byte integer number. Some machines store, for example, a two-byte integer with the least significant byte first, followed by the most significant byte. These machines are called little endian machines. Other machines store a two-byte integer with its most significant byte first, followed by its least significant byte. These machines are called big endian machines. Most UNIX machines are big endian. Whereas most PCs are little endian machines. Since this affects translation, Nachos needs to know which type of architecture we have (and does a conversion using the SwapHeader function in addrspace.cc if necessary.) You don't have to worry about this yourself. Nachos will do it for you. However, that SwapHeader function sure is a good place to see all the different parts of a NoffHeader object (noffH). You'll need those pieces to do the LoadPage function correctly.
No. NumPhysPages is the total number of frames in the simulated RAM. Nachos often refers to frames as "physical pages".
In Linux, a very handy thing you can do is to feed the output of one command directly as input into another command. For example, "ls -l" does a verbose (long) directory listing which, for a big directory, will probably go off the screen (try it in your antipasto account). The "more" command (example: more foo) will show the contents of file "foo" a screen at a time (you press any key to see the next screen). A pipe (the vertical bar) allows you to chain these commands together:
ls -l | more
The result of the above is that the verbose directory listing will now be shown a page at a time. Technically, it takes the output of the ls -l command and pipes it as input into the more command. You can easily extend this analogy to a multiprocess example, where the result of one process could be piped as input into another. Thus pipes allow you to take simple routines and chain them up anyway you like to do complex tasks. Nachos implements pipes with the help of bounded buffers between processes (the output of the first process goes into the buffer and the input from the second process comes out of the buffer). If any of the processes exit prematurely, the pipe is broken and data may be lost. We won't be implementing the pipes part of Nachos, but it's good to know what they do, especially if you work with UNIX/Linux in the future since it's a powerful feature unknown to the average Windows user.
No. SpaceId is simply an int. (a user-defined type. It's done in userprog/syscall.h.) Exec needs to return a unique id (int) to identify the new thread. Nachos decided to say that this unique identifier is of type SpaceId to more clearly indicate its purpose. The following is thus legal:
SpaceId new_pid = Exec("foo");
The Nachos Project Guide says to recycle old SpaceIds so you can reuse them. I say forget that. It's not worth your energy. Simply increment an int every time you assign a new pid. A real OS designer would care, but you have more important things to worry about.
Join allows child threads to finish before the current thread proceeds. See slide 28 for a formal definition. It's a way for user programs to synchronize (just like signal and wait are how the OS does synchronization). So say thread1 was doing mergesort with an array of size n and I want to spawn off 2 separate threads to sort the subarrays:
mergesort: SpaceId child1 = Exec("sortFirstHalf"); SpaceId child2 = Exec("sortSecondHalf"); mergeHalves();Exec is what spawns off the other threads. But since I have no control over the concurrency, it may be the case that thread1 gets to mergeHalves() before the child threads are done sorting. I can use Join to wait for the kids to finish:
mergesort: SpaceId child1 = Exec("sortFirstHalf"); SpaceId child2 = Exec("sortSecondHalf"); Join(child1, child2); mergeHalves();So basically Join is telling the invoking thread to wait until all the children listed as arguments have completed. So in regards to the variables needed, you'll definitely need a field in the processes' PCBs to indicate their status. Each time a child exits, it will want to inform its parent that it may be able to resume (assuming all the other kids have finished too.)