Operating Systems 2230

Similar documents
CITS2002 Systems Programming. Creating a new process using fork() 1 next CITS2002 CITS2002 schedule

UNIX System Calls. Sys Calls versus Library Func

CS240: Programming in C. Lecture 14: Errors

Naked C Lecture 6. File Operations and System Calls

CS240: Programming in C

Unix-Linux 2. Unix is supposed to leave room in the process table for a superuser process that could be used to kill errant processes.

CSC 1600 Unix Processes. Goals of This Lecture

CS240: Programming in C

Processes often need to communicate. CSCB09: Software Tools and Systems Programming. Solution: Pipes. Recall: I/O mechanisms in C

Process Management! Goals of this Lecture!

Operating Systems II Systems Programming in C

Lecture 8: Unix Pipes and Signals (Feb 10, 2005) Yap

Computer Science & Engineering Department I. I. T. Kharagpur

CS 355 Operating Systems. Keeping Track of Processes. When are processes created? Process States 1/26/18. Processes, Unix Processes and System Calls

CSE 333 SECTION 3. POSIX I/O Functions

The Process Abstraction. CMPU 334 Operating Systems Jason Waterman

SYSTEM CALL IMPLEMENTATION. CS124 Operating Systems Fall , Lecture 14

CSE 410: Systems Programming

628 Lecture Notes Week 4

Processes. Processes (cont d)

Process Management 1

Processes COMPSCI 386

Computer Science 330 Operating Systems Siena College Spring Lab 5: Unix Systems Programming Due: 4:00 PM, Wednesday, February 29, 2012

Lecture 23: System-Level I/O

UNIX System Programming. Overview. 1. A UNIX System. 2. Processes (review) 2.1. Context. Pipes/FIFOs

CSC209H Lecture 6. Dan Zingaro. February 11, 2015

Lecture 3. Introduction to Unix Systems Programming: Unix File I/O System Calls

518 Lecture Notes Week 3

Preview. Process Control. What is process? Process identifier The fork() System Call File Sharing Race Condition. COSC350 System Software, Fall

3. Process Management in xv6

Processes. Johan Montelius KTH

Workshop on Inter Process Communication Solutions

TCSS 422: OPERATING SYSTEMS

Process Management! Goals of this Lecture!

Recitation 8: Tshlab + VM

A process. the stack

CS 33. Architecture and the OS. CS33 Intro to Computer Systems XIX 1 Copyright 2018 Thomas W. Doeppner. All rights reserved.

CS24: INTRODUCTION TO COMPUTING SYSTEMS. Spring 2018 Lecture 20

CS Operating Systems Lab 3: UNIX Processes

Final Exam. Fall Semester 2016 KAIST EE209 Programming Structures for Electrical Engineering. Name: Student ID:

Operating systems and concurrency - B03

Preview. Interprocess Communication with Pipe. Pipe from the Parent to the child Pipe from the child to the parent FIFO popen() with r Popen() with w

Creating a Shell or Command Interperter Program CSCI411 Lab

Operating System Structure

CSci 4061 Introduction to Operating Systems. Processes in C/Unix

CS 550 Operating Systems Spring Process III

The course that gives CMU its Zip! I/O Nov 15, 2001

CS 33. Architecture and the OS. CS33 Intro to Computer Systems XIX 1 Copyright 2017 Thomas W. Doeppner. All rights reserved.

CS 537 Lecture 2 - Processes

Processes. CS3026 Operating Systems Lecture 05

CSE 333 SECTION 3. POSIX I/O Functions

Windows architecture. user. mode. Env. subsystems. Executive. Device drivers Kernel. kernel. mode HAL. Hardware. Process B. Process C.

MMAP AND PIPE. UNIX Programming 2015 Fall by Euiseong Seo

What is a Process. Preview. What is a Process. What is a Process. Process Instruction Cycle. Process Instruction Cycle 3/14/2018.

System Programming. Process Control III

Processes. Dr. Yingwu Zhu

OS COMPONENTS OVERVIEW OF UNIX FILE I/O. CS124 Operating Systems Fall , Lecture 2

Computer Systems Assignment 2: Fork and Threads Package

Prepared by Prof. Hui Jiang Process. Prof. Hui Jiang Dept of Electrical Engineering and Computer Science, York University

Operating systems. Lecture 7

Amsterdam Compiler Kit-ANSI C compiler compliance statements

Processes. Operating System CS 217. Supports virtual machines. Provides services: User Process. User Process. OS Kernel. Hardware

Process. Prepared by Prof. Hui Jiang Dept. of EECS, York Univ. 1. Process in Memory (I) PROCESS. Process. How OS manages CPU usage? No.

Exceptions and Processes

File Access. FILE * fopen(const char *name, const char * mode);

Fall 2015 COMP Operating Systems. Lab #3

System- Level I/O. Andrew Case. Slides adapted from Jinyang Li, Randy Bryant and Dave O Hallaron

Processes. q Process concept q Process model and implementation q Multiprocessing once again q Next Time: Scheduling

CS 5460/6460 Operating Systems

Operating System Labs. Yuanbin Wu

A Unix Process. Joseph Cordina

CSC209 Fall Karen Reid 1

Processes (Intro) Yannis Smaragdakis, U. Athens

Important Dates. October 27 th Homework 2 Due. October 29 th Midterm

CSC209H Lecture 7. Dan Zingaro. February 25, 2015

Processes and Threads

PESIT Bangalore South Campus Hosur road, 1km before Electronic City, Bengaluru -100 Department of Information Sciences and Engineering

UNIX I/O. Computer Systems: A Programmer's Perspective, Randal E. Bryant and David R. O'Hallaron Prentice Hall, 3 rd edition, 2016, Chapter 10

CS 261 Fall Mike Lam, Professor. Exceptional Control Flow and Processes

Altering the Control Flow

Process Control. Philipp Koehn. 23 April 2018

Maria Hybinette, UGA. ! One easy way to communicate is to use files. ! File descriptors. 3 Maria Hybinette, UGA. ! Simple example: who sort

File Descriptors and Piping

Interrupts, Fork, I/O Basics

Final Precept: Ish. Slides Originally Prepared by: Wonho Kim

de facto standard C library Contains a bunch of header files and APIs to do various tasks

CSC209H Lecture 3. Dan Zingaro. January 21, 2015

Processes. Jin-Soo Kim Computer Systems Laboratory Sungkyunkwan University

프로세스간통신 (Interprocess communication) i 숙명여대창병모

Processes: Introduction. CS 241 February 13, 2012

Unix Processes 1 / 31

everything is a file main.c a.out /dev/sda1 /dev/tty2 /proc/cpuinfo file descriptor int

15-213/18-243, Spring 2011 Exam 2

Operating Systems. Lecture 06. System Calls (Exec, Open, Read, Write) Inter-process Communication in Unix/Linux (PIPE), Use of PIPE on command line

1 Programs and Processes

CSE 451: Operating Systems Winter Module 4 Processes. Mark Zbikowski Allen Center 476

Process management. What s in a process? What is a process? The OS s process namespace. A process s address space (idealized)

Design Overview of the FreeBSD Kernel CIS 657

Network Socket Programming - 1 BUPT/QMUL

Design Overview of the FreeBSD Kernel. Organization of the Kernel. What Code is Machine Independent?

Transcription:

Operating Systems 2230 Computer Science & Software Engineering Lecture 4: Operating System Services All operating systems provide service points through which a general application program may request services of the operating system kernel. These points are variously termed system calls, system traps, or syscalls. It is considered desirable to minimise the number of system calls that an operating system provides, in the belief that doing so simplifies design and improves correctness. Unix 6th Edition (circa 1975) had 52 system calls, whereas modern Linux systems boast 240 (see /usr/include/asm/unistd.h). We are currently seeing an explosion in the number of system calls provided, as systems attempt to support legacy and current 32-bit system calls, while introducing new 64-bit and multi-processor calls. The system call interfaces of modern operating systems are presented as an API of C-language prototypes, regardless of the programmer s choice of application language (C++, Java, Visual-Basic). This is a clear improvement over earlier interfaces in assembly languages. Some material in this lecture is from two texts, both available in the Maths & Physical Sciences Library: Rochkind Marc J. Rochkind, Advanced Unix Programming, Prentice-Hall, 1985. Stevens W. Richard Stevens, Advanced Programming in the Unix Environment, Addison-Wesley, 1992. 1

The technique used in most modern operating systems is to provide an identicallynamed interface function in a standard C library or system s library (for example /lib/libc.so.6). An application program, written in any programming language, may invoke the system calls provided that the language s run-time mechanisms support the operating system s standard calling convention. In the case of a programming language employing a different calling convention, or requiring strong controls over programs (e.g. running them in a sandbox environment, as does Java), direct access to system calls may be limited. As the context switch between application process and the kernel is relatively expensive, most error checking of arguments is performed within the library, avoiding a call of the kernel with incorrect parameters: #include <syscall.h> int write(int fd, void *buf, size_t len) { if (any_errors_in_arguments) { errno = EINVAL; return (-1); return syscall(sys_write, fd, buf, len); But also, system calls need to be paranoid to protect the kernel from access violations! They will check their arguments, too. 2

Status Values Returned from System Calls To provide a consistent interface between application processes and the operating system kernel, a minimal return-value interface is supported by a language s run-time library. The kernel will use a consistent mechanism, such as using a processor register or the top of the run-time stack, to return a status indicator to a process. As this mechanism is usually of a fixed size, such as 32 bits, the value returned is typically an integer, or pointer value. For this reason, globally accessible values such as errno, convey additional state, and values returned via larger structures are passed to the kernel by reference (cf. getrusage()). The status interface employed by Linux and its C interface involves the globally accessible integer variable errno. From /usr/include/asm/errno.h: #define EPERM 1 /* Operation not permitted */ #define ENOENT 2 /* No such file or directory */ #define ESRCH 3 /* No such process */ #define EINTR 4 /* Interrupted system call */ #define EIO 5 /* I/O error */ #define ENXIO 6 /* No such device or address */ #define E2BIG 7 /* Arg list too long */ #define ENOEXEC 8 /* Exec format error */ #define EBADF 9 /* Bad file number */ #define ECHILD 10 /* No child processes */ On success, system calls return with a value of zero; on failure, their return value will be non-zero, and further characterisation of the error appears in errno. ANSI-C standard library functions employ the same practice. As a convenience (not strictly part of the kernel interface), the array of strings sys_errlist[] may be indexed by errno to provide a better diagnostic: 3

#include <stdio.h> #include <errno.h>... if (chdir("/user/someone")!= 0) { printf("cannot change directory, why: %s\n", sys_errlist[errno]); exit(1);... or, alternatively, we may call the function perror() to provide consistent error reporting: #include <stdio.h> #include <errno.h> int main(int argc, char *argv[]) { char *progname;... progname = argv[0]; --argc; ++argv;... if (chdir("/user/someone")!= 0) { perror(progname); exit(1); Note that a successful system call or function call will not set the value of errno to zero. The value will be unchanged. 4

Library Interface to System Calls System calls accept a small, bounded number of arguments; the single syscall entry point loads the system call s number, and puts all arguments into a fixed location, typically in registers, or on the argument stack. Ideally, all system call parameters are of the same length, such a 32-bit integers and 32-bit addresses. It is very uncommon for an operating system to use floating point values, or accept them as arguments to system calls. Depending on the architecture, the syscall() entry point will eventually invoke a TRAP or INT machine instruction an illegal instruction, or software interrupt, causing the hardware to jump to code which examines the required system call number and retrieves its arguments. Such code is often written in assembly language (see <asm/unistd.h>): #define SYSCALL3(x) \.globl NAME(x) ; \ NAME(x): \ push %ebx; \ mov 8(%esp), %ebx; \ mov 12(%esp), %ecx; \ mov 16(%esp), %edx; \ lea SYS_##x, %eax; \ int $0x80; \ pop %ebx; \ ret; \ END(x) There is a clear separation of duties between system calls and their calling functions. For example, the memory allocation function malloc() calls sbrk() to extend a process s memory space by increasing the process s heap. malloc() and free() later manage this space. 5

The Execution Environment of a Process Although C programs appear to begin at main() or its equivalent, standard libraries must often prepare the process s execution environment. An additional function, linked at a known address, is often provided by the standard run-time libraries to initialise that environment. For example, the C run-time library provides functions (such as) _init() to initialise (among other things) buffer space for the buffered standard I/O functions. (For example, /usr/include/linux/limits.h limits a process s arguments and environment to 128KB). high address command line arguments and environment variables stack heap uninitialised data (bss) initialised to zero by exec() initialised data code read from program file by exec() low address Figure 1: The execution environment of a process In particular, command-line arguments and environment variables are located at the beginning of each process s stack, and addresses to these are passed to main() and assigned to the global variable environ (Figure 1). 6

As with command-line arguments, each process is invoked with a vector of environment variables (null-terminated character strings) (Figure 2). environment pointer environment list environment strings environ: HOME=/home/kanga/year3/charles p\0 PATH=/bin:/usr/bin:/usr/local/bin\0 SHELL\/bin/zsh\0 LOGNAME=charles p\0 TERM=xterm\0 NULL Figure 2: The environment variables of a process These are typically maintained by application programs, such as a commandinterpreter (or shell), with calls to standard library functions such as putenv() and getenv(). #include <stdio.h> #include <stdlib.h> extern char **environ; int main(int argc, char *argv[]) { char **envp; putenv("editor=vi"); envp = environ; while (*envp) { printf("%s\n", *envp); ++envp; return (0); 7

A process s environment (along with many other attributes) is inherited by its child processes. Interestingly, the user s environment variables are never used by the kernel itself. However, a programming language s run-time library may use environment variables to vary its default actions. For example, the C library function execlp() may be called to commence execution of a new program (Figure 3). execlp execl execle build argv build argv build argv execvp try each PATH prefix execv use environ execve (system call) Figure 3: The invocation of a process execlp() receives the name of the new program, and the arguments to provide to the program, however it does not know how to find the program. execlp() locates the value of the environment variable PATH, assuming it to be a colon-separated list of directory names to search, e.g. PATH= /bin:/usr/bin:.:/usr/local/bin, and appends the program s name to each directory component. execlp() makes successive calls to the system call execve() until one of them succeeds in beginning execution of the required program. 8

Similarly, a process is quickly terminated by the system call exit(), but the library function exit() is usually called to flush buffered I/O, and call any functions requested via on_exit() and atexit(). We can consider _init() to include (Figure 4): int _init(int argc, char *argv[], char **envp) {... set up the library s run-time state... exit( main( argc, argv, environ = envp ) ); user functions exit handler call exit call _exit exit handler main function call exit exit function user process call _exit call exit call _exit C startup routine standard I/O cleanup KERNEL Figure 4: The execution of a process This shows how main() may either call exit(), call return, or simply fall past its bottom curly bracket. 9

Creating A New Linux Process We shall first create a new process by calling the fork() system call. Firstly, we note that a process is uniquely identified by an integer value termed its process identifier, process-id, or pid. A process can get its own process-id with the system call getpid(), and get its parent s process-id with getppid(). fork() is very unusual because it returns different values in the (existing) parent process, and in the (new) child process: the value returned by fork() in the parent process will be the process-id of the child process; the value returned by fork() in the child process will be 0, indicating that it is the child, because 0 is not a valid process-id. Each successful invocation of fork() returns a new monotonically increasing process-id (the kernel wraps the value back to the first unused positive value when it reaches 30,000). 10

int main(int argc, char *argv[]) { int pid; switch (pid = fork()) { case -1 : perror("fork()"); exit(1); break; case 0: /* child process */ printf("value of pid=%d\n", pid); printf("child s pid=%d\n", getpid()); printf("child s parent is pid=%d\n", getppid()); break; default: /* original, parent process */ sleep(1); printf("value of pid=%d\n", pid); printf("parent s pid=%d\n", getpid()); printf("parent s parent is pid=%d\n", getppid()); break; fflush(stdout); return (0); produces: child s value of pid=0 child s pid=5642 child s parent has pid=5641 parent s value of pid=5642 parent s pid=5641 parent s parent has pid=3244 Of note, we call sleep(1) to separate the outputs, and fflush() in each process to force its output to appear. 11

Variables in Parent and Child Processes The (existing) parent process and the (new) child process continue their own execution. Importantly, both the parent and child have their own copy of their program s variables. The parent naturally uses the variables that it had before it called fork(); the child receives its own copy of the same variables. The copy is made at the time of the fork(). As execution proceeds, each process may update its own variables without affecting the other process. Waiting for a Process to Terminate If a single program has two distinct execution paths/sequences, then the parent and child may run different parts of the same program. Typically the parent will want to know when the child terminates. The expected sequence of events is: the parent waits for the child s termination, calling the blocking function wait( &status ). the child calls exit(value), with an integer value to represent its success or failure. By convention, zero indicates successful execution, non-zero otherwise. the child s value given to exit() is written by the operating system to the parent s status. 12

Running a New Program Of course, we do not expect a single program to meet all our computing requirements, and so we need the ability to commence the execution of new programs after a fork. Under Linux, a new program may replace the currently running program. The new program runs as the same process (confusing!), by overwriting the current process s memory (instructions and data) with the instructions and data of the new program. The single system call execve() requests the execution of a new program as the current process: char *newargs[] = { "ls", "-l", "-F", NULL ;... execve( "/bin/ls", newargs, environ ); exit(1); On success, execve() does not return (to where would it return?): on error, -1 is returned, and errno is set appropriately. The single system call is supported by a number of library functions (see man execl) which simplify the calling sequence. Typically, the call to execve() (via one of its library interfaces) will be made in a child process, while the parent process waits for the child to terminate. 13

File Based Input and Output (I/O) We next consider how the operating system kernel presents and supports filebased I/O. To the kernel, all references to I/O operations are again provided through system calls. Although most languages and run-time libraries provide significantly enhanced I/O services, eventually references must be made to the kernel. Most operating systems present an interface to I/O based on internal handles (Windows-NT) or descriptors (Linux) (Figure 5). VNODE TABLE PROCESS TABLE ENTRY fd 0: fd 1: fd 2: flags rw r w ptr FILE TABLE file status flags file offset v node pointer v node information i node information file s size file status flags file offset v node pointer v node information i node information file s size Figure 5: File tables Their main purpose is to make the internal lookup and management of I/O resources (such as kernel buffers and pointers) more efficient. They also simplify the interface somewhat. An alternative, cumbersome, interface could require a file s name, access requirements and internal offset to be provided with each I/O request. 14

Instead, the descriptor is returned from a request to open or allocate an I/O service, and is expected in subsequent requests for the same service. #include <fcntl.h> int main(int argc, char *argv[]) { int i, fd, got; char buf[buffsize]; argc--; argv++; /* Skip over command-line arguments */ for (i=0 ; i<argc ; i++) { if ((fd = open(*argv, O_RDONLY, 0))!= -1) { while ((got = read(fd, buf, sizeof (buf))) > 0) write(1, buf, got); close(fd); argv++; return (0); This program would be invoked as mycat filename1 filename2... 15

Sharing File I/O Attributes It is a common requirement that multiple (often independent) processes must have the same file open. Of course, their interaction with this single file (often reading and seeking within) must not affect other processes (Figure 6). VNODE TABLE PROCESS TABLE ENTRY fd 0: fd 1: fd 2: flags rw r w ptr FILE TABLE file status flags file offset v node pointer v node information i node information file s size PROCESS TABLE ENTRY file status flags file offset v node pointer v node information i node information file s size fd 0: fd 1: fd 2: flags rw r w ptr Figure 6: Processes sharing a file 16

Also, there are occasions when a single process wishes to refer to the same file using different file descriptors (Figure 7). VNODE TABLE PROCESS TABLE ENTRY fd 0: fd 1: fd 2: flags rw r w ptr FILE TABLE file status flags file offset v node pointer v node information i node information file s size Figure 7: Process sharing a file with itself Here, reading (or writing) using one file descriptor will advance the read (or write) pointer associated with the other. However, the process s association with each file will not cease until all file descriptors pointing to that file are close()d. The file table maintains a count of the number of times each file is opened, and only when this drops to zero, is the file truly closed. 17

Creating A Pipe Between Processes Pipes are (unnamed) kernel I/O buffers between processes: int main(int argc, char *argv[]) { int p[2]; if (pipe(p) < 0) { perror("pipe()"); exit(1); /* We will have ps aux (the child) wc -l (the parent) The child writes to p[1] and the parent reads from p[0] */ switch (fork()) { case -1 : perror("fork()"); exit(1); break; case 0: /* child process */ close(0); dup2(p[1], 1); close(p[0]); close(p[1]); execl("/bin/ps", "ps", "aux", (char *)NULL); perror("execl(ps)"); exit(1); break; default: /* original, parent process */ dup2(p[0], 0); close(p[0]); close(p[1]); execl("/usr/bin/wc", "wc", "-l", (char *)NULL); perror("execl(wc)"); exit(1); break; return (0); 18

The Relationship to Standard I/O Libraries The size of an I/O request can dramatically affect the execution speed of an application. Moreover, many small I/O requests result in many system calls and, hence, context switches. Most programming languages provide libraries of buffered I/O routines which make a kernel request only when their buffer is exhausted (or full), their buffer is flushed, or the process exits. When a library s initialisation routine is first called (such as via _init()), a buffer is dynamically allocated for any pre-opened standard file descriptors (0=stdin, 1=stdout, 2=stderr). Provided that an application does not mix read()s and write()s, with fgets()s and fputs()s, I/O remains sequential. 19

We can rewrite our simple mycat program using C s standard I/O library routines: #include <stdio.h> int main(int argc, char *argv[]) { FILE *fp; char buf[bufsiz]; argc--; argv++; /* Process command-line arguments */ for (i=0 ; i<argc ; i++) { if ((fp = fopen(*argv, "r"))!= (FILE *)NULL) { while (fgets(buf, sizeof (buf), fp))!= NULL) fputs(buf, stdout); fclose(fp); argv++; return (0); Most raw I/O system calls must now have standard I/O equivalents which deal with the allocated buffers. For example, consider the relationship between lseek() (system call) and fseek() (standard I/O). An already open file descriptor can be wrapped up in a buffer with fdopen() and a buffer flushed with fflush(). 20