OS Interface 1

advertisement
OS Interface 1
• Learn OS interface before OS internal.
• Learn programming with OS system calls
(the ultimate API).
• UNIX as an example
• A subset of common UNIX System calls
– For a complete list of system calls on solaris, try
“man -s 2 intro” on program.cs.fsu.edu.
– The subset breaks down into three areas:
• Process Management: fork(), exec(), exit(), wait()
• InterProcess Communication (IPC): pipe(), signal().
• File and I/O System calls: open(), creat(), read(),
write(), lseek(), close(), unlink(), dup(), and stat()
– A good reference book:
• W. Richard Stevens, “Advanced Programming in the
UNIX environment,” Addison-Wesley.
Process management
• Examining processes in UNIX
– The ps command displays standard process
attributes.
– /proc directory contains more information
– top, vmstat commands examine CPU and
memory usage statistics.
Process management system calls
• Process creation:
– Reasons:
• User needs to run a program
• OS needs to create a process to provide a service
• One process starts another process
– In UNIX, a process is created by duplicating
the image of the calling process (parent
process).
• System call: fork();
Process creation system call: fork()
– create a new process. The new process (child) is
an exact copy of the calling process (parent).
Examples (example1.cpp, example2.cpp):
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
using namespace std;
main() {
fork();
cout << “111111\n”;
}
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
using namespace std;
main() {
getchar();
cout << “1111111\n”;
fork();
getchar();
cout << “2222222\n”;
}
• Points to note:
– fork() is called once, but returns two times
• Once in the parent
• Once in the child
• Parent and child are totally independent (e.g modifying a
variable in one process has no effects on the other process).
– How to distinguish between parent and child
• Return 0 in child
• Return a positive number (process id) in parent
– If the process creation fails, return –1;
• All UNIX system calls return –1 when the the calls fail.
• You should always check the return value of each system call.
– See example3.c and example4.cpp
#include <sys/types.h>
#include <unistd.h>
main() {
int pid;
if ((pid = fork()) == 0) {
// child process
printf(“I am child, my pid = %d\n”, getpid());
} else {
// parent process
printf(“I just made a child, pid = %d\n”, pid );
}
}
example3.c
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
using namespace std;
main() {
int val;
val = 10;
if (fork()) val = 20;
cout << “val = “ << val << “\n”;
}
example4.cpp
What is the value of I after
‘I = fork();’
• Three cases
• What is the purpose for creating processes?
– In most cases, to run commands.
– fork() itself does not quite do it: the source code
of the child process must be in the source code
of the parent process.
– We need something like ‘run_command’
routine that can execute pre-compiled
commands.
– In UNIX, this is done by the exec family
system calls.
The exec family system calls
• Load a new executable into the current
process image.
• The current process image is erased (no
return if the call is successful).
• For more details, ‘man –a exec’
• An example: execute the executable path.
int execv(const char *path, char *const argv[]);
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <stdio.h>
Using namespace std;
main() {
char command[100];
char *argv[10];
strcpy(command, “/bin/ls”);
argv[0] = command;
argv[1] = “/”;
argv[2] = NULL;
execv(command, argv);
cout << “finished\n”;
}
example5.cpp
(“/bin/ls /”)
• The argv is set exactly
the same as the regular
C/C++ programs.
• argv[0] must always
be the same as the
command.
• The last command
argument must be
followed by a NULL
pointer.
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <stdio.h>
Using namespace std;
main() {
char command[100];
char *argv[10];
strcpy(command, “/bin/ls”);
argv[0] = command;
argv[1] = “/”;
argv[2] = NULL;
if (execv(command, argv) != -1) cout << “successful!!\n”;
else cout << “failed n”;
}
Any comment about this program?
• The exec family system calls destroy the parent
process image.
•What if we want to keep the original process image
(e.g. to run multiple commands?)
• Fork an extra image to be destroyed by the exec system call.
#include <stdlib.h>
#include <unistd.h>
#include <iostream.h>
#include <stdio.h>
runcommand(char *command, char *argv[])
{
if (fork() == 0) {
// child process
execv(command, argv);
}
// parent process
// continue
}
Run using a child process
• Terminate process: exit
#include <stdlib.h>
void exit(int status);
• UNIX will call this routine automatically if it is not called by
the user.
• The status in exit can be examined by the parent process.
• UNIX convention:
• All successful execution exits with code 0.
• Default exit code when the end of the main() function
is reached.
• Exit code != 0 indicates abnormal execution.
• Wait for a child process to stop: wait, waitpid
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *stat_loc);
pid_t waitpid(pid_t pid, int *status, int options);
#include <stdlib.h>
#include <unistd.h>
#include <iostream.h>
#include <stdio.h>
runforeground(char *command, char *argv[])
{
int pid, status, rpid;
if ((pid = fork()) == 0) {
// child process
execv(command, argv);
}
rpid = wait(&status);
while ((rpid!= pid) && (rpid != -1))
rpid = wait(&status);
}
Foreground running
#include <stdlib.h>
#include <unistd.h>
#include <iostream.h>
#include <stdio.h>
runbackground(char *command, char *argv[])
{
if (fork() == 0) {
// child process
execv(command, argv);
}
// parent process
// continue
}
Background running
• Exit/wait
•
child
exit (10);
parent
wait(&stat_loc);
• The status in exit can be examined in the wait. See
example6.c, example7.c
• status = WEXITSTATUS(stat_loc)
• status = 0 for successful execution.
• status != 0 for failed execution.
• stat_loc also carries other information
• WIFSIGNALED(stat_loc)
• whether this process is killed by a signal (e.g ctrl-C).
• For more information, ‘man –a wait’
wait
• What are the <defunct> processes in ps?
– The process has exited.
– But it has not been waited upon.
• The entry in the process table is still occupied
– This is for passing exit status to the parent.
• The wait system call in the parent/or care taker
removes the entry from the process table.
• Implication? Make sure to have wait in your
code if you create a process in a program.
• Process manipulation system calls
fork() -- duplicate current process
execv() -- run a new executable file in the current process
wait() -- wait for the child process to finish
exit() -- terminate process
• For each system call above, name one thing that is different from
a typical routine call?
Download