Project
Suggestions.
You will want to be sure that your file system is able to handle big files. Testing this might be quite inconvenient. If you can put up with the inconvenience of having to type thousands of lines of input to test it, that’s OK, but don’t expect me to go along with that when I’m grading.
A very easy solution to the inconvenience would be to make a very basic shell program. Make up some simple commands for manipulating files, and let the user/tester enter them interactively. You would definitely need a command like ls or dir for showing a list of all the files in the current directory. You would definitely want a command like cat or more or type for displaying the contents of a file. It would be nice to have a text editor, like vi or pico, for really testing your ability to handle files, but writing an editor is a very long task, and not really a reasonable goal here.
Along with all the obvious commands for testing, you should have a create command (or something like that), which creates a new file, and allows the user to type a few lines of text, which are simply taken as the file’s initial contents. Certainly you should have a copy command, which makes a new file containing a copy of an existing file’s data. Also, you should have an ‘append’ command, which makes an existing file longer, by adding the contents of another file to its end.
Here’s a possible sample session:
<< dir
(no files)
<< create
fileone
(enter data for ‘fileone’, **** at end)
< one two three four
< five six seven eight
< test test test
< ****
(‘fileone’
created, 55 bytes)
<< create
filetwo
(enter data for ‘filetwo’, **** at end)
< hello
< hello
< ****
(‘filetwo’
created, 12 bytes)
<< dir
1 fileone 55 2004-11-30 15:23
2 filetwo 12 2004-11-30 15:31
<< copy fileone three
<< append
filetwo three
<< append
fileone three
<< list
three
one two three four
five six seven eight
test test
test
hello
hello
one two three four
five six seven eight
test test
test
<< dir
1 fileone 55 2004-11-30 15:23
2 filetwo 12 2004-11-30 15:31
3 three
122 2004-11-30
15:34
See how convenient it makes testing? It also makes it easy to build up big files quickly.
Now here’s the useful thing.
The real unix file-system is full of big files, and has already existing editors that are quite convenient to use. Wouldn’t it be nice if you could access those files as well as the ones that exist inside your own file-system?
If you use the special system functions sys$open, sys$read, sys$write, etc. to access your file-system, that becomes easy. Read the library function documentation for details of how it works, but basically you get that functionality for free. If a filename begins with an ‘@’ sign, then the emulator will assume it is a real unix file, and do everything for you automatically, you don’t have to do any extra programming. The emulator only passes file requests where the name does not begin with ‘@’ to the functions you create.
So, without any extra work, you would be able to use your shell thing to do this:
<< copy
filefour @/home/www/text/chaucer/canterbury
and you’ve instantly copied the entirety of Chaucer’s Canterbury Tales into a file in your file-system (if it works, that is). Copying in the other direction (from your file-system into a ‘real’ unix file) gives you an alternate way to test everything.
Using this URL http://rabbit.eng.miami.edu/text/index.html, you can see all of the sample text files available on rabbit.
Perhaps you could even go a bit further, and recognise another special ‘filename’. This won’t be done for you automatically by the emulator, but perhaps you could use the filename ‘#’ to represent your terminal (stdin on input and stdout on output), then your shell could be even simpler: you would not need a type or create command, they would be covered by ‘copy xxx #’ and ‘copy # xxx’.
Network File System
If you choose the network file system option, there are many ways you could go about it. One way would be with a simple sort of NFS system as briefly discussed in class.
A simpler way would be with a kind of RPC (Remote Procedure Call). Here’s the idea.
Normally, you define functions with names like open, read, write, etc., which take parameters describing exactly what you want them to do, they perform that task, and return a result directly to the calling program. With RPC, the task is split up. Taking just one function for example: when your program calls the read() function, it doesn’t do any work, it just sends a message containing all your parameters and the tag ‘read’ to a server somewhere else on the internet. The server receives that message and performs exactly the tasks that your read() function would normally have done, and sends the results back in a reply. Your new RPC read function() waits for the reply, and returns the results contained within it back to the calling program.
So the read, write, and open functions don’t actually do anything, they just ask a server to do it, wait for a reply, and then act as though they had done the work themselves.
This allows you to write programs that use a network file system exactly the same way as you would write a normal file-using program, you don’t even need to be aware that there is a difference.
You also get the option of having both systems available to all programs through one set of functions. Just choose a special character, such as ‘~’ or ‘?’, and make a rule: if the first character of a filename is ~ or ? or whatever, then treat it as a network file, otherwise handle it normally. Almost no extra work, but a lot more useful and impressive.
The emulator, as it stands, does not support networking, so this option is really for those of you who have been using the fakedisc functions under unix. However, it should not be too hard for me to add an (emulated) ethernet card abilities to the emulator, and I would not object to doing it if anyone would make use of it. Let me know right away if that is your desire.
Remember also that there are examples of unix-based (freeBSD) internet programs that you may borrow from freely: http://rabbit.eng.miami.edu/class/een521/internet.html.
Keyboard Input by Interrupts.
Look at the function sys$setiv in the documentation. There is a sample showing how to use it in the emulator (instruction set, not library) documentation.
By default, the emulator provides an interrupt handler for the keyboard. That is how getchar() is able to work. Once you create and establish your own interrupt handler for the keyboard, it will of course replace the default one, and getchar() will stop working. So you need to be careful in deciding how you are going to test your work.
The idea is simple: when there is a keyboard interrupt, simply add the character typed to the end of a circular queue buffer, incrementing your count of the number of characters (and maybe also whole lines) in that buffer. Your own version of getchar() simply waits until there is something in that buffer, and removes the first thing from the front of the queue. Do not call your version of getchar() “getchar”, or you will get confused. If you don’t get confused, the linker probably will, and if it doesn’t, you can be sure I will.
There is one fly in the ointment.
Remember the “race” condition. You need to protect your queue buffer and
associated variables with a semaphore (or something functionally equivalent).
Such things are to be covered in class this week.