Last updated Apr. 12, 2004 by Matt Mahoney, mmahoney@cs.fit.edu
UNIX is a multi-user, multi-tasking operating system. This introduction describes features common to most UNIX variants, including Solaris, OpenBSD, FreeBSD, and Linux.
An operating system is a program that, at a bare minimum, allows a user to load programs into memory, execute them, and interrupt their execution. Modern operating systems such as Windows and UNIX go far beyond this. UNIX provides the following services:
Because UNIX is multi-user, you must supply a login name and password before you can use it. After logging in, you can create and edit files and directories and run programs by giving text-based commands. A shell interprets these commands and executes them on your behalf. Some common commands:
ls -las List files in the current directory. man vi Display help on the vi program (a text editor) vi prog.cpp Create/edit the file prog.cpp g++ prog.cpp -o prog Compile C++ prog.cpp to executable file prog ./prog Run prog ^C (hold down Ctrl and type C) kill prog logout Log out
Each user has a home directory, such as /usr/joe, and a current directory (named .) which starts in the home directory. Each / separates one level in the directory tree with root /. A file name not starting with / is relative to the current directory. Thus, prog is equivalent to /usr/joe/prog, which means the file prog in the directory joe in the directory usr in the root directory. Some commands:
cd dir Change the current directory to dir cd .. Move up one level (e.g. /usr/joe to /usr) cd Move to your home directory cp file1 file2 Copy file1 to file2 mv file1 file2 Rename or move file1 to file2 rm file1 Remove file1
The input and output of any program or command may be redirected to a file or another program.
./prog > file1 Write output of prog to file1 ls >> file1 Append output of ls command to file1 sort < file1 > file2 Sort, reading from file1 and writing to file2 ls | sort Run ls and sort simultaneously with output of ls piped to the input of sort
You can run more than one program at a time by running them in the background. The shell prompts for the next command without waiting for the first one to finish running.
./prog & Run in background ps Show all running process IDs (e.g. ./prog 1234) kill 1234 Interrupt prog running in background
See www.emba.uvm.edu/CF/basic.html for a list of common UNIX commands.
perror("msg"); // Print "msg: error" depending on errno int fd = open("file", O_RDONLY); // Open for reading fd = open("file", O_WRONLY | O_TRUNC | O_CREAT, 0644); // Open for writing, truncate, create if needed with permissions rw-r--r-- // Also: O_RDWR = open in read/write mode // O_APPEND = open for appending // O_EXCL = fail if O_CREAT and file exists // O_NONBLOCK or O_NDELAY = read may return 0 bytes without blocking n = read(fd, buf, n); n = write(fd, buf, n); // Read or write up to n bytes to/from char buf[n], return number // of bytes actually read or written or 0 at EOF. n = lseek(fd, n, SEEK_SET) // Position file pointer to n from start (SEEK_END = end, SEEK_CUR = current) close(fd); // Close file unlink("file"); // Delete file truncate("file", n); // Change size to n ftruncate(fd, n); sync(); // Flush all buffers to disk (for shutdown) // Get file information struct stat s; // in sys/stat.h stat("file", &s); lstat("file", &s); // link fstat(fd, &s); // s.st_dev = device // s.st_ino = inode // s.st_mode = permissions // s.st_nlink = hard link count // s.st_uid = owner ID // s.st_gid = group ID // s.st_size = file size // s.st_atime = last read time (seconds since Jan. 1, 1970) // s.st_mtime = last write time // s.st_ctime = change time (e.g. change permissions) // Read directory struct dirent d; // in sys/dirent.h fd = open("dir", O_RDONLY); // dir is a directory while(getdents(fd, &d, sizeof(d))) // d.d_nam is next file in dir lseek(fd, d.d_off, SEEK_SET); // go to next file // Change permissions (only root can change onwer) chown("file", owner, group); // Change owner, group, -1 = unchanged lchown("file", owner, group); // Change link owner, group fchown(fd, owner, group); chmod("file", mode); // Change permissions, e.g. 0644 = rw-r--r-- fchmod(fd, mode); // Redirect fd2 = dup(fd); // copy fd to fd2 dup2(fd, fd2); // close fd2 and redirect it to fd dup2(fd, 0); // redirect stdin to fd dup2(fd, 1); // redirect stdout to fd dup2(fd, 2); // redirect stderr to fd // I/O device specific control fcntl(fd, cmd, arg) ioctl(fd, cmd, arg) // Special files mkdir("dir"); // Make directory mknod("pipe", S_IFIFO, 0); // Create named pipe // Create child process int pid = fork(); // In parent, pid = child. In child, pid = 0. pid = getpid(); // get process ID ppid = getppid(); // get parent process ID exit(n); // Exit with status n (0-255, normally 0 = success) pid = wait(&n); // Wait for child to exit with status n>>8 or signal n&127 // Replace current process execl("cmd", "arg0", "arg1", ... ,0); // Execute cmd with args execlp("cmd", "arg0", "arg1", ... ,0); // Execute cmd with args in PATH execv(argv[0], argv); // Execute, argv={"cmd","arg1",...,0}; execvp(argv[0], argv); // Execute in PATH // Change current directory chdir("dir"); // Lower priority by n nice(n); // Change process owner (if root) setuid(n); // set real owner seteuid(n); // effective owner (has permissions of user ID n) setgid(n); // set group setegid(n); // set effective group n = getuid(); // get the above n = geteuid(); n = getgid(); n = getegid(); // Signals - interrupt a running process kill(pid, sig); // Send signal sig (0-31) to process pid, where sig is: // SIGINT = ^C // SIGKILL = cannot be caught // SIGALRM = alarm clock // SIGTERM = default signal for shell "kill" command // SIGCHLD = child has exited // SIGSTP = suspend (^Z) // SIGCONT = continue after suspend (bg or fg command) // SIGSEGV = segmentation fault // and others... (man signal) alarm(n); // Schedule SIGALRM in n seconds pause(); // Wait for signal // Install signal handler int handler(int n) {} // to be called when signal is caught int (*oldHandler)(int) = signal(sig, handler); // install, save old handler signal(sig, SIG_IGN); // ignore sig signal(sig, SIG_DFL); // restore default behavior // Process group setpgid(pid, pgid); // set to pgid (to disconnect from terminal) setpgid(0, pgid); // set for self getpgid(pid); // get process group ID (pid = 0 means self) // Create pipe with fd[0] for reading and fd[1] for writing int fd[2]; pipe(fd); // Internet client #include sys/types.h, sys/socket.h, netinet/in.h, arpa/inet.h, netdb.h int fd = socket(AF_INET, SOCK_STREAM, 0); // TCP, SOCK_DGRAM = UDP sockaddr_in s; memset(&s, 0, sizeof(s)); // clear s s.sin_family = AF_INET; // internet, or AF_UNIX for local hostent *h = gethostbyname("server.com"); // DNS lookup, NULL = fail s.sin_addr.s_addr = ((in_addr*)(h->h_addr))->s_addr; // IP address s.sin_port = htons(80); // 80=HTTP, 23=telnet, 25=SMTP, 21=FTP, 22=SSH connect(fd, (sockaddr*)&s, sizeof(s)); // -1 = fail // then read, write, close fd // Internet server int sfd = socket(AF_INET, SOCK_STREAM, 0); // server file descriptor s.sin_addr.s_addr = htonl(INADDR_ANY); // rest of s as above, ports < 1024 require root bind(sfd, (sockaddr*)&s, sizeof(s)); // bind socket to server port listen(sfd, 5); // max client queue size is 5 sockaddr_in c; // client IP address and port int len = sizeof(c); int cfd = accept(sfd, (sockaddr*)&c, &len); // wait for client // read, write, close cfd to client (usually in a child process) // Misc. network gethostname(name, len); // get host name in char name[len] Example program to read a web page
Process ID Parent process ID Real and effective user and group IDs State Pending signals Code segment (executable code memory bounds) Data segment (static data) Stack segment (temporary data) User area Signal handler table Open file descriptors Recent CPU usage Hardware register contents (unless running) Page table
A process can be in one of 6 states.
Suspended / ^ SIGCONT / \ SIGSTOP / \ / Allocated \ Initialize V CPU \ Exit Idle --------------> Ready ----------> Running ----------> Zombie ^ / \ / Event occurs \ / Wait for event \ / \ V SleepingScheduling is round-robin with preemption by higher priority processes.
Every second: For each process priority = (recent CPU usage)/constant + base priority + nice setting Every 1/10 second or when a process waits or is suspended Move highest priority process to running state Every clock tick (1/100 sec) Increment count If count = 4 then recompute priority of running processIn Linux, priority is computed as follows:
Credits = credits/2 + priorityAt each context switch, the processor is given to the process with the most credits. Both methods favor interactive processes over long running CPU bound processes.
A disk is divided into cylinders, tracks, and sectors, which are numbered in the order in which they can be accessed most quickly sequentially (possibly interleaved). This array of blocks has the following structure:
Boot block (executed at startup) Super block (bitmap of free blocks) Inodes (pointers to file blocks) User blocks (directory and file blocks)A directory is a table of file names and inode pointers as read by getdents(). An inode is:
Pointers to blocks 0-9 (typically 4KB each) Indirect pointer for files over 40KB Double indirect pointer for files over 4MB Permissions, owner, group, type, timestamps... as returned by stat()An indirect pointer points to a 4K block of 1K pointers. A double indirect block points to a 4K block of 1K pointers to 1K pointers to support files up to 4GB.
User process makes I/O request (read() or write()) to kernel. Kernel puts user process in waiting state and gives CPU to another process. Kernal requests I/O to hardware. I/O transfers data by DMA. I/O signals hareware interrupt. Kernal puts user process in ready state.
32 bit Logical virtual High Physical User address +---+ address 20 bits +-----+ address Process ----------->| + |------------+------>| MMU |-----------> +---+ | +-----+ RAM ^ | Segment | +-------------------------> Table ----+ Low 12 bitsMMU page table indexed by high part of address
In hardware: RAM address Valid bit Referenced bit Modified bit Copy-on-write bit In software: Disk address Age Free bit Ready-to-swap-out bit Reference countMMU algorithm (in hardware)
Read: If valid then Output mapped address Set referenced bit Else Page fault interrupt Write: If valid and not copy-on-write Output mapped address Set referenced bit Set modified bit Else Page fault interruptPage fault algorithm (MMU interrupt)
Move current process to sleep state If page is not still in RAM Find page with free bit set Load page from disk Update page table address Set valid bit Clear free and ready-to-swap-out bitsThe page daemon (kernel process) swaps out the least recently used pages:
For each page If referenced bit is set age = 0 Else age = age + 1 If age > limit If no disk address or modified bit is set Set ready-to-swap-out Else Set free bit If number of free pages < limit For each page If ready-to-swap-out Copy to swap file Set free bit
Single user Single user Multi user Single tasking Multitasking Multitasking BASIC | DOS | Windows 3.1 ----------------------- \ \ Windows 95 Windows NT | | Windows 98 | | | Windows Me Windows 2000 | | \ | ------------\ | Windows XP
Transition ---> Ready --------> Standby -------> Running ---> Terminated ^ (front of queue) / \ / \ (preemption) / \ <---------------------- / \ / <---- Waiting <-------- (for event)