Credit Where Credit is Due
• These slides for CSC209H have been developed by Sean Culhane, a previous instructor: I have modified them for this presentation of the Introduction to course, but must acknowledge their origins! UNIX
S -1 S -2
Logging in Shells
• Login name, password • Bourne shell, C shell, Korn shell, tcsh • System password file: usually “/etc/passwd” – command line interpreter that reads user input and executes commands
• /etc/passwd has 7 colon-separated fields: > ls -l /var/shell total 6 maclean:x:132:114:James MacLean: lrwxrwxrwx 1 root 12 May 15 1996 csh -> /usr/bin/csh ^^^1^^^ 2 ^3^ ^4^ ^^^^^^5^^^^^^ lrwxrwxrwx 1 root 12 May 15 1996 ksh -> /usr/bin/ksh /u/maclean:/var/shell/tcsh lrwxrwxrwx 1 root 17 May 15 1996 newsh -> /local/sbin/newsh ^^^^^6^^^^ ^^^^^^^7^^^^^^^ lrwxrwxrwx 1 root 11 May 15 1996 sh -> /usr/bin/sh lrwxrwxrwx 1 root 15 May 15 1996 tcsh -> /local/bin/tcsh 1: user name 5: “in real life” 2: password (hidden) 6: $HOME 3: uid 7: shell 4: gid
S -3 S -4
newsh “man page” Files and Directories newsh • UNIX filesystem is a hierarchical arrangement of directories & files newsh - shell for new users • Everything starts in a directory called root whose name is the single SYNOPSIS character / newsh DESCRIPTION • Directory: file that contains directory entries newsh shows the CDF rules, runs passwd to force the user to • File name and file attributes change his or her password, and runs chsh to change the – type user's shell to the default system shell (/local/bin/tcsh). – size FILES /etc/passwd – owner SEE ALSO – permissions passwd(1), chsh(1) – time of last modification HISTORY Written by John DiMarco at the University of Toronto, CDF
S -5 S -6
1 Files: an example Directories and Pathnames
> stat /u/maclean • Command to create a directory: mkdir • Two file names automatically created:
File: "/u/maclean" -> "/homes/u1/maclean" – current directory (“.”) Size: 17 Allocated Blocks: 0 Filetype: Symbolic Link – parent directory (“..”) Mode: (0777/lrwxrwxrwx) Uid: ( 0/ root) Gid: ( 1/ other) Device: 0/1 Inode: 221 Links: 1 Device type: 0/0 Access: Sun Sep 13 18:32:37 1998 • A pathname is a sequence of 0 or more file names, separated by /, Modify: Fri Aug 28 15:42:09 1998 optionally starting with a / Change: Fri Aug 28 15:42:09 1998 – absolute pathnames: begins with a / – relative pathnames: otherwise
S -7 S -8
Working directory Permissions
• Current working directory (cwd) • When a file is created, the UID and GID of the creator are remembered – directory from which all relative pathnames are interpreted • Every named file has associated with it a set of permissions in the form of a string of bits: • Change working directory with the command: cd or chdir rwxs rwxs rwx • Print the current directory with the command: pwd owner group others • Home directory: working directory when we log in mode regular directory – obtained from field 6 in /etc/passwd r read list contents • Can refer to home directory as ~maclean or $HOME w write create and remove x execute search s setuid/gid n/a
• setuid/gid executes program with user/group ID of file’s owner • Use chmod to change permissions S -9 S -10
Input and Output Basic UNIX Tools
• File descriptor man ("man -k", "man man") (1.13) – a small non-negative integer used by kernel to identify a file ls -la ("hidden files") cd • A shell opens 3 descriptors whenever a new program is run: pwd – standard input (normally connected to terminal) du, df – standard output chmod – standard error cp, mv, rm (in cshrc: "alias rm rm -i" ... ) mkdir, rmdir (rm -rf) • Re-direction: diff ls >file.list grep sort
S -11 S -12
2 More Basic UNIX Tools C Shell Commands
more, less, cat which head, tail, wc echo compress, uncompress, bg, fg, jobs, kill, nice gzip, gunzip, zcat alias, unalias lpr, lpq, lprm dirs, popd, pushd quota -v a209xxxx exit pquota -v a209xxxx source logout, exit rehash mail, mh, rn, trn, nn set/unset who, finger date, password
S -13 S -14
Additional Commands
arch cal Introduction to the ps hostname C Shell clear tar uptime xdvi gs, ghostview setenv, printenv
S -15 S -16
What is the Shell? csh Shell Facilities
• A command-line interpreter program that is the interface between the • Automatic command searching (6.2) user and the Operating System. • Input-output redirection (6.3) • The shell: • Pipelining commands (6.3) – analyzes each command • Command aliasing (6.5) – determines what actions to be performed • Job control (6.4) – performs the actions • Command history (6.5) • Example: • Shell script files (Ch.7) wc -l file1 > file2
S -17 S -18
3 I/O Redirection Pipes
• stdin (fd=0), stdout (fd=1), stderr (fd=2) • Examples: who | wc -l • Redirection examples: ( <, >, >>, >&, >!, >&! ) ls /u/csc209h |& sort -r fmt • For a pipeline, the standard output of the first process is connected to fmt < personal_letter the standard input of the second process fmt > new_file fmt < personal_letter > new_file fmt >> personal letter fmt < personal_letter >& new_file fmt >! new_file fmt >&! new_file
S -19 S -20
Filename Expansion Command Aliases
• Examples: • Examples: ls *.c alias md mkdir rm file[1-6].? alias lc ls -F cd ~/bin alias rm rm -i ls ~culhane \rm *.o unalias rm * Matches any string (including null) alias ? Matches any single character alias md [...] Matches any one of the enclosed characters alias cd 'cd \!*; pwd' [.-.] Matches any character lexically between the pair [!...] Matches any character not enclosed
S -21 S -22
Job Control Some Examples
a | b | c • A job is a program whose execution has been initiated by the user – connects standard output of one program to standard input of another • At any moment, a job can be running or stopped (suspended) – shell runs the entire set of processes in the foreground • Foreground job: – prompt appears after c completes – a program which has control of the terminal a & b & c • Background job: – executes a and b in the background and c in the foreground – runs concurrently with the parent shell and does not take control of – prompt appears after c completes the keyboard a & b & c & • Initiate a background job by appending the “&” metacharacter – executes all three in the background • Commands: jobs, fg, bg, kill, stop – prompt appears immediately a | b | c & – same as first example, except it runs in the background and prompt appears immediately
S -23 S -24
4 The History Mechanism Shell Variables (setting)
• Example session: • Examples: alias grep grep -i set V grep a209 /etc/passwd >! ~/list set V = abc history set V = (123 def ghi) cat ~/list set V[2] = xxxx !! set !2 unset V !-4 !c !c > newlist grpe a270 /etc/passed | wc -l ^pe^ep
S -25 S -26
Shell Variables Shell Control Variables (referencing and testing)
• Examples: filec a given with tcsh echo $term prompt my favourite: set prompt = “%m:%~%#” echo ${term} ignoreeof disables Ctrl-D logout echo $V[1] history number of previous commands retained echo $V[2-3] mail how often to check for new mail echo $V[2-] path list of directories where csh will look for commands (†) set W = ${V[3]} noclobber protects from accidentally overwriting files in redirection set V = (abc def ghi 123) noglob turns off file name expansion set N = $#V echo $?name • Shell variables should not to be confused with Environment variables. echo ${?V}
S -27 S -28
Variable Expressions File-oriented Expressions
• Examples: Usage: set list1 = (abc def) -option filename set list2 = ghi where 1 (true) is returned if selected option is true, and 0 (false) otherwise set m = ($list2 $list1) -r filename Test if filename can be read -e filename Test if filename exists @ i = 10 # could be done with “set i = 10” -d filename Test if filename is a directory @ j = $i * 2 + 5 -w filename Test if filename can be written to @ i++ -x filename Test if filename can be executed -o filename Test if you are the owner of filename • comparison operators: ==, !=, <, <=, >, >=, =~, !~ • See Wang, table 7.2 (page 199) for more
S -29 S -30
5 csh Script Execution
• Several ways to execute a script: 1) /usr/bin/csh script-file 2) chmod u+x script-file, then: csh a) make first line a comment, starting with “#” – (this will make your default shell run the script-file) b) make first line “#!/usr/bin/csh” – (this will ensure csh runs the script-file, preferred!)
• Useful for debugging your script files: “#!/usr/bin/csh -x” or “#!/usr/bin/csh -v” • Another favourite: “#!/usr/bin/csh -f”
S -31 S -32
if Command if Command (cont.)
• Syntax: • Syntax: if ( test-expression ) command if ( test-expression ) then • Example: shell commands if ( -w $file2 ) mv $file1 $file2 else if ( test-expression ) then shell commands • Syntax: else if ( test-expression ) then shell commands shell commands endif else shell commands endif
S -33 S -34
foreach Command while Command • Syntax: • Syntax: while ( expression ) foreach item ( list-of-items ) shell commands shell commands end end • Example: • Example: set count = 0 foreach item ( ‘ls *.c’ ) set limit = 7 cp $item ~/.backup/$item while ( $count != $limit ) end echo “Hello, ${USER}” @ count++ • Special statements: end break causes control to exit the loop • break and continue have same effects as in foreach continue causes control to transfer to the test at the top
S -35 S -36
6 switch Command goto Command
• Syntax: • Syntax: switch ( test-string ) goto label case pattern1: ... shell commands other shell commands breaksw ... case pattern2: shell commands label: breaksw shell commands default: shell commands breaksw end
S -37 S -38
repeat Command Standard Variables
• Syntax: $0 Þ calling function name repeat count command $N Þ Nth command line argument value $argv[N] Þ same as above • Example: $* Þ all the command line arguments repeat 10 echo “hello” $argv Þ same as above $# Þ the number of command line arguments $< Þ an input line, read from stdin of the shell $$ Þ process number (PID) of the current process $! Þ process number (PID) of the last background process $? Þ exit status of the last task
S -39 S -40
Example: ls2 Other Shell Commands # Usage: ls2 # produces listing that separately lists files and dirs
source file set dirs = `ls -F | grep '/'` shift set files = `ls -F | grep -v '/'` shift variable rehash echo "Directories:" foreach dir ($dirs) • Other commands … see Wang, Appendix 7 echo " " $dir end
echo "Files:" foreach file ($files) echo " " $file end
S -41 S -42
7 Example: components Example: debug #!/usr/bin/csh -x while ( $#argv ) #!/usr/bin/csh -f echo $argv[1] set test = a/b/c.d shift echo "the full string is:" $test end echo "extension (:e) is: " $test:e # while ( 2 ) Þ output of "debug a b" echo "head (:h) is: " $test:h # echo a echo "root (:r) is: " $test:r # a echo "tail (:t) is: " $test:t # shift # end ### output: # while ( 1 ) # the full string is: a/b/c.d # echo b # extension (:e) is: d # b # head (:h) is: a/b # shift # root (:r) is: a/b/c # end # tail (:t) is: c.d # while ( 0 )
S -43 S -44
Example: newcopy
#!/usr/bin/csh -f ### An old exam question: # Write a csh script “newcopy
S -45 S -46
What is UNIX good for? History (Introduction)
• Ken Thompson working at Bell Labs in 1969 wanted a small • Supports many users running many programs at the same time, all MULTICS for his DEC PDP-7 sharing (transparently) the same computer system • He wrote UNIX which was initially written in assembler and could • Promotes information sharing handle only one user at a time • More than just used for running software … geared towards facilitating • Dennis Ritchie and Ken Thompson ported an enhanced UNIX to a the job of creating new programs. So UNIX is “expert friendly” PDP-11/20 in 1970 • Got a bad reputation in business because of this aspect • Ritchie ported the language BCPL to UNIX in 1970, cutting it down to fit and calling the result “B” • In 1973 Ritchie and Thompson rewrote UNIX in “C” and enhanced it some more • Since then it has been enhanced and enhanced and enhanced and … • See Wang, page 1 for a brief discussion of UNIX variations • POSIX (portable operating system interface) - IEEE, ANSI
S -47 S -48
8 Some Terminology Concurrency
• Program: executable file on disk • Most modern developments in computer systems & applications rely on: • Process: executing instance of a program – communication: the conveying of info by one entity to another • Process ID: unique, non-negative integer identifier (a handle by which – concurrency: the sharing of resources in the same time frame to refer to a process) note: concurrency can exist in a single processor system as well as in • UNIX kernel: a C program that implements a general interface to a a multiprocessor system. computer to be used for writing programs • System call: well-defined entry point into kernel, to request a service • Managing concurrency is difficult, as execution behaviour (e.g. relative • UNIX technique: for each system call, have a function of same name in order of execution) is not always reproducible the standard C library • More details on this in the last 1/3 or the course – user process calls this function – function invokes appropriate kernel service
S -49 S -50
Fork Fork example
• The fork system call is used to create a duplicate of the currently int i, pid; running program i = 5; process printf( “%d\n”, i ); A #1 process pid = fork(); A fork process if ( pid != 0 ) A #2 i = 6; /* only the parent gets to here */ else • The duplicate (child process) and the original (parent process) both i = 4; /* only the child gets to here */ proceed from the point of the fork with exactly the same data • The only difference between the two processes is the fork return value, i.e. (… see next slide) printf( “%d\n”, i );
S -51 S -52
Exec Exec example
PROGRAM X • The exec system call replaces the program being run by a process by a int i; different one i = 5; • The new program starts executing from its beginning printf( “%d\n”, i );
process A process A exec( “Y” ); exec(“Y”) running running i = 6; program X program Y printf( “%d\n”, i );
• Variations on exec: execl(), execv(), etc. which will be PROGRAM Y discussed later in the course printf( “hello” ); • On success, exec never returns; on failure, exec returns with value -1
S -53 S -54
9 Processes and File Descriptors PIDs and FDs across an exec
• File descriptors (11.1) belong to processes, not programs • File descriptors are maintained across exec calls: • They are a process’ link to the outside world
0 1 process A process A running exec(“Y”) running process 2 program X program Y A 3 3 3 4 /u/culhane/file /u/culhane/file 5
S -55 S -56
PIDs and FDs across a fork
• File descriptors are maintained across fork calls: More UNIX process A #1 Concepts fork 3
process A #2
3
/u/culhane/file
S -57 S -58
Initializing UNIX Initializing UNIX
• The first UNIX program to be run is called “/etc/init” • It forks and then execs one “/etc/getty” per terminal • getty sets up the terminal properly, prompts for a login name, and then execs “/bin/login” init init init init init • login prompts for a password, encrypts a constant string using the password as the key, and compares the results against the entry in the file “/etc/passwd” init getty login csh • If they match, “/usr/bin/csh” (or whatever is specified in the passwd file as being that user’s shell) is exec’d • See “ ”, “ ”, etc. to see what’s running at any given time • When the user exits from their shell, the process dies. Init finds out top ps -aux about it (wait system call), and forks another process for that terminal • The only way to create a new process is to duplicate an existing process, therefore the ancestor of ALL processes is init, with pid=1
S -59 S -60
10 How csh runs commands How csh runs (cont.)
> date process running shell, duplicate: Sun May 25 23:11:12 EDT 1997 PID 34 fork() • When a command is typed csh forks and then execs the typed command: parent process running shell, child process running shell, PID 35 PID 34, waiting for child csh csh csh csh differentiate: exec() wait for child: child process running utility, PID 35 csh date wait()
• After the fork and exec, file descriptors 0, 1, and 2 still refer to the terminate: exit() standard input, output, and error in the new process signal parent process running shell, • By UNIX programmer convention, the executed program will use these PID 34, awakens child process terminates PID 35 descriptors appropriately
S -61 S -62
Fork: PIDs and PPIDs PID/PPID example
#include
printf( "PID %d terminates.\n\n", getpid() ); return( 1 ); }
S -63 S -64
Concurrency Example Producer/Consumer Problem
Program a: Program b: • Simple example: #!/usr/bin/csh -f #!/usr/bin/csh -f who | wc -l @ count = 0 @ count = 0 • Both the writing process (who) and the reading process (wc) of a while( $count < 200 ) while( $count < 200 ) pipeline execute concurrently @ count++ @ count++ • A pipe is usually implemented as an internal OS buffer echo -n "a" echo -n "b" • It is a resource that is concurrently accessed by the reader and by the end end writer, so it must be managed carefully
• When run sequentially (a;b) output is as expected • When run concurrently (a&;b&) output is interspersed, and re-running it may produce different output
S -65 S -66
11 Producer/Consumer (cont.) Machine Language
• consumer should be blocked when buffer is empty • CPU interprets machine language programs: • producer should be blocked when buffer is full 1100101 11111111 11100110 00000000 • producer and consumer should run independently so far as the buffer 1010001 00000010 01011101 00000000 capacity and contents permit 1100101 00000000 11111111 00100100 • producer and consumer should never both be updating the buffer at the • Assembly language instructions bear a one-to-one correspondence same instant (otherwise, data integrity cannot be guaranteed) with machine language instructions • producer/consumer is a harder problem if there is more than one MOVE FFFFDC00, D0 % b = a * 2 consumer and/or more than one producer MUL #2, D0 MOVE D0, FFFDC04
S -67 S -68
Compilation Tools and Applications
• High Level Language (HLL) is a language for expressing algorithms whose meaning is (for the most part) independent of the particular computer system being used vi cat more date gcc gdb … • A compiler translates a high-level language into object files (machine csh (or any other shell) language modules). • A linker translates object files into a machine language program (an executable) UNIX system services • Example: UNIX kernel in C – create object file “fork.o” from C program “fork.c”: gcc -c fork.c -o fork.o computer – create executable file “fork” from object file “fork.o”: gcc fork.o -o fork
S -69 S -70
C and libc Miscellaneous
• We haven’t gone over these in any detail yet: C Application Programs – ln (symbolic links) libc - C Interface to UNIX system services – chmod (permissions) – man -k fork and man 2 fork (ie: viewing specific pages) – du (disk space usage) – quota -v username and pquota -v username UNIX system services – noglob – … any others ????? UNIX kernel in C
computer
S -71 S -72
12 Core Functionality of Shells
• built-in commands Still more • variables • wildcards (file name expansion) UNIX • background processing • scripts • redirection • pipes • subshells • command substitution
S -73 S -74
Executables vs. Built-ins Variables
• Most UNIX commands invoke utility programs that are stored as • Two kinds of variables: executable files in the directory hierarchy – local • Shells also contains several built-in commands, which it executes – environment internally • Both hold data in a string format • Type for a partial listing man shell_builtins • Main difference: when a shell invokes another shell, the child shell • Built-in commands execute as subroutines, and do not spawn a child- gets a copy of its parent’s environment variables, but not its local shell shell via fork() variables – Expect built-in (e.g. cd) to be faster than external (e.g. ls) • Any local shell variables which have corresponding environment variables (term, path, user, etc.) are automatically inherited by Built-In: Non-Built-In: subshells cd, echo, jobs, fg, bg ls, cp, more
S -75 S -76
Variables (cont.) Startup Files
• Local (shell) variables: • Every time csh is invoked, $HOME/.cshrc is read, and contents of – Simple variable: holds one value the file are executed – List variable: holds one or more values • If a given csh invocation is the login shell, $HOME/.login will also – Use set and unset to define, delete, and list values be read and its contents executed • Environment variables: • csh -f starts a shell without reading initialization files • opening a new xterm -ls under X-windows will open a new login shell – Use setenv and printenv to set and list values – All environment variables are simple (ie: no list variables … compare shell variable $path to enviroment variable $PATH )
S -77 S -78
13 Sourcing files Input Processing
• Assume you create a file called “my_aliases” • When a input is typed, it is processed as follows: – history substitution • Typing csh my_aliases executes the lines in this file, but it occurs in the forked csh, so it will have no lasting effect on the – alias substitution interactive parent shell – variable substitution – command substitution • Correct method is to use the source command: – file name expansion source my_aliases
• Common setup: – put all aliases in a file called $HOME/.alias – add the line “source .alias” to the last line of $HOME/.cshrc
S -79 S -80
Command Substitution
• Can substitute the output from a command into the text string of a command UNIX set dir = `pwd` set name = `pwd`/test.c Systems Programming set x = `/bin/ls -l $file`
S -81 S -82
System Calls Error Handling
• System calls: • All system calls return -1 if an error occurs – perform a subroutine call directly to the UNIX kernel • errno: – global variable that holds the numeric code of the last system call • 3 main categories: • perror(): – file management – a subroutine that describes system call errors – process management • Every process has errno initialized to zero at process creation time – error handling • When a system call error occurs, errno is set • See /usr/include/sys/errno.h • A successful system call never affects the current value of errno • An unsuccessful system call always overwrites the current value of errno
S -83 S -84
14 perror() perror() example
• Library routine: #include
S -85 S -86
Processes Termination Zombies
• Orphan process • Zombie process: – a process whose parent is the init process (pid 1) because its – a process that is “waiting” for its parent to accept its return code original parent died before it did – a parent accepts a child’s return code by executing wait() • Terminating a process: exit() – shows up with 'Z' in ps -a • System call: • A terminating process may be a (multiple) parent; the kernel ensures int exit( int status ) all of its children are orphaned and adopted by init • Every normal process is a child of some parent, a terminating process sends its parent a SIGCHLD signal and waits for its termination code status to be accepted • The C shell stores the termination code of the last command in the local shell variable status
S -87 S -88
wait() Signals
• Unexpected/unpredictable events: • Waiting for a child: system call is – floating point error int wait( int *status ) – interval timer expiration (alarm clock) • A process that calls wait() can: – death of a child – block (if all of its children are still running) – control-C (termination request) – return immediately with the termination status of a child (if a child – control-Z (suspend request) has terminated and is waiting for its termination status to be • Events are called interrupts fetched) • When the kernel recognizes such an event, it sends the corresponding – return immediately with an error (it it doesn’t have any child process a signal processes) • Normal processes may send other processes a signal, with permission • More details in a few weeks, when we cover Chapter 11 of Wang (useful for synchronization) • Again, we’ll cover this in much more detail in a few weeks
S -89 S -90
15 Race conditions Example: Race Condition
• A race condition occurs when multiple processes are trying to do #!/usr/bin/csh -f something with shared data and the final outcome depends on the order set count = 0 in which the processes run while( $count < 50 ) • This is a situation when using forks: if any code after the fork set sharedData = `cat shareVal` explicitly or implicitly depends on whether or not the parent or child runs first after the fork @ sharedData++ echo $sharedData >! shareVal • A parent process can call wait() for a child to terminate (may block) • A child process can wait for the parent to terminate by polling it @ count++ (wasteful) end • Standard solution is to use signals • Create two identical copies, “a” and “b” • Run as: ./a&; ./b&
S -91 S -92
Miscellaneous
• From Wang: – rlogin C: Primer and – rsh – rcp Advanced Topics – telnet – ftp – finger
S -93 S -94
Style Brace Styles
• Basics: • K&R: • non-K&R: – comments if (total > 0) if (total > 0) { – white space { printf( “Pay up!” ); – modularity printf("Pay up!"); total = 0; total = 0 ; • Naming conventions: } else { } – variableNames ("Hungarian Notation": m_pMyInt, bDone) printf( “Goodbye” ); else } { – FunctionNames printf("Goodbye"); – tTypeDefinitions } – CONSTANTS
S -95 S -96
16 Variables and Storage Operators
• Syntax: • Arithmetic Operators:
S -97 S -98
Arrays Decision and Control
• Arrays start at ZERO! (a mistake you will make often, trust me) if( condition ) • Arrays of int, float, etc. are pretty intuitive statement; int months[12]; else float scores[30]; statement; while( condition ) • Strings are arrays of char (C’s treatment of strings is not so intuitive) statement – see Wang, Appendix 12 for string handling functions for( initial; condition; iteration ) • Multi-dimensional arrays: statement; int matrix[2][4]; (not matrix[2,4]) do statement; while( condition )
• break and continue useful inside loops
S -99 S -100
Decision and Control (cont) Scope
switch ( expression ) • Scopes are delimited with curly braces case constant1: “{”
S -101 S -102
17 Functions Preprocessor
• Definition: #include (
S -103 S -104
Structs Typedefs and Enumerated Types struct [
S -105 S -106
Pointers Pointers (cont)
• A pointer is a type that points to another type in memory • Use brackets to avoid confusion: – ie: *(currPtr++); is very different from (*currPtr)++; • Pointers are typed: a pointer to an int is different than a pointer to a long • Using ++ on a pointer will increment the pointer’s address by the size • An asterisk before a variable name in its declaration makes it a pointer of the type pointed to – i.e.: int *currPointer; (pointer to an integer) – i.e.: char *names[10]; (an array of char pointers) • You can use pointers as if they were arrays (in fact, arrays are implemented a pointers) • An ampersand (&) gives the address of a pointer – i.e.: currPtr = &value; (makes currPtr point to value)
• An asterisk can also be used to de-reference a pointer – i.e.: currValue = *currPtr;
S -107 S -108
18 Command Line Arguments Casting
int main( int argc, char *argv[] ) • You can force one type to be interpreted as another type through { casting, ie: . . . someSignedInt = (signed int) someUnsignedInt; • argc is the number of arguments on the command line, including the • Be careful, as C has no type checking, so you can mess things up if program name you’re not careful • The array argv contains the actual arguments • Example: • NULL pointer should always be cast, ie: if( argc == 3 ) – (char *) NULL, (int *) NULL, etc. printf( “file1:%s file2:%s\n”, argv[1], argv[2] );
S -109 S -110
Opening and Closing Files
FILE *fp; Library Functions fp = fopen( fileName, “r” ); fclose( fp ); for I/O • fp is of type “FILE*” (defined in stdio.h) • fopen returns a pointer (or NULL if unsuccessful) to the specified fileName with the given permissions: – “r” read – “w” write (create new, or wipe out existing fileName) – “a” append (create new, or append to existing fileName) – “r+” read and write
S -111 S -112
Character-by-Character I/O Line-by-Line Input fgetc( fp ) # returns next character from files referenced by fp fgets( data, size, fp ) # read next line from fp (up to size) getc( fp ) # same as fgetc, but implemented as a macro gets( data ) # read next line from stdin getchar() # same as getc( stdin ) • fgets() is preferable to gets() • These return the constant “EOF” when the end-of-file is reached • Returns address of data array (or NULL if EOF or other error occurred) • Example: fputc( c, fp ) # outputs character c to file referenced by fp #define MAX_LENGTH 256 putc( c, fp ) # same as fputc, but implemented as a macro char inputData[MAX_LENGTH]; putchar( c ) # same as putc( c, stdout ) FILE *fp; fp = fopen( argv[1], “r” ); fgets( inputData, MAX_LENGTH, fp );
S -113 S -114
19 Line-by-Line Output Formatted Output fputs( data, fp ) # prints string “data” on stream referenced by fp printf( fmt, args ... ) puts( data ) # same as fputs( data, stdout ) except a newline fprintf( fp, fmt, args ... ) is automatically appended sprintf( string, fmt, args ... )
• Examples: fprintf( stderr, “Can’t open %s\n”, argv[1] ); sprintf( fileName, “%s”, argv[1] );
• sprintf example above better achieved with “strcpy()” function • K&R book or man pages for all the details
S -115 S -116
Formatted Input Binary I/O scanf( fmt, *args ... ) fread( buf, size, numItems, fp ) fscanf( fp, fmt, *args ... ) fwrite( buf, size, numItems, fp ) sscanf( string, fmt, *args ... ) • Examples: • Examples: fread( readBuf, sizeof( char ), 80, stdin ); fscanf( fp, “%s %s”, firstName, lastname ); fwrite( writeBuf, sizeof(struct utmpx), 1, fp ); sscanf( argv[1], “%d %d”, &int1, &int2 ); • Returns number of successful items read or written • Returns number of successful args matched … be careful, scanf should only be used in limited cases where exact format is know in advance • Other functions: • See K&R book or man pages for all the details rewind(fp); fseek(fp, offset, kind); ftell(fp);
S -117 S -118
Standard Libraries
• Any system call is not part of the C language definition • Such system calls are defined in libraries, identified with the suffix .a Library Functions • Libraries typically contain many .o object files • To create your own library archive file: ar crv mylib.a *.o • Disregard “ranlib” command (no longer needed) • Look in /usr/lib and /usr/local/lib for most system libraries • Can list all .o files in an archive use “ar t /usr/lib/libc.a” • More useful to see all the function names: /usr/ccs/bin/nm /usr/lib/libc.a | grep FUNC
S -119 S -120
20 Standard Libraries (cont) Standard Libraries: Example
• By default, gcc links /usr/lib/libc.a to all executables #include
S -121 S -122
Files and Directories Example: argc/argv
• Disk drives divided into partitions #include
S -123 S -124
Miscellaneous
• fopen/fread/fwrite/fclose, etc. are implemented in terms of low-level non-standard i/o functions open/read/write/close, etc. • There are 3 types of buffering: Advanced Library – fully buffered (or block buffered): Functions • actual physical i/o takes place only when buffer is filled – line buffered: • actual i/o takes place when a newline (\n) is encountered – unbuffered: • output as soon as possible • All files are normally block buffered, except stdout (line buffered only if it refers to a terminal), and stderr (always unbuffered) • Can use fflush() to force a buffer to be cleared
S -125 S -126
21 String/Character Handling Storage Allocation
• All “str” functions require input strings be terminated with a null byte • Dynamic memory allocation (very important for many C programs): • Some of the most common ones: malloc, calloc, free, realloc strlen, strcpy, strcmp, strcat • An (incomplete) example: • strtok used for extracting "tokens" from strings #include
S -127 S -128
Date and Time Functions Variable Arguments
• clock_t, clock(), time_t, time() • An under-used but very powerful feature • Most UNIX time functions have evolved from various sources, and are • printf() is an example where the number and types of arguments sometimes inconsistent, referring to time as one of: can differ from invocation to invocation – the number of seconds since Jan 1, 1970 (or Jan 1, 1900) • /usr/include/stdarg.h provides definitions of: – the number of clock ticks since Jan 1, 1970 (or Jan 1, 1900) – a special type named va_list – the broken down structure “struct tm” – three macros to implement variable arguments: (see /usr/include/time.h) • va_start – the broken down structure “struct timeval” • va_end (see /usr/include/sys/time.h) • va_arg • Some are intended for time/date, whereas others are intended for • Another useful function is “vfprintf”, as shown in the next slide measuring elapsed time
S -129 S -130
Variable Arguments Environment Interfacing
• A very useful example: • Reading environment variables: #include
S -131 S -132
22 wait and waitpid
• Recall from a previous slide: pid_t wait( int *status ) • wait() can: (a) block; (b) return with status; (c) return with error Processes • If there is more than one child, wait() returns on termination of any children • waitpid can be used to wait for a specific child pid • waitpid also has an option to block or not to block
pid_t waitpid( pid, &status, option ); pid == -1 waits for any child option == NOHANG non-blocking option == 0 blocking waitpid(-1, &status, 0) equivalent to wait(&status)
S -133 S -134
example: wait.c prExit.c
#include
S -135 S -136
exec Memory Layout of a C program high address stack command-line arguments • Six versions of exec: and environment variables
execl( char *pathname, char *arg0, ... , (char*) 0 ); grow & shrink •dynamically allocated memory execv( char *pathname, char *argv[] ); as needed appears in the heap •function invocations and local execle( char *pathname, char *arg0, ..., (char*) 0, variables appear in the stack char *envp[] ); heap execve( char *pathname, char *argv[], uninitialized data initialized to zero by exec char *envp[] ); initialized data execlp( char *filename, char *arg0, ..., (char*) 0 ); read from program file by exec execvp( char *filename, char *argv[] ); text low address
S -137 S -138
23 Miscellaneous: permissions Miscellaneous: buffering control
• Read permissions for a directory and execute permissions for it are not int setbuffer(FILE *fp, char *buf, int size) the same: – specifies that “buf” should be used instead of the default system- – Read: read directory, obtain a list of filenames allocated buffer, and sets the buffer size to “size” – Execute: lets users pass through the directory when it is a – if “buf” is NULL, i/o will be unbuffered component of a pathname being accessed – used after stream is opened, but before it is read or written • Cannot create a new file in a directory unless user has write int setlinebuf( FILE *fp ) permissions and execute permission in that directory – used to change stdout or stderr to line buffered – can be called anytime • To delete an existing file, the user needs write and execute permissions • A stream can be changed from unbuffered or line buffered to block in the directory containing the file, but does not need read or write buffered by using freopen(). A stream can be changed from block permission for file itself (!!!) buffered or line buffered to unbuffered by using freopen() followed by setbuf() with a buffer argument of NULL.
S -139 S -140
Motivation for Signals
• When a program forks into 2 or more processes, rarely do they execute independently of each other
Signals • The processes usually require some form of synchronization, and this is typically handled using signals
• Data usually needs to be passed between processes also, and this is typically handled using pipes and sockets, which we’ll discuss in detail in a week or two
• Signals are usually generated by – machine interrupts – the program itself, other programs, or the user (e.g. from the keyboard)
S -141 S -142
Introduction signal()
•
• When a C program receives a signal, control is immediately passed to • For nearly all signal types, the default action can be changed using the a function called a signal handler signal() function. The exceptions are SIGKILL and SIGSTOP
• The signal handler function can execute some C statements and exit in • Usage: signal(int sig, void (*disp)(int)) three different ways: • For each process, UNIX maintains a table of actions that should be – return control to the place in the program which was executing performed for each kind of signal. The signal() function changes when the signal occurred the table entry for the signal named as the first argument to the value – return control to some other point in the program provided as the second argument – terminate the program by calling the exit (or _exit) function • The second argument can be SIG_IGN (ignore the signal), SIG_DFL (perform default action), or a pointer to a signal handler function
S -143 S -144
24 signal() example Checking the return value #include
S -145 S -146
Signalling between processes Timer signals
• One process can send a signal to another process using the • Three interval timers are maintained for each process: misleadingly named function call – SIGALRM (real-time alarm, like a stopwatch) kill( int pid, int sig ) – SIGVTALRM (virtual-time alarm, measuring CPU time) • This call sends the signal “sig” to the process “pid” – SIGPROF (used for profilers, which we’ll cover later) • Useful functions to set and get timer info are: • Signalling between processes can be used for many purposes: – setitimer(), getitimer() – kill errant processes – alarm() (simpler version: only sets SIGALRM) – temporarily suspend execution of a process – pause() (suspend until next signal arrives) – make processes aware of the passage of time – sleep() (caused calling process to suspend) – synchronize the actions of processes – usleep() (like sleep(), but with finer granularity) Note: sleep() and usleep() are interruptible by other signals
S -147 S -148
Inter-Process Communication (IPC)
• Data exchange techniques between processes: – message passing: files, pipes, sockets – shared-memory model (not the default … but we’ll still cover in Pipes this, in a few weeks) • Limitations of files for inter-process data exchange: – slow! • Limitations of pipes: – two processes must be running on the same machine – two processes communicating must be “related” • Sockets overcome these limitations (we’ll cover sockets in the next lecture)
S -149 S -150
25 File Descriptors Revisited Pipes and File Descriptors
• Used by low-level I/O • A fork’d child inherits file descriptors from its parent – open(), close(), read(), write() • It’s possible to alter these using fclose() and fopen(): • declared as an integer fclose( stdin ); int fd ; FILE *fp = fopen( “/tmp/junk”, “r” ); • Not the same as a "file stream", FILE *fp • streams and file descriptors are related (see following slides) • One could exchange two entries in the fd table by closing and reopening both streams, but there’s a more efficient way, using dup() or dup2() (…see next slide)
S -151 S -152
dup() and dup2() pipe()
newFD = dup( oldFD ); • The pipe() system call creates an internal system buffer and two file if( newFD < 0 ) { perror(“dup”); exit(1); } descriptors: one for reading and one for writing
or, to force the newFD to have a specific number: • With a pipe, typically want the stdout of one process to be connected returnCode = dup2( oldFD, newFD ); to the stdin of another process … this is where dup2() becomes if(returnCode < 0) { perror(“dup2”); exit(1);} useful (see next slide and figure 12-2 for examples) • In both cases, and now refer to the same file oldFD newFD • Usage: • For , if is open, it is first automatically closed dup2() newFD int fd[2]; • Note that and refer to fd’s and not streams dup() dup2() pipe( fd ); /* fd[0] for reading; fd[1] for writing */ – A useful system call to convert a stream to a fd is int fileno( FILE *fp );
S -153 S -154
pipe()/dup2() example popen() and pclose()
/* equivalent to “sort < file1 | uniq” */ int fd[2]; • popen() simplifies the sequence of: FILE *fp = fopen( “file1”, “r” ); – generating a pipe dup2( fileno(fp), fileno(stdin) ); – forking a child process fclose( fp ); – duplicating file descriptors pipe( fd ); if( fork() == 0 ) { – passing command execution via an exec() dup2( fd[1], fileno(stdout) ); • Usage: close( fd[0] ); close( fd[1] ); execl( “/usr/bin/sort”, “sort”, (char *) 0 ); exit( 2 ); FILE *popen( const char *command, } else { const char *type ); dup2( fd[0], fileno(stdin) ); • Example: close( fd[0] ); close( fd[1] ); FILE *pipeFP; execl( “/usr/bin/uniq”, “uniq”, (char *) 0 ); exit( 3 ); } pipeFP = popen( “/usr/bin/ls *.c”, “r” );
S -155 S -156
26 What are sockets?
• Sockets are an extension of pipes, with the advantages that the processes don’t need to be related, or even on the same machine • A socket is like the end point of a pipe -- in fact, the UNIX kernel Sockets implements pipes as a pair of sockets • Two (or more) sockets must be connected before they can be used to transfer data • Two main categories of socket types … we’ll talk about both: – the UNIX domain: both processes on same machine – the INET domain: processes on different machines • Three main types of sockets: SOCK_STREAM, SOCK_DGRAM, and SOCK_RAW … we’ll only talk about SOCK_STREAM
S -157 S -158
Connection-Oriented Paradigm SERVER CLIENT Example: server.c Create a socket Create a socket socket() socket() • FILE “server.c” … highlights:
Assign a name to the socket socket( AF_UNIX, SOCK_STREAM, 0 ); bind() serv_adr.sun_family = AF_UNIX; Establish a queue for connections strcpy( serv_adr.sun_path, NAME ); listen() bind( orig_sock, &serv_adr, size ); listen( orig_sock, 1 ); Extract a connection from the queue Initiate a connection accept( orig_sock, &clnt_adr, &clnt_len ); accept() connect() established read( new_sock, buf, sizeof(buf) );
read() write() close( sd ); write() read() unlink( the_file );
S -159 S -160
Example: client.c The INET domain
• FILE “client.c” … highlights: • The main difference is the bind() command … in the UNIX domain, the socket name is a filename, but in the INET domain, the socket socket( AF_UNIX, SOCK_STREAM, 0 ); name is a machine name and port number: serv_adr.sun_family = AF_UNIX; strcpy( serv_adr.sun_path, NAME ); static struct sockaddr_in serv_adr; memset( &serv_adr, 0, sizeof(serv_adr) ); connect(orig_sock, &serv_adr, size ); serv_adr.sin_family = AF_INET; write( new_sock, buf, sizeof(buf) ); serv_adr.sin_addr.s_addr = htonl(INADDR_ANY); serv_adr.sin_port = htons( 6789 ); close( sd );
• Note: server.c and client.c need to be linked with the • Need to open socket with AF_INET instead of AF_UNIX libsocket.a library (ie: gcc -lsocket) • Also need to include
S -161 S -162
27 The INET domain (cont.)
• The client needs to know the machine name and port of the server struct hostent *host; host = gethostbyname( “eddie.cdf” ); Multiplexed I/O
• Note: need to link with libnsl.a to resolve gethostbyname()
• see Wang for: – server.c, client.c UNIX domain example – iserver.c, iclient.c, INET domain example
S -163 S -164
Motivation select()
• Consider a process that reads from multiple sources without knowing • Usage: in advance which source will provide some input first #include
S -165 S -166
Details “FD_” macros
• The first argument (nfds) represents the number of bits in the masks • Useful macros defined in
S -167 S -168
28 Example
#include
S -169 S -170
Motivation shmget()
• Shared memory allows two or more processes to share a given region • shmget() is used to obtain a shared memory identifier: of memory -- this is the fastest form of IPC because the data does not #include
S -171 S -172
shmat() shmctl()
• Once a shared memory segment has been created, a process attaches it to • shmctl() performs various shared memory operations: its address space by calling shmat(): int shmctl( int shmid, int cmd, void *shmat( int shmid, void *addr, int flag ); struct shmid_ds *buf ); • shmat() returns pointer to shared memory segment if OK, -1 on error • cmd can be one of IPC_STAT, IPC_SET, or IPC_RMID: • The recommended technique is to set addr and flag to zero, i.e.: – IPC_STAT fills the buf data structure (see
S -173 S -174
29 Shared Memory Example mmap() char *ShareMalloc( int size ) • An alternative to shared memory is memory mapped i/o, which maps a { file on disk into a buffer in memory, so that when bytes are fetched from int shmId; the buffer the corresponding bytes of the file are read char *returnPtr; • One advantage is that the contents of files are non-volatile
if( (shmId=shmget( IPC_PRIVATE, size, (SHM_R|SHM_W) )) < 0 ) • Usage: Abort( "Failure on shmget {size is %d}\n", size ); caddr_t mmap( caddr_t addr, size_t len, int prot, int flag, int filedes, off_t off ); if( (returnPtr=(char*) shmat( shmId, 0, 0 )) == (void*) -1 ) – addr and off should be set to zero, Abort( "Failure on Shared Mem (shmat)" ); – len is the number of bytes to allocate shmctl( shmId, IPC_RMID, (struct shmid_ds *) NULL ); – prot is the file protection, typically (PROT_READ|PROT_WRITE) return( returnPtr ); – flag should be set to MAP_SHARED to emulate shared memory } – filedes is a file descriptor that should be opened previously
S -175 S -176
Memory Mapped I/O Example char *ShareMalloc( int size ) { int fd; char *returnPtr; Semaphores if( (fd = open( "/tmp/mmap", O_CREAT | O_RDWR, 0666 )) < 0 ) Abort( "Failure on open" ); if( lseek( fd, size-1, SEEK_SET ) == -1 ) Abort( "Failure on lseek" ); if( write( fd, "", 1 ) != 1 ) Abort( "Failure on write" ); if( (returnPtr = (char *) mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 )) == (caddr_t) -1 ) Abort( "Failure on mmap" ); return( returnPtr ); }
S -177 S -178
Motivation The Critical Section Problem
• Programs that manage shared resources must execute portions of code • The critical section problem refers to the problem of executing critical called critical sections in a mutually exclusive manner. A common sections in a fair, symmetric manner. Solutions to the critical section method of protecting critical sections is to use semaphores problem must satisfy each of the following:
• Code that modifies shared data usually has the following parts: Mutual Exclusion: At most one process is in its critical section at any time. Entry Section: The code that requests permission to modify Progress: If no process is executing its critical section, a the shared data. process that wishes to enter can get in. Critical Section: The code that modifies the shared variable. Bounded Waiting: No process is postponed indefinitely. Exit Section: The code that releases access to the shared data. Remainder Section: The remaining code. • An atomic operation is an operation that, once started, completes in a logical indivisible way. Most solutions to the critical section problem rely on the existence of certain atomic operations
S -179 S -180
30 Semaphores Semaphores (cont.)
• A semaphore is an integer variable with two atomic operations: wait and • Three problems with the previous slide’s wait() and signal(): signal. Other names for wait are down, P, and lock. Other names for – busy waiting is inefficient signal are up, V, unlock, and post. – doesn’t guarantee bounded waiting • A process that executes a wait on a semaphore variable S cannot – “++” and “--” operations aren’t necessarily atomic! proceed until the value of S is positive. It then decrements the value of • Solution: use system calls semget() and semop() (… see next slide) S. The signal operation increments the value of the semaphore variable. • Some (flawed) pseudocode: • The following pseudocode protects a critical section: void wait( int *s ) void signal( int *s ) wait( &s ); { { /* critical section */ while( *s <= 0 ) ; (*s)++; signal( &s ); (*s)--; } /* remainder section */ } • What happens if S is initially 0? What happens if S is initially 8?
S -181 S -182
semget() semop()
• Usage: • Usage: int semop( int semid, struct sembuf *sops, #include
S -183 S -184
Example
struct sembuf semWait[1] = { 0, -1, 0 }, semSignal[1] = { 0, 1, 0 }; int semID; Posix Threads semop( semID, semSignal, 1 ); /* init to 1 */
while( (semop( semID, semWait, 1 ) == -1) && (errno == EINTR) ) ;
{ /* critical section */ }
while( (semop( semID, semSignal, 1 ) == -1) && (errno == EINTR) ) ;
S -185 S -186
31 Thread Concepts Creating a PThread
• Threads are "lightweight processes" #include
S -187 S -188
Creating a Pthread [cont'd] Thread Termination [cont'd]
• pthread_create() returns 0 if successful, a +ve error code if not • status, if not NULL, returns the void * returned by the thread when • does not set errno, but returns compatible codes it terminates • can use strerror() to print error messages • a thread can terminate by – returning from func() – the main() function exiting Thread Termination – pthread_exit()
#include
S -189 S -190
"Detaching" Threads Passing Arguments to Threads
#include
S -191 S -192
32 Thread-Safe Functions PThread Semaphores
• Not all functions can be called from threads (e.g. strtok()) #include
S -193 S -194
PThread Semaphores [cont'd] pthread_mutex_t myMutex ; int status ; status = pthread_mutex_init(&myMutex, NULL) ; Concurrency Concepts if (status != 0) printf("Error: %s\n", strerror(status)); pthread_mutex_lock(&myMutex); /* critical section here */ pthread_mutex_unlock(&myMutex); status = pthread_mutex_destroy(&myMutex); if (status != 0) printf("Error: %s\n", strerror(status));
S -195 S -196
Non-determinism Deadlocks
• A process is deterministic when it always produces the same result • A concurrent program is in deadlock if all processes are waiting for when presented with the same data; otherwise a process is called some event that will never occur non-deterministic • Typical deadlock pattern: print j Process 1 is holding resource X, waiting for Y Process 2 is holding resource Y, waiting for X j = 10 exit j = 100 Process 1 will not get Y until Process 2 releases it Process 2 will not release Y until it gets X, • Evaluation proceeds non-deterministically in one of two ways, which Process 1 is holding, waiting for … producing an output of 10 or 100 • Race conditions lead to non-determinism, and are generally undesirable
S -197 S -198
33 Dining Philosophers Philosopher Process
• N philosophers are seated loop in a circle, one chopstick
• Each philosopher needs two
• A typical philosopher
S -199 S -200
Deadlock Example Comments on Deadlock
• In practice, deadlocks can arise when waiting for some reusable • For N=2, call philosophers P1 and P2, and chopsticks C1 and C2 resources. For example, an operating system may be handling several • Deadlocking sequence: executing jobs, none of which has enough room to finish (and free up P1 requests; gets C1 memory for the others) P2 requests; gets C2 • Operating systems may detect/avoid deadlocks by: P1 requests; WAITS for C2 – checking continuously on requests for resources – refusing to allocate resources if allocation would lead to a deadlock P2 requests; WAITS for C1 – terminating a process that is responsible for deadlock ** DEADLOCK ** • One can have a process that sits and watches, and can break a deadlock if necessary. This process may be invoked: • Can avoid deadlock if the philosopher processes request both chopsticks – on a timed interrupt basis at once, and then they get both or wait until both are available – when a process wants to queue for a resource – when deadlock is suspected (i.e.: CPU utilization has dropped to 0)
S -201 S -202
Indefinite Postponement Dekker's Algorithm
• Indefinite postponement occurs when a process is blocked waiting for /* other, me are threadID's with values 0, 1 */ an even that can, but will not occur in some future execution sequence int turn ; int need[2] = { FALSE, FALSE }; • This may arise because other processes are “ganging up” on a process to “starve” it void wait() • During indefinite postponement, the overall system does not grind to a { halt, but treats some of its processes unfairly need(me) = TRUE ; turn = other ; while (need[other] && (turn != me)); • Indefinite postponement can be avoided by having priority queues } which serve concurrent processes on a first-come, first-served basis void signal() • UNIX semaphores do this, using a FIFO (first-in, first-out) queue for { all requests need(me) = FALSE ; }
S -203 S -204
34 Dependencies
iserver.c Project Management proto.h xserver.c include.h . globals.h
.
S -205 S -206
Makefile Makefile Macros
OBJS = iserver.o xserver.o CC = gcc
S -207 S -208
Suffix Rules Multiply-defined globals
iserver.c: • Unix has many "standard" suffixes (.c .f .o .s .a .so) #include "include.h" include.h: • can specify the same make rule for all files with a given suffix, void main( void ) #include
S -209 S -210
35 Two Solutions for initialized globals: for uninitialized globals: globals.h: globals.h: #ifdef _MAIN #ifdef _MAIN int X_ServerPid = 14; #define EXTERN Miscellanea #else #else extern X_ServerPid; #define EXTERN extern #endif #endif
iserver.c: EXTERN X_ServerPid; /* set in Init()*/ #define _MAIN #include "include.h"
S -211 S -212
gzip, compress tar
• Usage: gzip [filename]: compress specified filename • Traditionally, tar (short for Tape ARchive) was used for backups to gunzip [filename]: uncompress specified filename tape drives • It’s also useful to create archive files on disk. • Examples: gzip file1 creates file1.gz • Example: creating an archive of a directory structure: gunzip
S -213 S -214
nice, nohup Named pipes: mknod()
#include
S -215 S -216
36 vfork() system()
• The typical fork()/exec() sequence is inefficient because • It is sometimes convenient to execute a command string from within a fork() creates a copy of the data, heap, and stack area of the original program. process, which is then immediately discarded when exec() is called. • For example, to put a time and date stamp into a certain file, one could: • vfork()is intended to create a new process when the purpose of the new process is to exec() a new program. vfork() has the same – use time(), and ctime() to get and format the time, then open calling sequence and the same return values as fork(). a file for writing and write the resulting string. • vfork() creates the new process, just like fork(), without fully – use system( “date > file” ); (much simpler) copying the address space of the parent into the child, since the child is typically implemented by calling , , won’t reference that address space -- the child just calls exec() right • system() fork() exec() and after the vfork(). waitpid() • Another difference between vfork() and fork() is that vfork() guarantees that the child runs first, until the child calls exec() or exit().
S -217 S -218
lint
• lint is a useful utility that checks programs more thoroughly that gcc or other compilers • Usage: lint file1 [file2] ...
% cat main.c % lint main.c
#include
S -219
37