File Access Library Calls

Download Report

Transcript File Access Library Calls

System Calls: pipes
CSRU3130
Ellen Zhang
1
Review: fork()
int K;
main() {
int i; int j;
j = 200;
K = 300;
printf("Before forking: j = %d, K = %d\n", j, K);
i = fork();
if (i > 0) {
sleep(10);
printf("After forking, parent: j = %d, K = %d\n", j, K);
} else {
j++; K++;
printf("After forking, child: j = %d, K = %d\n", j, K);
}
}
2
…
main() {
int i; int seekp; int fd;
char *s1;
char s2[1000];
fd = open("tmpfile", O_WRONLY | O_TRUNC | O_CREAT, 0666);
s1 = "Before forking\n";
write(fd, s1, strlen(s1));
i = fork();
if (i > 0) {
sleep(10); /* Delay the parent by ten seconds */
s1 = "Parent";
}
else {
s1 = "Child";
}
seekp = lseek(fd, 0, SEEK_CUR);
sprintf(s2, "%s: After forking: Seek pointer = %d\n", s1, seekp);
write(fd, s2, strlen(s2));
[zhang@storm Demo]$ ./a.out
}
[zhang@storm Demo]$ more tmpfile
3
Before forking
Child: After forking: Seek pointer = 15
Parent: After forking: Seek pointer = 55
Signals
 Mechanism for OS to notify processes of special events such as
 Timer expire
 User type Ctrl-C on the controlling terminal
 Owner kill the process
…
 Signals cause process to suspend its usual execution to run a
signal handling procedure
 Similar to hardware interrupt
4
Signals (cont’d)
 A signal is an interruption of program
 when you hit CNTL-C, SIGINT signal is sent to your program.
 When you hit CNTL-\, SIGQUIT signal is sent to your program.
 When you generate a segmentation violation, that sends the
SIGSEGV signal to your program.
 Command “kill” can be used to send a signal to a process
 kill -9 [process_id]
 By default, there are certain actions that take place.
 When you hit CNTL-C, program usually exits.
 When you hit CNTL-\ or get a segmentation violation, your
program dumps core and then exits (default action for SIGQUIT
and SIGSEGV)
5
Example of signals
Signal Value
SIGHUP
1
SIGINT
SIGQUIT
SIGILL
SIGABRT
SIGFPE
SIGKILL
SIGSEGV
SIGPIPE
6
2
3
4
6
8
9
11
13
Action Comment
Term Hangup detected on controlling
terminal or death of controlling process
Term
Interrupt from keyboard
Core
Quit from keyboard
Core
Illegal Instruction
Core
Abort signal from abort(3)
Core
Floating point exception
Term
Kill signal
Core
Invalid memory reference
Term
Broken pipe: write to pipe with no
readers
Register signal handler
#include < signal.h >
void cntl_c_handler(int dummy) {
printf("You just typed cntl-c\n");
signal(SIGINT, cntl_c_handler);
}
main() {
int i, j;
signal(SIGINT, cntl_c_handler);
for (j = 0; j < 40; j++) {
for (i = 0; i < 1000000; i++);
}
}
Example file: signal.c
7
Signal
as
IPC
void parentdone(int signum) {}
int main() {
int pid;
if ((pid = fork())== -1) {
perror("fork() failed");
exit(1);
}
if (pid == 0) {
/* child process */
signal(SIGUSR1, parentdone);
pause();
/* sleep until a signal is received */
printf("World!\n");
fflush(stdout);
8
} else {
/* parent process */
printf("Hello, ");
fflush(stdout);
kill(pid, SIGUSR1);
/* send a signal to the child */
wait(NULL);
/* wait the child exit */
}
exit(0);
} // end of main()
Pipe as inter-process communication
method
 In Unix, all inter-process communication must take
place with help of operating system
 Process is considered as primary unit of isolation: one process
cannot crash whole system, instead you get segmentation fault
 Well, not quite, the forkbomb we saw last class could halt
whole system ! Be extremely careful!
 Pipes are a nice clean IPC method

9
One process write to the pipe, one process read from it
Processes
Process memory layout
stack
Heap
Data
Text(Code)
10
Per-process
opened file table
0fd
10
21
pipefd[0]
2
pipefd[1]
3
r/w
r
w
w
rw
Operating
system
Pipe
 Pipe is a inter-process communication mechanism:
 Allow parent-child processes to communicate with each other
 Make pipeline in shell possible (avoid using disk file)
Producer:
Write data to
writing end
Consumer:
Read data from
reading end
 Pipes are treated as files
 You can call read() on the reading end, call write() on writing end,
close() it…
 FIFO: data that are written first into the pipe are read out first
 Operating system: buffer data to handler faster writer & slower
reader…
11
Pipe system call
 #include <unistd.h>
 int pipe(int fd[2]);
 Parameter: an array of two integers.
 Upon return: the array is filled with two file descriptions:
 fd[0]: reading end of pipe
 fd[1]: writing end of pipe
 Anything that is written on fd[1] can be read from fd[0].
 Pipes are treated as files
 You can use system call read(), write(), close() … on pipes
12
Simple example
#include <stdio.h>
main() {
int pipefd[2];
int i;
char s[1000];
char *s2;
if (pipe(pipefd) < 0) {
write() to a reading end of a pipe: asks
perror("pipe");
operating system to hold those bytes in
exit(1);
a buffer until some process requests for
}
them by performing a read() on the read
s2 = “Hello World!";
end of the pipe.
write(pipefd[1], s2, strlen(s2));
i = read(pipefd[0], s, 1000);
s[i] = '\0';
printf("Read %d bytes from the pipe: '%s'\n", i, s);
}
13
Visualize pipes
Process memory layout
stack
Heap
Data
Text(Code)
14
Per-process
opened file table
0fd
10
21
pipefd[0]
2
pipefd[1]
r/w
pipefd[0]
r
pipefd[1]
w
r
Operating
system
w
w
buffer
Hello World!
Pipe: inter-process
communication
main() {
else {
int pipefd[2];
//child process
int pid, i, line;
i = 0; line = 1;
char s[1000];
while(read(pipefd[0], s+i, 1) == 1) {
if (pipe(pipefd) < 0) {
if (s[i] == '\n') {
perror("pipe");
s[i] = '\0';
exit(1);
printf("%6d %s\n", line, s);
}
line++; i = 0;
pid = fork();
}
if (pid > 0) {
else {
// parent process
i++;
while(fgets(s, 1000, stdin) != NULL) {
}
write(pipefd[1], s, strlen(s));
} // end of while loop
}
} // end of else{
close(pipefd[1]);
}
} //end of main()
15
Visualize pipes
Parent Process
stack
Heap
Data
Text(Code)
Child process
Per-process
opened file table
0fd
10
21
pipefd[0]
2
pipefd[1]
Per-process
opened file table stack
r/w
fd
r/w
r
0
r
w
1
w
w
2
w
pipefd[0]
r
pipefd[0]
r
pipefd[1]
w
pipefd[1]
w
Operating
system
buffer
Hello World!
16
Heap
Data
Text(Code)
Let’s try it out: ctrl-d to finish standard input
Why the child process lingers ?
OS does not know no one is writing to pipe
Parent Process
stack
Heap
Data
Text(Code)
Child process
Per-process
opened file table
0fd
10
21
pipefd[0]
2
pipefd[1]
Per-process
opened file table stack
r/w
fd
r/w
r
0
r
w
1
w
w
2
w
pipefd[0]
r
pipefd[0]
r
pipefd[1]
w
pipefd[1]
w
Operating
system
buffer
Hello World!
17
Heap
Data
Text(Code)
main() {
else {
int pipefd[2];
int pid; int i, line;
close(0);
char s[1000];
close(pipefd[1]);
if (pipe(pipefd) < 0) {
i = 0; line = 1;
perror("pipe");
while(read(pipefd[0], s+i, 1) == 1) {
exit(1);
if (s[i] == '\n') {
}
pid = fork();
s[i] = '\0';
if (pid > 0) {
printf("%6d %s\n", line, s);
close(1);
line++; i = 0;
close(pipefd[0]);
}
while(fgets(s, 1000, stdin) != NULL) {
else {
write(pipefd[1], s, strlen(s));
i++;
}
close(pipefd[1]);
}
}
} //end of while
Sol: close unused ends of the pipe!!
18
} //end of else
} //end of main
Handling broken pipes
 When read from a pipe that has no write end, read() returns
0.
 When write to a pipe that has no read end, a SIGPIPE signal
is generated.
 If signal isn't handled, program exits silently
 Example: If you execute:
UNIX> cat exec1.c | head -5 | tail -1
 and you kill the middle process (the head one),
 the other two will exit automatically
19
Now: command pipeline
 In shell, we can build command pipeline
 How to implement this ?
 Create a pipe
 Create two child processes (both children inherit the pipe)
 Redirect standard output of first child to writing end of pipe
 Redirect standard input of second child to reading end of pipe
 First child to run first command, another child to run second
command
 How to redirect standard input/output ?
20
Redirect standard output
 To redirect standard output to a different target
 Open the target (whether a file, or a pipe) which returns a file descriptor,
say fd
 Duplicate the file descriptor, fd, to descriptor 1 (standard output)
 i.e., let file descriptor 1 pointing to the target
 Old and new descriptors may be used interchangeably, and they share locks, file
position pointers and flags.
 To duplicate file descriptor:
 int dup(int oldfd);
 int dup2(int oldfd, int newfd);
//Prefer to use this one
create a copy of file descriptor oldfd, to lowest-numbered unused file descriptor (dup), or
makes newfd be copy of oldfd, closing newfd first if necessary.
21
Example: pipeline.c
if (pipe(pipefd) < 0) {
perror("pipe");
exit(1);
} //upon successful return, pipefd[0] is reading end, pipefd[1] is writing end
pid = fork();
if (pid==0) {
ret=dup2 (pipefd[1],1); //close standard output, make 1 pointing to pipefd[1]
close (pipefd[1]); //as 1 is pointing to writing end too, we can close pipefd[1]
if (ret==-1){
fprintf (stderr,"first child cannot dup\n");
exit(1);
}
close(pipefd[0]); //close reading end of pipe
execlp("ls","ls",0); //the standard output of ls will be pipefd[1]
fprintf (stderr,”failed to execue ls”);
} //end of else
22
Redirect standard input to a file
 Here is code segment for redirect standard input to a file
int fd=open(“file.txt”,O_RDONLY);
if (fd<0) …
ret=dup2 (fd,0); //close current standard input, make 0
//pointing to the file that fd is pointing to
if (ret==-1){
fprintf (stderr,"first child cannot dup\n");
exit(1);
}
cin >> number >> name; //all subsequent read from standard
// input is from the file file.txt
23
Pipe vs named pipe
 For two processes to communicate through pipes, they need
access to same pipe
 Only possible if the pipe is created by their common ancestors
 Named pipe make it possible for two unrelated processes to
communicate in a similar way
 Named-pipe has a name (like other files), process can open the
pipe to read or write
24
Using named pipe
 Create a named pipe
mkfifo myPipe
 ls –l will show myPipe as
prw-r--r-- 1 zhang staff
0 2008-04-25 09:30 myPipe
 In one terminal, type:
 ls -l > myPipe
 in another type:
 cat < myPipe
 Difference with using file:
 You can start “cat” command first
 “ls” process will wait until “cat” pick up the output
 Remember that “ls” and “cat” program are not aware of the fact that
input/output is from/to a named pipe
25
Named pipes: server
#define HALF_DUPLEX "/tmp/halfduplex"
#define MAX_BUF_SIZE> 255
int main(int argc, char *argv[]) {
int fd, ret_val, count, numread;
char buf[MAX_BUF_SIZE];
ret_val = mkfifo(HALF_DUPLEX, 0666);
if ((ret_val == -1) && (errno != EEXIST)) {
perror("Error creating the named pipe");
exit (1);
}
fd = open(HALF_DUPLEX, O_RDONLY);
26
numread = read(fd, buf, MAX_BUF_SIZE);
buf[numread] = '0';
printf("Half Duplex Server : Read From the pipe : %sn", buf);
….
printf("Half Duplex Server : Converted String : %sn", buf);
}
Named pipe: client
#define HALF_DUPLEX "/tmp/halfduplex"
#define MAX_BUF_SIZE 255
int main(int argc, char *argv[]) {
int fd;
if (argc != 2) {
printf("Usage : %s <string to be sent to the server>n", argv[0]);
exit (1);
}
fd = open(HALF_DUPLEX, O_WRONLY);
write(fd, argv[1], strlen(argv[1]));
}
27
Process & Child Process
Processes do not share data or stack
Parent Process
stack
Heap
Data
Text(Code)
28
Child process
Per-process
opened file table
0fd
10
21
pipefd[0]
2
pipefd[1]
Per-process
opened file table stack
r/w
fd
r/w
r
0
r
w
1
w
r
2
r
Operating
system
Heap
Data
Text(Code)
Inter-Processes Communication:
pipe, shared memory, file, signal, …
Multi-thread programming
 Threads within a process share data
Process
and code (less expensive way to
achieve parallelism)
stack
 Each thread has separate stack space
 Programs need to ensure data
integrity:
 E.g., Multiple threads cannot write
a global variable simultaneously
29
pthread_create
New stack
for thread
Heap
Data
Text(Code)
Per-process
opened file table
0fd
10
21
pipefd[0]
2
pipefd[1]
r/w
r
w
r
Hints for final project: analysis
 How to get started ?
 Reading the requirement !
 Start with one simple cast:
 For example, focus first upon understanding how to support the –i mode
(i.e., read command from standard input)…
 Identify modules:
 I will need to be able to run a simple command (w/o pipeline)
 I will need to split pipeline into two commands
 I will need to see if there is a trailing & in command …
 Do not start next stage until you are clear what the program
needs to do …
30
Hints for final project: design
 How to implement the required functionalities?
 Do I know how to solve one case ?
 E.g., interactive mode
 Try write the pseudocode (a plan for the coding)
 Is the scripting mode (i.e., read command from file) much
different ?
 Try to generalize your solution as much as possible !
 Scripting mode and interactive mode
 Similarity ?
 Difference ?
31
Modular Design
 Identify and write the headers of functions
 Function body can be done later …
 Write main function
 A mixture of code and comments describing the pseudocode
will be fine
 Verifying your design before start coding
 Walk-through your code, pay attention to:
 The information flow: argument passing, value returning, …
32
Finally, coding/testing/debugging
 Whenever call a library function, make sure the arguments
are passed correctly
 And check the value returned for possible errors !!!
 Add assertion statement in the code to verify and isolate
errors
 assert (fp!=NULL);
 assert (n>0);
 Add printf () or cout statements to check the value of
important variables
 Is the program doing what I assume it is doing ?
 If not, when does it diverge from my assumption ?
33