Download presentation
Presentation is loading. Please wait.
Published bySteven Norton Modified over 8 years ago
1
Chapter 13 Systems Programming Graham Glass and King Ables, UNIX for Programmers and Users, Third Edition, Pearson Prentice Hall, 2003.
2
Systems Programming UNIX System calls: C functions that provide access to the file system, processes, and error handling. System Calls grouped into 3 main categories: File Management (Fig. 13.1) Process Management (Fig. 13.2) Error Handling (Fig. 13.3)
3
Error Handling Most system calls are capable of failing in some way. Example: open a file may fail because file does not exist! System call returns a value of -1 when it fails. This value does not tell much about the cause of the failure.
4
errno Error Handling: errno errno Each process has a global variable errno that holds the numeric code of the last system-call error. (Initially, it 0). “/usr/include/sys/errno.h” #define EPERM 1 /*Operation not permitted*/ #define ENOENT 2 /*No such file or directory*/ #define EIO 5 /* I/O error */ #define EMFILE 24 /* Too many open files */ #include #include
5
Error Handling function perror() describes the system-call error void perror(char* str) /* standard C function in stdio.h */ Displays str followed by a description of the last system call error. Error 0 is displayed if no error errno errno should be manually reset to 0 after system call failure!
6
perror Error Handling: perror() errno = 2 Main: No such file or directory errno = 21 main: Is a directory errno = 29 main: Illegal seek main: Success #include void main() { int fd; fd = open ("nonexist.txt", O_RDONLY); if(fd == -1) { printf ("errno = %d\n", errno); perror("main"); } fd = open ("/", O_WRONLY); if(fd == -1) { printf ("errno = %d\n", errno); perror("main"); } fd = open ("nonexist.txt", O_RDONLY | O_CREAT, 0644); printf ("errno = %d\n", errno); perror("main"); errno = 0; perror("main"); }
7
Unix File System directory structure Unix files are organized by hierarchy of labels commonly known as directory structure. Regular files Regular files: sequence of bytes that generally corresponds to code or data. Directory files Directory files: stored in a special format and form the backbone of the file system (directory-specific system calls). Special files Special files correspond to peripherals, such as printers, disks, pipes and sockets.
8
File Management System Calls: open, fcntl, read, write, lseek, unlink, close Typical sequence: open read/write close
9
Typical File I/O Sequence int fd; /* file descriptor 0: std. in, 1: std. out, 2: std error*/ fd = open(fileName,...); if (fd == -1) /* deal with error */ fcntl(fd,...) /* set IO flags if necessary */ read(fd,...) /* read from file */ write(fd,...) /* write to file */ lseek(fd,...) /* seek within file */ close(fd); /* close file, freeing file descriptor */
10
File Descriptors Each descriptor has its own private set of properties file pointer (stores offset within file; changes on read/write/lseek) flag indicating if the file descriptor should be closed or not when process execs flag indicating if output to file should be appended to end of file or not A pipe or a socket have additional properties
11
File Descriptors Can open file several times (with different descriptors) System calls open() and fcntl() both allow you to manipulate these flags. fd1 fd2 fd3 File
12
Opening a File: open() int open(char* fileName, int mode[, int perm]) int open(char* fileName, int mode[, int perm]) allows you to open an existing file or create a new file for r/w fileName: absolute or relative path name mode: bitwise or-ing of a r/w flag together with zero or more miscellaneous flags (next slide) permissions: supplied only when file is created (ex. 0600 octal)
13
Mode Flags r/w flags: O_RDONLY, O_WRONLY, O_RDWR misc. flags: O_APPEND : position file pointer at the end of file before each write O_CREAT : if the file does not exist, create it and set the owner ID = process' effective UID (uses umask value to set permissions) O_EXCL : if O_CREAT is set and file exists then open() fails O_NONBLOCK: for named pipes O_TRUNC: if file exists it is truncated to length 0
14
Create a File #include void main() { int tmpfd; char tmpName[32]; sprintf(tmpName, ".rev.%d", getpid()); tmpfd = open (tmpName, O_CREAT | O_RDWR, 0600); if(tmpfd == -1) { printf ("errno = %d\n", errno); perror("main"); } printf("create a file %s\n", tmpName); } create a file.rev.4024
15
Opening an Existing File #include void main(int argc,char *argv[]) { if (argc>1) { int fd = open (argv[1], O_RDONLY); if (fd == -1) { perror ("reverse: "); exit (1); } else printf("File %s opened \n", argv[1]); } [c33225@snowball ~]$./fopen nonexist reverse: : No such file or directory [c33225@snowball ~]$./fopen power.h File power.h opened
16
: CREAT() CREATING A FILE: CREAT() int creat(char* fileName, mode_t perm) int creat(char* fileName, mode_t perm) S_IRUSR: owner read permit S_IWUSR: owner write permit S_IXUSR: owner execute permit S_IRGRP: group read permit S_IWGRP: group write permit S_IROTH: others read permit S_IWOTH: owners write permit S_IXOTH: others execute permit open(“myfile”, O_CREAT, S_IRUSR | S_IXOTH)
17
Read from a regular file: read() size_t read(int fd, void* buf, size_t count) size_t read(int fd, void* buf, size_t count) copies upto count bytes from the file referenced by fd into buffer buf the bytes are read from current position (file pointer) which is then updated accordingly
18
Read from a regular file: read() it returns number of bytes copied returns 0 if it attempts to copy after end of file returns -1 if unsuccessful Example: charsRead = read(fd, buffer, BUFFER_SIZE); if (charsRead == 0) break; if (charsRead == -1) fatalError();
19
int charsRead; char buffer [4096]; while (1) { charsRead = read (fd, buffer, 4096); if (charsRead == 0) { printf("reach the end of the file.\n"); break; /* EOF */ } if (charsRead == -1) { perror ("reverse: "); exit (1); } [c33225@snowball ~]$./fread power.h File power.h opened reach the end of the file. [c33225@snowball ~]$./fread nonexist reverse: : No such file or directory Read Example
20
Write to a regular file: write() ssize_t write(int fd, void *buf, size_t count) Copies upto count bytes from a buffer buf into the file referenced by fd The bytes are written into current position (file pointer) which is then updated accordingly If O_APPEND was set, file pointer is set to end of file before each write
21
Write to a regular file:write() It returns number of bytes copied You should check this return value returns -1 if unsuccessful
22
int charsRead, charsWritten; char buffer [4096]; while (1) { charsRead = read (fd, buffer, 4096); if (charsRead == 0) break; /* EOF */ if (charsRead == -1) { perror ("reverse: "); exit (1);} charsWritten=write(out,buffer,charsRead); if (charsWritten!=charsRead){ perror ("reverse: "); exit (1);} } Write Example
23
Moving the file pointer: lseek() off_t lseek(int fd, off_t offset, int mode) off_t lseek(int fd, off_t offset, int mode) fd. Changes current file position in the file referenced by fd. modeoffset mode describes how to interpret the offset.
24
Moving the file pointer: lseek() modes mode = SEEK_SET offset relative to start of file mode = SEEK_CUR offset relative to current position of file mode = SEEK_END offset relative to end of file
25
Moving the file pointer: lseek() lseek fails if moved before start of file returns new file position if successful returns -1 if unsuccessful
26
Assume, fd is a file descriptor, lines[] is an array that holds starting positions of each line in the file. for (i = 0; i <10; i++) { int charsRead; char buffer [4096]; lseek (fd, lines[i], SEEK_SET); charsRead = read (fd, buffer, lines[i+1] - lines[i]); write (1, buffer, charsRead); }
27
Current Offset of lseek To find out current position use: currentOffset = lseek(fd, 0, SEEK_CUR); If you move past the end of file and write there, Unix automatically extends the size of the file and treats intermediate area as NULLS (0) Unix does not allocate disk area for intermediate space!! (see next example)
28
[c33235@snowball ~]$ cat sparse.txt Sparsefile [c33235@snowball ~]$ cat normal.txt normalfile
29
Closing a file: close() int close(int fd) int close(int fd) Frees fd; releases resources When a process terminates, all fds are automatically closed Still it is a good idea to close yourself Returns 0 if success -1 if failure
30
Deleting a file: unlink() int unlink(const char* fileName) int unlink(const char* fileName) Removes the hard link from the fileName to its file If fileName is the last hard link, file resources are deallocated. Example: unlink(tmpName);
31
Reverse Example (reverse.c) Starting page 440 % reverse -c fileName Reverses all lines in fileName The -c option reverses each line; If fileName is missing, standard input is used
32
Reverse Example Algorithm Step 1: Parse Command Line (parseCommandLine, processOptions) System Calls used: none Step 2: If reading from standard input, create temp. file to store input; otherwise open file for input (pass1) System Calls used: open()
33
Reverse Example Algorithm Step 3: Read from file in chunks storing starting offsets of each line in an array. If reading from std. input, write each chunk into temp. file. (pass1, trackLines) System Calls used: read(), write() Step 4: Read input file again, but backward, copying each line to std. output; reverse the line if -c option (pass2, processLine, reverseLine) System Calls used: lseek()
34
Reverse Example Algorithm Step 5: Close file; remove it if temp. file; (pass2) System Calls used: close(), unlink()
35
Listing of reverse.c #include /* For file mode definitions */ #include /* Enumerator */ enum { FALSE, TRUE }; /* Standard false and true values */ enum { STDIN, STDOUT, STDERR }; /* Standard I/O channel indices */ /* #define Statements */ #define BUFFER_SIZE 4096 /* Copy buffer size */ #define NAME_SIZE 12 #define MAX_LINES 100000 /* Max lines in file */
36
Listing of reverse.c /* Function Prototypes */ void parseCommandLine (int argc, char* argv[]); void processOptions (char* str); void usageError (); void pass1 (); void trackLines (char* buffer, int charsRead); void pass2 (); void processLine (int i); void reverseLine (char* buffer, int size); void fatalError ();
37
Listing of reverse.c /* Globals */ char *fileName = NULL; /* Points to file name */ char tmpName [NAME_SIZE]; int charOption = FALSE; /* Set to true if -c option is used */ int standardInput = FALSE; /* Set to true if reading stdin */ int lineCount = 0; /* Total number of lines in input */ int lineStart [MAX_LINES]; /* Store offsets of each line */ int fileOffset = 0; /* Current position in input */ int fd; /* File descriptor of input */ /*****************************************************/
38
Listing of reverse.c int main (int argc, char* argv[]) { parseCommandLine (argc,argv); /* Parse cmd line */ pass1 (); /* Perform first pass through input */ pass2 (); /* Perform second pass through input */ return (/* EXITSUCCESS */ 0); /* Done */ } /*****************************************************/
39
Function parseCommandLine void parseCommandLine (int argc, char* argv[]) { /* Parse command line arguments */ int i; for (i= 1; i < argc; i++) { if(argv[i][0] == '-') processOptions (argv[i]); else if (fileName == NULL) fileName= argv[i]; else usageError (); /* An error occurred */ } standardInput = (fileName == NULL); }
40
Function processOptions void processOptions (char* str) { /* Parse options */ int j; for (j= 1; str[j] != NULL; j++) { switch(str[j]) /* Switch on command line flag */ { case 'c': charOption = TRUE; break; default: usageError (); break; }
41
Function usageError void usageError () { fprintf (stderr, "Usage: reverse -c [filename]\n"); exit (/* EXITFAILURE */ 1); }
42
Function pass1 void pass1 () { /* Perform first scan through file */ int tmpfd, charsRead, charsWritten; char buffer [BUFFER_SIZE]; if (standardInput) /* Read from standard input */ { fd = STDIN; sprintf (tmpName, ".rev.%d",getpid ()); /* Random name */ /* Create temporary file to store copy of input */ tmpfd = open (tmpName, O_CREAT | O_RDWR, 0600); if (tmpfd == -1) fatalError (); } else /* Open named file for reading */ { fd = open (fileName, O_RDONLY); if (fd == -1) fatalError (); } lineStart[0] = 0; /* Offset of first line */ }
43
Function pass1 Continued while (TRUE) /* Read all input */ { /* Fill buffer */ charsRead = read (fd, buffer, BUFFER_SIZE); if (charsRead == 0) break; /* EOF */ if (charsRead == -1) fatalError (); /* Error */ trackLines (buffer, charsRead); /* Process line */ /* Copy line to temporary file if reading stdin */ if (standardInput) { charsWritten = write (tmpfd, buffer, charsRead); if(charsWritten != charsRead) fatalError (); } /* Store offset of trailing line, if present */ lineStart[lineCount + 1] = fileOffset; /* If reading standard input, prepare fd for pass2 */ if (standardInput) fd = tmpfd; }
44
Function trackLines void trackLines (char* buffer, int charsRead) { /* Store offsets of each line start in buffer */ int i; for (i = 0; i < charsRead; i++) { ++fileOffset; /* Update current file position */ if (buffer[i] == '\n') lineStart[++lineCount] = fileOffset; }
45
Function pass2 void pass2 () { /* Scan input file again, displaying lines in reverse order */ int i; for (i = lineCount - 1; i >= 0; i--) processLine (i); close (fd); /* Close input file */ if (standardInput) unlink (tmpName); /* Remove temp file that we made*/ }
46
Function processLine void processLine (int i) { /* Read a line and display it */ int charsRead; char buffer [BUFFER_SIZE]; /* Find the line and read it */ lseek (fd, lineStart[i], SEEK_SET); charsRead = read (fd, buffer, lineStart[i+1] - lineStart[i]); /* Reverse line if -c option was selected */ if (charOption) reverseLine (buffer, charsRead); /* Write it to standard output */ write (1, buffer, charsRead); }
47
Function reverseLine void reverseLine (char* buffer, int size) { /* Reverse all the characters in the buffer */ int start = 0, end = size - 1; char tmp; /* Leave trailing newline */ if (buffer[end] == '\n') --end; /* Swap characters in a pairwise fashion */ while (start < end) { tmp = buffer[start]; buffer[start] = buffer[end]; buffer[end] = tmp; ++start; /* Increment start index */ --end; /* Decrement end index */ }
48
Function fatalError void fatalError () { perror ("reverse: "); /* Describe error */ exit (1); }
49
[c33225@snowball reverse]$ cat > test Christmas is coming, The days that grow shorter, Remind me of seasons I knew in the past. [c33225@snowball reverse]$./reverse test Remind me of seasons I knew in the past. The days that grow shorter, Christmas is coming, [c33225@snowball reverse]$./reverse -c test.tsap eht ni wenk I snosaes fo em dnimeR,retrohs worg taht syad ehT,gnimoc si samtsirhC [c33225@snowball reverse]$ cat test |./reverse Remind me of seasons I knew in the past. The days that grow shorter, Christmas is coming,
50
[c33225@snowball reverse]$./reverse hello world hi there hello world [c33225@snowball reverse]$./reverse -c hi there hello world dlrow olleh ereht ih
51
Second Example: monitor.c Uses 3 new advanced system calls: stat(): obtains status information about a file fstat(): similar to stat getdents(): obtains directory entries Program monitor.c allows the user to monitor a collection of files obtain information whenever any of them are modified
52
Using monitor.c % monitor [-t delay] [-l count] {fileName}+ Every delay seconds Scans all specified files Displays information about any that were modified since the last scan If fileName is a directory, all of the files inside the directory are scanned.
53
Using monitor.c File modification is indicated as follows: ADDED : indicates that the file was created since the last scan every file is given this label in the first scan CHANGED : indicates that the file was modified since the last scan DELETED : indicates that the file was deleted since the last scan
54
Using monitor.c By default monitor will scan forever unless overridden by [-l count] option (in which case it scans only count times) The default delay between scans is 10 seconds which can be overridden by the [-t delay] option.
55
Algorithm Monitor program continually scans the specified files/directory It uses stat() to get information (type and last modification time) It calls getdents() to scan directories
56
Algorithm If the file is not in the scan table, it is ADDED If the file is already in scan table and has been modified, then MODIFIED message At the end of a scan, if a file is not present in current scan but was present in previous scan, it is marked DELETED
57
System Call stat() int stat(const char* name, struct stat* buf) stat() fills the buffer buf with information about file name The stat structure is defined in /usr/include/sys/stat.h and includes the following fields: st_dev device number st_ino the inode number st_mode the permission flags
58
System Call stat() (stat fields continued) st_nlink the hard-link count st_uid the user ID st_gid the group ID st_size the file size st_atime the last access time st_mtime the last modification time st_ctime the last status-change time
59
Macros in /usr/include/sys/stat.h S_ISDIR(st_mode) true if directory S_ISCHR(st_mode) true if file is a character special device S_ISBLK(st_mode) true if file is a block special device S_ISREG(st_mode) true if a regular file S_ISFIFO(st_mode) true if a pipe
60
Variations of stat() lstat() : same as stat() except it returns information about the symbolic link itself rather than the file it refers to fstat() : same as stat() except it takes file descriptor as first parameter All return 0 if successful and -1 otherwise
62
Example Using stat() Call updateStat() if the file is a regular file character special file, or block special file. Either adds or updates the file's status entry If status has changes, updateEntry() is called to display file's new status The decoding of time is done using localtime() and asctime()
63
Reading Directory Information: getdents() int getdents(int fd, struct dirent* buf, int structSize) Reads the directory file with descriptor fd from its current position and fills structure pointed to by buf with the next entry.
64
Reading Directory Information: getdents() The dirent struct is defined in /usr/include/sys/dirent.h and contains the following fields: d_ino : the inode number d_off : the offset of the next directory entry d_reclen : length of the dirent struct d_name : the fileName
65
Reading Directory Information: getdents() Returns length of the directory entry if successful 0 if last directory entry has already been read -1 if error processDirectory function skips. and.. and uses lseek to advance to the next directory entry
67
opendir() Directory Manipulation: opendir() DIR * opendir (const char *dirname) DIR * opendir (const char *dirname) dirname Opens and returns a directory stream of directory dirname, or NULL, if fails.
68
readdir() closedir() Directory Manipulation: readdir() and closedir() struct dirent * readdir (DIR *dirstream) struct dirent * readdir (DIR *dirstream) Reads the next entry from the directory. Returns a pointer to a structure containing information about the file. This structure is statically allocated and can be rewritten by a subsequent call. If there are no more entries or an error is detected, returns a null pointer. int closedir (DIR *dirstream) int closedir (DIR *dirstream) dirstream Closes the directory stream dirstream. Returns 0 or -1 if fails.
69
#include int main (void) { DIR *dp= opendir ("temp"); struct dirent *ep; if (dp != NULL) { while (ep = readdir (dp)) printf (ep->d_name); closedir (dp); } else perror ("Couldn't open"); return 0; }
70
Listing for monitor.c #include /* For printf, fprintf */ #include /* For strcmp */ #include /* For isdigit */ #include /* For O_RDONLY */ #include /* For getdents */ #include /* For IS macros */ #include /* For modet */ #include /* For localtime, asctime */
71
Listing for monitor.c void parseCommandLine (int argc, char* argv[]); int findEntry (char* fileName); void fatalError (); void usageError (); void processOptions (char* str); int getNumber (char* str, int* i); void monitorLoop (); void monitorFiles (); void monitorFile (char* fileName); void processDirectory (char* dirName); void updateStat (char* fileName, struct stat* statBuf); int findEntry (char* fileName); int addEntry (char* fileName, struct stat* statBuf); int nextFree (); void updateEntry (int index, struct stat* statBuf); void printEntry (int index); void printStat (struct stat* statBuf); void fatalError ();
72
Listing for monitor.c /* #define Statements */ #define MAX_FILES 100 #define MAX_FILENAME 50 #define NOT_FOUND -1 #define FOREVER -1 #define DEFAULT_DELAY_TIME 10 #define DEFAULT_LOOP_COUNT FOREVER /* Booleans */ enum { FALSE, TRUE }; /* Status structure, one per file. */ struct statStruct { char fileName [MAX_FILENAME]; /* File name */ int lastCycle, thisCycle; /* To detect changes */ struct stat status; /* Information from stat () */ };
73
Listing for monitor.c /* Globals */ /* One per file on command line */ char* fileNames [MAX_FILES]; /* Count of files on command line */ int fileCount; /* One per matching file */ struct statStruct stats [MAX_FILES]; /* Number of times to loop */ int loopCount = DEFAULT_LOOP_COUNT; /* Seconds between loops */ int delayTime = DEFAULT_DELAY_TIME;
74
Listing for monitor.c int main (int argc, char* argv[]) { parseCommandLine (argc, argv); /* Parse command line */ monitorLoop (); /* Execute main monitor loop */ return (/* EXIT_SUCCESS */ 0); } void parseCommandLine (int argc, char* argv[]) { /* Parse command line arguments */ int i; for (i = 1; ( (i < argc) && (i < MAX_FILES) ); i++) { if (argv[i][0] == '-') processOptions (argv[i]); else fileNames[fileCount++] = argv[i]; } if (fileCount == 0) usageError (); }
75
Listing for monitor.c void processOptions (char* str) { /* Parse options */ int j; for (j = 1; str[j] != '\0'; j++) { switch(str[j]) /* Switch on option letter */ { case 't': delayTime = getNumber (str, &j); break; case 'l': loopCount = getNumber (str, &j); break; }
76
Listing for monitor.c int getNumber (char* str, int* i) { /* Convert a numeric ASCII option to a number */ int number = 0; int digits = 0; /* Count the digits in the number */ while (isdigit (str[(*i) + 1])) { /* Convert chars to ints */ number = number * 10 + str[++(*i)] - '0'; ++digits; } if (digits == 0) usageError (); /* There must be a number */ return (number); }
77
Listing for monitor.c void usageError () { fprintf (stderr, "Usage: monitor -t -l {filename}+\n"); exit (/* EXIT_FAILURE */ 1); } void monitorLoop () { /* The main monitor loop */ do { monitorFiles (); /* Scan all files */ fflush (stdout); /* Flush standard output */ fflush (stderr); /* Flush standard error */ sleep (delayTime); /* Wait until next loop */ } while (loopCount == FOREVER || --loopCount > 0); }
78
Listing for monitor.c void monitorFiles () { /* Process all files */ int i; for (i = 0; i < fileCount; i++) monitorFile (fileNames[i]); for (i = 0; i< MAX_FILES; i++) { /* Update stat array */ if (stats[i].lastCycle && !stats[i].thisCycle) printf ("DELETED %s\n", stats[i].fileName); stats[i].lastCycle = stats[i].thisCycle; stats[i].thisCycle = FALSE; }
79
Listing for monitor.c void monitorFile (char* fileName) { /* Process a single file/directory*/ struct stat statBuf; mode_t mode; int result; result = stat(fileName, &statBuf); /* get file status */ if (result == -1) /* Status was not available */ { fprintf (stderr, "Cannot stat %s\n", fileName); return; } mode = statBuf.st_mode; /* Mode of file */ if(S_ISDIR (mode)) /* Directory */ processDirectory (fileName); else if (S_ISREG (mode) || S_ISCHR (mode) || S_ISBLK (mode)) updateStat (fileName, &statBuf); /* Regular file */ }
80
Listing for monitor.c void processDirectory (char* dirName) { /* Process all files in the named directory */ DIR *dp; struct dirent *dep; char fileName [MAX_FILENAME]; dp = opendir (dirName); /* Open for reading */ if (dp == NULL) fatalError (); while (dep = readdir(dp)) /* Read all dir entries */ { if (strcmp (dep->d_name, ".") != 0&& strcmp (dep->d_name, "..") != 0) /* Skip... */ { sprintf (fileName, "%s/%s", dirName, dep->d_name); monitorFile (fileName); /* Call recursively */ } closedir (dp); /* Close directory */ }
81
Listing for monitor.c void updateStat (char* fileName, struct stat* statBuf) { /* Add a status entry if necessary */ int entryIndex; /* Find existing entry */ entryIndex = findEntry (fileName); if (entryIndex == NOT_FOUND) /* Add new entry */ entryIndex = addEntry (fileName, statBuf); else /* Update existing entry */ updateEntry (entryIndex, statBuf); if (entryIndex != NOT_FOUND) /* Update status array */ stats[entryIndex].thisCycle = TRUE; }
82
Listing for monitor.c int findEntry (char* fileName) { /* Locate the index of a named filein the status array */ int i; for (i = 0; i < MAX_FILES; i++) if (stats[i].lastCycle && strcmp (stats[i].fileName, fileName) == 0) return (i); return (NOT_FOUND); }
83
Listing for monitor.c int addEntry (char* fileName, struct stat* statBuf) { /* Add a new entry into the status array */ int index; index = nextFree (); /* Find the next free entry */ if (index == NOT_FOUND) return (NOT_FOUND); /* None left */ /* Add filename */ strcpy (stats[index].fileName, fileName); stats[index].status = *statBuf; /* Add status info */ printf ("ADDED "); /* Notify standard output */ printEntry (index); /* Display status information */ return (index); }
84
Listing for monitor.c int nextFree () { /* Return the nextfree index in the status array */ int i; for (i = 0; i < MAX_FILES; i++) if (!stats[i].lastCycle && !stats[i].thisCycle) return (i); return (NOT_FOUND); }
85
Listing for monitor.c void updateEntry (int index, struct stat* statBuf) { /*Display information if the file has been modified */ if (stats[index].status.st_mtime != statBuf->st_mtime) { stats[index].status = *statBuf; /* Store stat info */ printf ("CHANGED "); /* Notify standard output */ printEntry (index); } void printEntry (int index) { /* Display an entry of the status array */ printf ("%s ", stats[index].fileName); printStat (&stats[index].status); }
86
Listing for monitor.c void printStat (struct stat* statBuf) { /* Display a status buffer */ printf ("size %lu bytes, mod. time = %s", statBuf->st_size, asctime (localtime (&statBuf->st_mtime)));// convert system time to local time } // then convert it to human-readable version void fatalError () { perror ("monitor: "); exit (/* EXIT_FAILURE */ 1); } /*** End of monitor.c listing ***/
87
[c33225@snowball monitor]$ ls file monitor monitor.c [c33225@snowball monitor]$./monitor tmp myFile.txt >& monitor.out & [1] 8782 [c33225@snowball monitor]$ cat > tmp hi there [c33225@snowball monitor]$ cat > myFile.txt Hi there [c33225@snowball monitor]$ cat > myFile.txt hi again [c33225@snowball monitor]$ rm tmp [c33225@snowball monitor]$ jobs [1]+ Running./monitor tmp myFile.txt >&monitor.out & [c33225@snowball monitor]$ kill %1 [c33225@snowball monitor]$ jobs [c33225@snowball monitor]$ cat monitor.out Cannot stat tmp Cannot stat myFile.txt Cannot stat tmp Cannot stat myFile.txt ADDED tmp size 12 bytes, mod. time = Tue Jul 20 19:52:25 2010 Cannot stat myFile.txt ADDED myFile.txt size 9 bytes, mod. time = Tue Jul 20 19:52:42 2010 CHANGED myFile.txt size 0 bytes, mod. time = Tue Jul 20 19:52:53 2010 CHANGED myFile.txt size 9 bytes, mod. time = Tue Jul 20 19:52:57 2010 Cannot stat tmp DELETED tmp
88
[c33225@snowball monitor]$./monitor file >& monitor.out & [1] 8869 [c33225@snowball monitor]$ cd file [c33225@snowball file]$ ls mychown mychown.c [c33225@snowball file]$ cat > myFile.txt hello world [c33225@snowball file]$ cat > tmp hi there [c33225@snowball file]$ rm tmp [c33225@snowball file]$ jobs [1]+ Running./monitor file >&monitor.out & (wd: ~/monitor) [c33225@snowball file]$ kill %1 [c33225@snowball file]$ cd.. [1]+ Terminated./monitor file >&monitor.out [c33225@snowball monitor]$ cat monitor.out ADDED file/mychown size 5086 bytes, mod. time = Thu Jul 15 20:25:10 2010 ADDED file/mychown.c size 107 bytes, mod. time = Thu Jul 15 20:24:45 2010 ADDED file/myFile.txt size 12 bytes, mod. time = Tue Jul 20 20:07:15 2010 ADDED file/tmp size 11 bytes, mod. time = Tue Jul 20 20:07:26 2010 DELETED file/tmp
89
[c33225@snowball monitor]$./monitor -t15 -l3 myFile.txt >& monitor.out & [1] 8923 [c33225@snowball monitor]$ cat > myFile.txt hello world [c33225@snowball monitor]$ cat > myFile.txt hi there [c33225@snowball monitor]$ rm myFile.txt [c33225@snowball monitor]$ jobs [1]+ Done./monitor -t15 -l3 myFile.txt >&monitor.out [c33225@snowball monitor]$ cat monitor.out ADDED myFile.txt size 9 bytes, mod. time = Tue Jul 20 20:17:49 2010 CHANGED myFile.txt size 12 bytes, mod. time = Tue Jul 20 20:18:19 2010 DELETED myFile.txt
90
Miscellaneous File Management System Calls int chown (const char* fileName, uid_t ownerId, gid_t groupId) int fchown (int fd, uid_t ownerId, gid_t groupId) Set owner and group IDs of fileName to ownerId and groupId respectively Value of -1 indicates that the ID should not change See lchown() for changing the ownership of a symbolic link itself, rather than the file
91
Miscellaneous File Management System Calls $ cat mychown.c int main() { int flag; flag = chown("test.txt", -1, 62); if (flag == -1) perror("error changing group ID for test.txt"); } $ ls –lg test.txt -rw-r--r--1glassmusic3May 25 11:42 test.txt $ mychown $ ls –lg test.txt -rw-r--r--1glasscs3May 25 11:42 test.txt
92
System call chmod() int chmod (const char* fileName, int mode) int fchmod (int fd, int mode) These change the mode of fileName to mode (specified as octal; ex. 0600)
93
Miscellaneous File Management System Calls $ cat mychmod.c int main() { int flag; flag = chmod("test.txt",0600); if (flag == -1) perror("problem setting mode"); } $ ls –l test.txt -rw-r--r--1glass3May 25 11:42 test.txt $ mychmod $ ls –l test.txt -rw-------1glass3May 25 11:42 test.txt
94
Duplicating a file descriptor: dup() and dup2() Int dup (int oldFd) Int dup2 (int oldFd, int newFd) dup finds the smallest free file descriptor entry and point it to the same file as oldFd Dup2 closes newFd and points it to the same file as oldFd In both cases, the original and copied file descriptors share the same file pointer and access mode. Both return the index of the new file descriptor if successful; value of -1 otherwise
95
Example Program mydup.c #include int main() { int fd1, fd2, fd3; fd1 = open("test.txt", O_RDWR | O_CREAT); printf("fd1 = %d\n", fd1); write(fd1,"what's",6); fd2 = dup(fd1); printf("fd2 = %d\n", fd2); write(fd2," up",3); close(0); /* Close standard input */ fd3 = dup(fd1); printf("fd3 = %d\n", fd3); write(fd3," doc",4); dup2(3,2); write(2,"?\n",2); } $ mydup fd1 = 3 fd2 = 4 fd3 = 0 $ cat test.txt What’s up doc?
96
File Descriptor Operations int fcntl (int fd, int cmd, int arg) Performs the operation encoded in cmd on the file associated with descriptor fd arg is an optional argument for cmd cmd = F_SETFL sets the current file-status flags to arg cmd = F_GETFL returns a number corresponding to the current file-status flags and mode
97
Example Program myfcntl.c #include main() { int fd; fd = open("test.txt", O_WRONLY); write(fd,“hi there\n", 9); lseek(fd, 0, SEEK_SET); fcntl(fd, F_SETFL, O_WRONLY | O_APPEND); write(fd,“ guys\n",6); close(fd); } $ cat test.txt Here are the content of The original file. $myfcntl $cat test.txt Hi there The content of The original file. guys
98
System call link() int link (const char* oldPath, const char* newPath) Create a hard link to an existing file Returns -1 if unsuccessful and 0 otherwise
99
Link() example $ cat mylink.c main() { link (“original.txt”, “another.txt”); } $ cat original.txt this is a file. $ ls –l original.txt another.txt another.txt not found -rw-r--r--1 glass16 May 25 12:18 original.txt $ mylink $ ls –l orignial.txt another.txt -rw-r--r--2 glass16 May 25 12:18 another.txt -rw-r--r--2 glass16 May 25 12:18 original.txt $cat >> another.txt Hi ^D $ ls –l original.txt another.txt -rw-r--r--2 glass20 May 25 12:19 another.txt -rw-r--r--2 glass20 May 25 12:19 original.txt $ rm original.txt $ ls –l original.txt another.txt Original.txt not found -rw-r--r--1 glass20 May 25 12:18 another.txt $ cat another.txt this is a file. hi $
100
System call truncate() int truncate (const char* fileName, off_t lenght) int ftruncate (int fd, off_t length) Set the length of the file fileName to length bytes. If the file is longer than length, it is truncated. If it is shorter than legnth, it is padded with nulls. Return -1 if unsuccessful and 0 otherwise
101
Truncate example $ cat truncate.c main() { truncate (“file1.txt”, 10); truncate (“file2.txt”, 10); } $ cat file1.txt short $ cat file2.txt long file with lots of letters $ ls –l file*.txt -rw-r—r--1glass6May 25 12:16 file1.txt -rw-r—r--1glass32May 25 12:17 file2.txt $ truncate $ ls –l file*.txt -rw-r—r--1glass10May 25 12:16 file1.txt -rw-r—r--1glass10May 25 12:17 file2.txt $ cat file1.txt short #cat file2.txt long file
102
Process Management A UNIX process is a unique instance of a running or runable program. Every process in UNIX has some code some data a stack a unique process ID (PID)
103
Init Process When UNIX starts (boots), there is only one process, called init, with process ID = 1. The only way to create a new process is to duplicate an existing process So init is the ancestor of all subsequent processes. Initially, init duplicates (forks) several times and each child process replaces its code (execs) with the code of the executable getty which is responsible for user logins.
104
The initial process hierarchy Parent Init (PID 1) Child getty (PID 4) Handle a login Child getty (PID 6) Handle a login Child getty (PID 5) Handle a login Duplicate: fork(), then differentiate: exec()
105
Parent and Child Processes It is very common for a parent process to suspend itself until one of its child processes terminates. For example: Consider the way a shell process executes a utility in the foreground: The shell first duplicates itself using fork() The child shell process replaces its code with that of the utility using exec(). (Differentiates)
106
Parent and Child Processes The parent process waits for the child process to terminate using wait() When the child process terminates using exit(), the parent process is informed (using a signal) the parent process presents the user with the shell prompt to accept the next command
107
How a shell runs a utility Parent process PID 34 Running shell Parent process PID 34 running shell, Waiting for child Child process PID 35 running shell Parent process PID 34 running shell, awakens Duplicate: fork() Differentiate: exec() Child process PID 35 running utility Terminate: exit() Child process PID 35 terminates Signal Wait for child: wait()
108
Process Creation & Termination
109
System Calls fork() --- duplicates a process getpid() --- obtains a process’ ID number getppid() --- obtains a parent process’ ID number exit() --- terminate a process wait() --- waits for a child process Exec() --- replaces the code, data, and stack of a process
110
System Call fork() pit_t fork(void) Causes a process to duplicate The child process is almost exactly a duplicate of the parent process, but no sharing of memory inherits a copy of its parent's code, data, stack, open file descriptors, and signal tables The only difference is in the process IDs (pid) and parent process IDs (ppid)
111
System Call fork() If fork() succeeds, it returns a value of 0 to the child process and the PID of the child process to the parent. If fork() fails, it returns a -1 to the parent process and the child process is not created. Cannot predict which process runs first
112
If ((pid=fork()) == 0){ { … } else { } exit(0); if ((pid=fork() == 0){ { … } else { } exit(0); ParentChild fork() What’s a Fork() Child is an exact copy of the parent process. They have their own memory space.
114
As before, suppose foobar.txt consists of 6 ASCII characters "foobar". Then what is the output of the following program? int main() { int fd; char c; fd = open("foobar.txt", O_RDONLY, 0); if(fork() == 0) {read(fd, &c, 1); exit(0);} wait(NULL); read(fd, &c, 1); printf("c = %c\n", c); exit(0); }
115
fork Normal cases in fork: The parent waits for the child to complete. The parent and child each go their own way (e.g., network servers). Reasons for fork to fail Too many processes in the system The total number of processes for exceeds the limit: CHILD_MAX Usages of fork Duplicate a process to run different sections of code Want to run a different program
116
System Call getpid() pid_t getpid(void) pid_t getppid(void) Return the process' ID and parent process ID respectively They always succeed
117
Example Program with getpid() #include main () { int pid; printf ("I'm the original process with PID %d and PPID %d.\n", getpid (), getppid ()); pid = fork (); if (pid != 0) { printf ("I'm the parent process with PID %d and PPID %d.\n", getpid (), getppid ()); printf ("My child's PID is %d\n", pid); } else { printf ("I'm the child process with PID %d and PPID %d.\n", getpid (), getppid ()); } printf ("PID %d terminates.\n", getpid () ); } $./myfork I'm the original process with PID 639 and PPID 416. I'm the parent process with PID 639 and PPID 416. My child's PID is 640 PID 640 terminates. I'm the child process with PID 640 and PPID 639. PID 639 terminates.
118
Orphan Processes If a parent process terminates before its child terminates, the child process is automatically adopted by the init process The following program shows this.
119
Example Program of Orphan #include main () { int pid; printf ("I'm the original process with PID %d and PPID %d.\n", getpid (), getppid ()); pid = fork (); if (pid != 0) { printf ("I'm the parent process with PID %d and PPID %d.\n", getpid (), getppid ()); printf ("My child's PID is %d\n", pid); } else { sleep (5); /* Make sure that the parent terminates first */ printf ("I'm the child process with PID %d and PPID %d.\n", getpid (), getppid ()); } printf ("PID %d terminates.\n", getpid () ); } $ orphan I'm the original process with PID 680 and PPID 416. I'm the parent process with PID 680 and PPID 416. My child's PID is 681 PID 680 terminates. I'm the child process with PID 681 and PPID 1. PID 681 terminates.
120
Example Program of Orphan init Parent dies first Adopt child Child Survives The parent
121
System Call exit() void exit(int status) closes all of a process' file descriptors, deallocates its code, data, and stack; then terminates the process. When a child process terminates, it sends its parent a SIGCHLD signal and waits for its termination code (status) to be accepted. Only lower 8 bits of status are used; so value 0-255
122
System Call exit() A process which is waiting for its parent process to accept its return code is called a zombie process. A parent accepts a child's termination code by executing wait()
123
System Call exit() init always accepts its children's termination code. exit() never returns
124
Example of exit() % cat myexit.c #include #include /* needed for exit */ main() { printf("I am going to exit with status code 42\n"); exit(42); } % myexit I am going to exit with status code 42 % echo status is $? status is 42
125
Zombie Processes A process cannot leave the system until parent process accepts its termination code even if it has exit-ed If parent process is dead; init adopts process and accepts code If the parent process is alive but is unwilling to accept the child's termination code because it never executes wait() the child process will remain a zombie process.
126
Zombie Processes Zombie processes do not take up system resources But do use up an entry in the system's fixed-size process table Too many zombie processes is a problem
127
Zombie Example #include main () { int pid; pid = fork (); /* Duplicate */ if (pid != 0) { /* Never terminate, never execute a wait () */ while (1) sleep (1000); } else { exit (42); } [c33225@snowball ~]$./zombie & [1] 19263 [c33225@snowball ~]$ ps PID TTY TIME CMD 18434 pts/3 00:00:00 bash 19263 pts/3 00:00:00 zombie 19264 pts/3 00:00:00 zombie 19265 pts/3 00:00:00 ps [c33225@snowball ~]$ kill 19263 [c33225@snowball ~]$ ps PID TTY TIME CMD 18434 pts/3 00:00:00 bash 19267 pts/3 00:00:00 ps [1]+ Terminated./zombie
128
Waiting for a Child: wait() pid_t wait(int *status) Causes a process to suspend until one of its child processes terminates. A successful call to wait() returns the PID of the child process that terminated places a status code into status
129
Waiting for a Child: wait() Status code is encoded as: If the rightmost byte of status is zero the leftmost byte contains the low 8 bits of the value returned by the child's exit() or return() call If the rightmost byte of status is non-zero the rightmost 7 bits are equal to the Signal Number that caused the child to terminate the last bit is set to 1 if the child core dumped
130
Waiting for a Child: wait() If a process executes a wait() and has no children, wait() returns immediately with a value of -1 If a process executes a wait(), And one or more children are already zombies, Then wait() returns immediately with the status of one of the zombies
131
Example Program using wait() #include main () { int pid, status, childPid; printf ("I'm the parent process and my PID is %d\n", getpid()); pid = fork (); if (pid != 0) { printf ("I'm the parent process with PID %d and PPID %d\n", getpid (), getppid ()); /* Wait for a child to terminate. */ childPid = wait (&status); printf("A child with PID %d terminated with exit code %d\n", childPid, status >> 8); } else { printf ("I'm the child process with PID %d and PPID %d\n", getpid (), getppid ()); exit (42); } printf ("PID %d terminates\n", getpid () ); } $./mywait I'm the parent process and my PID is 695 I'm the parent process with PID 695 and PPID 418 I'm the child process with PID 696 and PPID 695 A child with PID 696 terminated with exit code 42 PID 695 terminates
132
Differentiating a Process: exec With the exec family, a process replaces Its current code Data Stack PID and PPID stay the same Only the code that the process is executing changes
133
Differentiating a Process: exec Use the absolute or relative pathname of the executable file to be supplied int execl(const char* path, const char* arg0,..., const char* argn, NULL) int execv(const char* path, const char* argv[ ])
134
Differentiating a Process: exec Use $PATH environment variable to find the executable: int execlp(const char* path, const char* arg0,..., const char* argn, NULL) int execvp(const char* path, const char* argv[ ])
135
Differentiating a Process: exec argi or argv[i]: ith command line argument for executable (arg0: name of executable) If executable is not found, -1 is returned otherwise the calling process replaces its code, data, and stack with those of the executable and starts executing the new code A successful exec() never returns
136
Example Using execl() #include main () { printf ("I'm process %d and I'm about to exec an ls -l\n", getpid ()); execl ("/bin/ls", "ls", "-l", NULL); /* Execute ls */ printf ("This line should never be executed\n"); } [c33225@snowball monitor]$./myexec I'm process 24543 and I'm about to exec an ls -l total 56 -rwxrwxr-x 1 c33225 c33225 9270 Jul 20 20:13 monitor -rw-rw-r-- 1 c33225 c33225 7547 Jul 15 19:20 monitor.c -rw-rw-r-- 1 c33225 c33225 134 Jul 20 20:22 monitor.out -rwxrwxr-x 1 c33225 c33225 5351 Jul 22 15:10 myexec -rw-rw-r-- 1 c33225 c33225 212 Jul 22 15:10 myexec.c
137
Changing Directories: chdir() Every process has a current working directory Used when processing a relative path name A child process inherits the current working directory from its parent Example: when a utility is run from a shell, the utility process inherits the shell's current working directory
138
Changing Directories: chdir() int chdir(const char* pathname) Sets a process' current working directory to pathname The process must have execute permission from the directory for chdir() to succeed chdir() returns -1 if it fails 0 if it succeeds
139
Example Using chdir() #include main () { system ("pwd"); /* Change working directory to root directory */ chdir ("/"); /* Display new working directory */ system ("pwd"); chdir ("/home/c33225"); /* Change again */ system ("pwd"); /* Display again */ } $./mychdir /home/c33225/temp / /home/c33225
140
Changing Priorities: nice() Child process inherits priority of parent process Can change the priority using nice() int nice(int delta) Adds delta to the priority Legal values of priority -20 to +19 Only super user can change to negative priority. Smaller the priority value, faster the process will run.
141
Example Using nice() #include main () { printf (“original priority\n”); system (“ps”); nice (0); printf (“running at priority 0\n”); system (“ps”); nice (10); printf(“running at priority 10\n”); system (“ps”); } [c33225@snowball ~]$./mynice original priority UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 70110 23427 00000000 00010000 00384004 4b813efb Ss pts/3 0:00 -bash 70110 24814 00000000 00010000 00000006 00000000 S+ pts/3 0:00./mynice 70110 24815 00000000 00000000 00000000 73d3fad9 R+ pts/3 0:00 ps -s running at priority 0 UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 70110 23427 00000000 00010000 00384004 4b813efb Ss pts/3 0:00 -bash 70110 24814 00000000 00010000 00000006 00000000 S+ pts/3 0:00./mynice 70110 24816 00000000 00000000 00000000 73d3fad9 R+ pts/3 0:00 ps -s running at priority 10 UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 70110 23427 00000000 00010000 00384004 4b813efb Ss pts/3 0:00 -bash 70110 24814 00000000 00010000 00000006 00000000 SN+ pts/3 0:00./mynice 70110 24817 00000000 00000000 00000000 73d3fad9 RN+ pts/3 0:00 ps -s
142
Getting and Setting User and Group IDs: The get functions always succeed The set methods will succeed only when executed by super user or if id is the real or effective ID of the calling process. uid_t getuid() uid_t setuid(uid_t id) uid_t geteuid() uid_t seteuid(uid_t id) gid_t getgid() uid_t setgid(gid_t id) gid_t getegid() uid_t setegid(gid_t id)
143
Example Using fork() and exec() Executes a program in background Original process creates a child process to exec the specified executable and terminates. The orphaned child process is adopted by init.
144
Example Using fork() and exec() #include main (int argc, char* argv[]) { if (fork () == 0) /* Child */ { /* Execute other program */ execvp (argv[1], &argv[1]); fprintf (stderr, "Could not execute %s\n", argv[1]); } $ background gcc mywait.c $ mywait.c: In function âmainâ: mywait.c:20: warning: incompatible implicit declaration of built-in function âexitâ
145
Signal Programs sometimes deal with unexpected or unpredictable events, such as A floating-point error A power failure An alarm clock “ring” The death of a child process A termination request from a user (i.e., a Control-C) A suspend request from a user (i.e., a Control-Z) all these called interrupts when interrupts happens, UNIX sends the corresponding process a signal.
146
Signal Signals are defined in “usr/include/sys/signal.h” Signal handler usually performs one of the following actions: Terminates the process and generates a core file (dump) Terminates the process without generating a core image file (quit) Ignores and discards the signal (ignore) Suspends the process (suspend) Resumes the process
147
A List of Signals Macro#DefaultDescription SIGHUP1quitHang-up SIGINT2quitInterrupt SIGQUIT3dumpQuit SIGILL4dumpInvalid instruction SIGTRAP5dumpTrace trap SIGABRT6dumpAbort SIGEMT7dumpEmulator trap instruction SIGFPE8dumpArithmetic exception SIGKILL9quitKill SIGBUS10dumpBus error SIGSEGV11dumpSegmentation violation SIGSYS12dumpBad argument to system call SIGPIPE13quitWrite to a pipe with no one to read it SIGALRM14quitAlarm clock SIGTERM15quitSoftware termination signal
148
A List of Signals Macro#DefaultDescription SIGUSR116quitUser signal 1 SIGUSR217quitUser signal 2 SIGCHLD18ignoreChild status changed SIGPWR19ignorePower fail or restart SIGWINCH20ignoreWindow size change SIGURG21ignoreUrgent socket condition SIGPOLL22exitPollable event SIGSTOP23quitStopped (signal) SIGSTP24quitStopped (user) SIGCONT25ignoreContinued SIGTTIN26quitStopped (tty input) SIGTTOU27quitStopped (tty output) SIGVTALRM28quitVirtual timer expired SIGPROF29quitProfiling time expired SIGXCPU30dumpCPU time limit exceeded SIGXFSZ31dumpFile size limit exceeded
149
Terminal Signals When recognizes Control-C, send a SIGINT signal to all foreground processes SIGINTquit When recognizes Control-Z, send a SIGTSTP signal to all foreground processes SIGTSTPsuspend
150
Alarm Signal unsigned int alarm (unsigned int count) send SIGALRM signal after count seconds display message “Alarm clock” and terminates the process return the number of seconds that remain until the alarm signal is sent
151
Example with alarm() #include main() { alarm(3);/* schedule an alarm signal in three seconds */ printf(“Looping forever … \n”); while (1); printf(“This line should never be executed\n”); } $./alarm Looping forever … Alarm clock//occur three seconds later
152
Handling Signals: signal() void (*signal(int sigCode, void(*func)(int))) (int) Allow a process to specify the action to override the default action sigCode specifies the number of the signal that is to reprogrammed func may be one of several values SIG_IGN: ignore or discard specified signal SIG_DFL: default hander used
153
pause int pause (void) Suspends the calling process and returns when the calling process receives a signal Often used to wait efficiently for an alarm signal It doesn’t return anything useful
154
Example with pause() #include int alarmFlag = 0; void alarmHandler(); main() { signal(SIGALRM, alarmHander); alarm(3); printf(“Looping …\n”); while(!alarmFlag) { pause(); } printf(“Loop ends due to alarm signal \n”); } void alarmHandler() { printf(“An alarm clock signal was received \n”); alarmFlag = 1; } $./handler Looping … An alarm clock signal was received Loop ends due to alarm signal
155
Sending Signal: kill() Int kill (pid_t pid, int sigCode) Send the signal with value sigCode to the process with PID pid Success conditions The sending process and the receiving process have the same owner The sending process is owned by a superuser
156
Example with kill() #include int delay; void childHandler(); main(int argc, char* argv[]) { int pid; signal(SIGCHLD, childHandler); pid = fork(); if (pid == 0) { execvp(argv[2], &argv[2]); perror(“limit”); } else { sscanf(argv[1], “%d”, &delay); sleep(delay); printf(“child %d exceeded limit and is being killed\n”, pid); kill(pid, SIGINT); } void childHandler() { int childPid, childStatus; childpid = wait(&childStatus); printf(“Child %d terminated within %d seconds \n”, childPid, delay); exit(0); } $./limit 5 ls power.hlimit limit.c power power.c Child 994 terminated within 5 seconds $./limit 4 sleep 100 Child 1001 exceeded limit and is being killed
157
Suspending and Resuming Processes #include Main() { int pid1; int pid2; pid1 = fork(); /*First child*/ if (pid1 == 0) { while(1) { printf(“pid1 is alive\n”); sleep(1); } pid2 = fork(); /*Second child*? if (pid == 0) { while(1) { printf(“pid2 is alive\n”); sleep(1); } sleep(3); kill(pid1, SIGSTOP); /*Suspend first child*/ sleep(3); kill(pid1, SIGCONT); /*Resume first child*/ sleep(3); kill(pid1, SIGINT); /*Kill first child*/ kill (pid2, SIGINT); /*Kill second child*/ } $./pulse pid1 is alive //both run in first three seconds pid2 is alive pid1 is alive pid2 is alive pid1 is alive pid2 is alive pid2 is alive // just the second child runs now pid2 is alive pid1 is alive // the fist child is resumed pid2 is alive pid1 is alive pid2 is alive pid1 is alive pid2 is alive
158
Review C commands here work with OS Error Handling File I/O and management open read write close stat
159
Review System Commands fork() getpid() exit() wait() exec
160
Review Working with directories and file entries getdents chown chmod Process Management fork chdir nice
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.