CS 321 Spring 2012  >  Lecture Notes for Monday, January 23, 2012

CS 321 Spring 2012
Lecture Notes for Monday, January 23, 2012

More on “Virtual”

We used a Linux shell to look at examples of virtual files: keyboard input, screen output, pipes, named pipes.

Here are some examples.

cat < abc > def1
sort < abc > def2
uniq < abc > def3

Each of the above three command lines reads from file abc and writes to a def... file. The first sends the contents of abc to file def1, unchanged. The second sorts by line before writing. The third removes duplicate consecutive lines before writing. The arrows (“<”, “>”) indicate the direction of data flow.

cat > def

The above reads from the terminal (keyboard?) used as a virtual file. and writes to file def.

sort < abc

The above reads from file abc, sorts by line, and writes to the terminal, used as a virtual file.

cat < abc | sort | uniq

The above reads from file abc, sorts by line, removes duplicate lines, and writes to the terminal. This comamnd line includes two uses of a pipe: a virtual output file connected to virtual input file.

mkfifo mypipe
cat < abc | sort > mypipe

And then, in another terminal window:

cat < mypipe | uniq

The above two together have the same effect as before, but they create and use the named pipe mypipe. This is much like the pipe used earlier, except that looks like a file in the current directory.

Operating System Concepts [1.5]

A process is a program in execution. This is an abstraction of the processor. A typical modern computer runs hundreds of processes at once. If processes share the same address space, then we generally call them threads.

Each process has an address space: its abstraction of the memory. This looks like a simple sequence of bytes, accessed via the usual assembly-language instructions. In practice, parts of the address space may correspond to physical memory, while other parts are actually on disk. When the latter are accessed, they are loaded into memory (this is virtual memory). If memory is full, then parts may need to be copied out to disk.

A file is another abstraction that looks like a sequence of bytes, but it is accessed via a very different interface: open, read, write, close, etc. Conceptually, a file is an abstraction of storage; however, as we have seen, essentially anything can be behind the file interface.

Input/output, or I/O, means communication with anything other than the processor and the memory.

All modern OSs provide various kinds of protection: ensuring that all access (to memory, files, etc.) is authorized.

A shell is a low-ish level interface to operating-system functionality. Traditionally, a shell uses a command-line interface.

System Calls [1.6]


Some things an OS “just does” (e.g., process scheduling). Other things it needs to be told to do (e.g., output something, quit, wait a while, start a new process). The latter are done via system calls.

System calls happen a lot: pretty much everything a program does, besides mucking about with its own variables, will involve system calls.

Nonetheless, in a typical program we rarely deal directly with actual system calls. Typically we use higher-level library routines that make system calls. For example, in C++, “cout << ...” is (in part) a wrapper around the sys_write system call.

Calls & Thin Wrappers

In C/C++, system calls are usually made through thin wrapper functions. These are bare-bones interfaces to the assembly-language system calls. The main reason for a wrapper is calling conventions: C/C++ functions are not called the same way that system calls are made.

We looked at the following Unix system call wrappers. All are usually declared in <unistd.h> (not an ANSI standard header).

Wrapper around sys_write. Write to a (virtual?) file. Takes file descriptor, pointer to character buffer, number of characters to write. Returns number of characters actually written. File descriptors are returned by the sys_open system call. Standard file descriptors that are opened for us are 0 (standard input), 1 (standard output), 2 (standard error output).
Wrapper around sys_exit. (The underscore avoids name conflict with another standard library function.) End current process. Takes integer parameter, which is used as status of process. Does not return.
Implementation varies. Originally wrapper about sys_sleep; may be wrapper around sys_nanosleep, which allows for more fine-grained timing. Put process to sleep for given number of seconds. Takes integer parameter: number of seconds to sleep.
Wrapper around sys_fork. Clone the current process. No parameters. Return value is integer of type pid_t. Return value is integer of type pid_t. For child process, returns zero. For parent process, returns non-zero. If positive: PID of child. If negative: fork failed.


See syscall1.cpp (NetRun link) syscall2.cpp (NetRun link) for C++ code that makes system calls. Note: These will probably work on most Unix-derived OSs; they may not work under Windows.

System Calls will be continued next time.

CS 321 Spring 2012: Lecture Notes for Monday, January 23, 2012 / Updated: 31 Jan 2012 / Glenn G. Chappell / ggchappell@alaska.edu