COP 4610: Operating Systems & Concurrent Programming

What is an Operating System?

 

Contents


What is an Operating System?


By this point, you should be an experienced user of operating systems, having used (at least) one of the Microsoft Windows family of operating systems and one of the Unix family of operating systems. For this experience, you should have a practical understanding of what an operating system is and what functions it performs.

The list above is obviously incomplete, but should serve to remind you of some of the more important aspects of operating systems.

In this course we will look at all these aspects of operating systems, and some more.


Warning About Terminology

As you read the textbook, read the class notes, and relate these to knowledge you have acquired from other sources, beware that authors who write about operating systems often will use a given terms in quite different ways. You will need to take care to understand the useage of each term in the local context. I will try to be consistent with the usages followed by the author of our textbook, but may occasionally slip into using a term with a slightly different intended meaning. If you think are confused, and think it may be for this reson, please do not hesitate to ask me what I mean by a term in a given context.


Why Study Operating Systems?


It usually takes some distance in time before a person recognizes the full value of understanding something about the internals of an operating system. The greatest value in the long term is probably the ability to apply concepts and techniques from operating systems to other software systems.


Specific versus General Knowledge

Specific

General


As you study this subject, it is helpful to categorize and sort what you learn. One way of categorizing knowledge about operating systems is according to whether it is about just one specific system, or whether it about operating systems in general. In this course, we will try to spend more time on generalities. However, we will need to look at some specifics, to make sure we really understand the generalities, and can apply them.

The specifics will mostly be about Unix/Linux. One reason is that detailed information about internals is more readily available for open-source systems than for proprietary operating systems (like MS Windows).


Different Views of an Operating System


There is a story of several blind men who touched different parts of an elephant and came away with quite different perceptions.
One felt a leg, and perceived something like a tree trunk.
One felt the trunk, and perceived something like a thick snake.
One felt the tail, and perceived something like a rope with a tassle.
One felt the ear, and perceived something like a large leaf.
One felt the body, and perceived something like a wall.

The same is true of an operating system. An operating system is a huge thing, like an elephant. Depending on your role, and how you interact with it, you can have quite different perceptions. In fact, to make the analogy more complete, we should add many more views of the "elephant", such as the view of an anatomist (who looks at the inner construction -- like the designer or implementor of an operating system), the view of a veterinary pathologist (who looks at the diseases -- like a person might study computer viruses that infect an operating system), the view of a trainer (who tries to get it to perform tasks -- like an application programmer or system adminstrator tries to make an operating system perform task), and the view of the owner (who worries about how much it costs to feed -- like the manager of a computing center, or opeating system performance analyst).

Up to this point, your interactions with operating systems have probably been mainly through the user interfaces, including the command-line interface and the graphical (windows) interface. You should already have experience with the user interfaces of both the Unix and Microsoft Windows operating systems.

You will also come to look at operating systems from two other perspectives: the view of an application program that makes service requests to the operating system; the view of an operating system designer or implementator.


Some Unix Shells

There are more. Why do we have so many shells?


The command line interface of an operating system is implemented by a program known as a shell. A shell program reads in commands from a user, interprets (executes) them, and gives output back to the user. Unix has several different shells.

All these shells support a fairly complete language, including some built-in commands, variables, structures for control flow, and the ability to execute a user-specified program. They can be used both interactively and for writing shell scripts (programs, written in the shell language).

In this course you will use and write shell scripts, mainly to compile and test programs. Besides using a shell, you will also learn some of the API calls that are used to implement a shell.

When you write a shell script, like any other program, it is wise to write it in a portable way, so that it is likely to still work if you run it on a different computer and operating system some day. Just as a large number of compiler developers and users got together and defined standards for programming languages (e.g., ANSI C), a large number of operating system vendors and users got together and defined a series of standards for operating systems. The language of the Bourne shell (sh) is the most widely supported standard.

So that what you learn will be portable, shell scripts for this course should be written for the Bourne shell.


Example of a Shell Script

The following is a script, submit1_sh, used for the second qstudent submission of a programming assignment, simple_fork.cq.

#!/bin/sh
# submit code for a programming assignment
ASSIGNMENT=prog1a
HOME=/tmp
export HOME
PROGNAME=prog1
GRADER=baker@cs.fsu.edu
HOSTNAME=`uname -a`
SYSTEMS="Linux SunOS"
OSNAME=`uname -s`
PATH=/bin\:/usr/bin
if [ ${OSNAME} = "Linux" ]; then
  MAIL=mail
elif [ ${OSNAME} = "SunOS" ]; then
  MAIL=mailx
else
  echo unrecognized OS; this script must run on Linux or SunOS
  exit -1;
fi;
for SYSTEM in ${SYSTEMS}; do
  if [ ! -x ${SYSTEM}/prog1 ]; then
     echo aborted: did not find file ${SYSTEM}/${PROGNAME}
     echo please check that you are in the correct working directory,
     echo and that you did compile and test your program with ${SYSTEM}
     exit -1;
  fi;
done;
for SUFFIX in .tar .tar.gz .uu; do
  if [ -f ${ASSIGNMENT}${SUFFIX} ]; then
    echo submit aborted: would overwrite file ${ASSIGNMENT}${SUFFIX}
    echo please rename ${ASSIGNMENT}${SUFFIX} or remove it, and then rerun this script
    exit -1;
  fi;
done;
for FILE in ${PROGNAME}.c; do
  if [ ! -f ${FILE} ]; then
    echo submit aborted: missing file ${FILE}
    echo please make sure you are in the directory that contains the files 
    echo you want to submit, and then rerun this script
    exit -1;
  fi;
done;
tar cpf ${ASSIGNMENT}.tar ${PROGNAME}.c
gzip ${ASSIGNMENT}.tar
uuencode ${ASSIGNMENT}.tar.gz ${ASSIGNMENT}.tar.gz > ${ASSIGNMENT}.uu
${MAIL} -n -s "submission: ${ASSIGNMENT}" ${GRADER} < ${ASSIGNMENT}.uu
for SUFFIX in .tar .tar.gz .uu; do
  rm -f ${ASSIGNMENT}${SUFFIX};
done;
echo "sent file(s) [ ${PROGNAME}.c ] to ${GRADER}"

The example above is a shell script intended to submit a student programming assignment, by e-mail. It is intended to introduce the idea of a shell script. Some of you, including those who took the course COP 3502 recently, should be very familiar with shell scripts. If this is a new thing for you, you don't need to read and understand all of it right now, but by the second assignment you will be expected to learn to read and write similar scripts.

Many of the commands in this shell script, such as "tar" and "gzip", cause the shell to execute a "fork" operation followed by an "exec" operation. The fork operation creates a copy of the current process, and the exec operation causes the process to execute a new program. Soon, you will study these operations in detail, and use them in programming assignments.

To learn more about the shell features used in this example, read the relevant on-line manual pages by entering the commands "man sh" and "man test".


Features Used in the Example


The C-language API


The family of Unix operating systems originated from a single system, developed at Bell Laboratories. Unix was so useful and so easy to port to new hardware (and the AT&T licensing terms so liberal) that a plethora of clones rapidly developed. A key component of Unix was a portable compiler for the C language, which was used to compile the operating system. This combination of a common operating system and a common programming language was a big advantage for users, who discovered that programs written in C for Unix could be ported easily from one hardwared platform to another. This was a huge contrast to the situation with the competing proprietary OS's at the time.

However, the Tower of Babel problem recurred. The Unix clones naturally began to diverge, as the people responsible for supporting Unix on various hardware platforms all made their own "improvements". So did the clones of the C language. Unix users began to notice increasing difficulty porting applications. Some of the users got together to try to push the vendors to standardize the C language and the Unix operating system interfaces, including both the shell and the application program interfaces. Some of the vendors also formed their own Unix standarization groups. These efforts gradually converged, as the groups merged. Even non-Unix operating system vendors, such as Microsoft, decided they could not ignore this movement, and decided to support a Unix-like shell and API. (It is not well publicized, but Microsoft's Windows operating system bears a strong resemblance to Unix internally, and Microsoft will sell you - as an extra-cost option -- a complete implementation of the Unix shell, utilities, and API, for its Windows operating system.)

A few years ago, all the Unix standardization projects converged into a single group, known as the "Austin Group". This group combines three different organizations: The Portable Applications Standards Committee of the IEEE STandards Association (POSIX); The Open Group (Single Unix Specification); ISO/IEC JTC1 SC 22 WG 15 (ISO/IEC STD 9945-1).

In this course, we will try to adhere to the standard C-language API defined by these groups.


The Unix C-Language API

NAME
       fork - create a child process

SYNOPSIS
       #include <sys/types.h>
       #include <unistd.h>

       pid_t fork(void);

DESCRIPTION
       fork  creates a child process that differs from the parent process
       only in its PID and PPID, and in the fact that  resource  utiliza-
       tions are set to 0.  File locks and pending signals are not inher-
       ited.

       Under Linux, fork is implemented using copy-on-write pages, so the
       only  penalty  incurred by fork is the time and memory required to
       duplicate the parent's page tables, and to create  a  unique  task
       structure for the child.

RETURN VALUE
       On  success,  the PID of the child process is returned in the par-
       ent's thread of execution, and a 0  is  returned  in  the  child's
       thread  of  execution.   On  failure, a -1 will be returned in the
       parent's context, no child process will be created, and errno will
       be set appropriately.

ERRORS
       EAGAIN fork cannot allocate sufficient memory to copy the parent's
              page tables and allocate a task structure for the child.

       ENOMEM fork failed to allocate  the  necessary  kernel  structures
              because memory is tight.

CONFORMING TO
       The fork call conforms to SVr4, SVID, POSIX, X/OPEN, BSD 4.3.

SEE ALSO
       clone(2), execve(2), vfork(2), wait(2)

This is an example of the a C library function that provides an interface for application programs to the functionality of the Unix fork operation.


A Program Using fork()


These are examples of the use of the fork() system call. They are part of a family of graduate examples, which we will study in more detail later. We are just looking at this one example now, to illustrate what we mean by the C-language API, and to prepare you for what is to come.

The program simple-fork.cc is written in C++. The program simple_fork.c is written in ANSI C. These two programs illustrate several important points, including the following:


Underlying Abstract Concepts


To use the API, one must have an understanding of the abstractions implemented by the system, to which the API provides access. In the case of fork(), these abstractions include the concept of a process, which in turn requires the concept of a program and an address space. The conceptual fork operation creates a duplicate of a running process, executing the same program (starting at the point of the fork) in an independent address space. The original process is viewed as the parent of the new process, which is called the child.

You don't need to fully understand the above immediately. We will look at processes, fork, and the parent child relationship in more detail over the next few classes. For now, we just use this as an example of what we mean by an underlying abstract concept. The point being made here is that these abstract concepts have a sort of existence of their own, in the Platonic sense. They can apply to more than one operating system, more than one API, and more than one implementation.


OS Internals

The following are examples of Linux kernel source files:


This code, taken from the source tree of the Linux kernel (version 2.4.18), is just given as an example. You are not expected to understand it, or even read it thoroughly, not even by the end of this course. However, by the end of the course you should know enough about operating systems that you will be able (with enough time and effort) to read through this code and figure out what it is doing.

Do not be misled into thinking the file fork.c is just the "body" of the API function fork(). Between this code and the API there are several intervening layers, including the C library function fork() that is called directly, and a kernel trap mechanism (in file entry.S), which eventually transfers control to the kernel fork implementation (mostly in file process.c), which in turn calls the functions in fork.c.

© 2005 T. P. Baker & Florida State University. No part of this publication may be reproduced, stored in a retrieval system, or transmitted in any form or by any means without written permission. (Last updated by $Author: cop4610 $ on $Date: 2002/09/02 20:27:19 $.)