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