标签:before write mina keyboard lua uil several htm request
Preface: Most of the answers below are written by myself --- only instructors are given access to the exercise solutions. If you find anything wrong, please let me know so that I can correct them, thank you!
Note: You can answer this question by looking at the manual page for fork, but before you do that, think about what the fork system call does. If you were designing this call, would you need to allow fork to return an error?
Yes. Because we need to ensure the parent process notified if this system call fails, and returning an error directly is one way to achieve that.
According to the man page of fork(2)
in Ubuntu 18.04.1:
On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately.
Note: You can answer this question by looking at the manual page for exec, but before you do that, think about what the exec system call does. If you were designing this call, would you need to allow it to return an error?
Yes. Because when a process fails to call exec()
, we must ensure it notified to do something about this exception, and returning an error directly is one of the way to achieve that.
According to the man page of execve(2)
in Ubuntu18.04.1:
on error -1 is returned, and errno is set appropriately.
main(){
while (fork() >= 0)
;
}
This is called a fork bomb, which is a denial-of-service attack where in a process continually replicates itself to deplete available system resources, slowing down or crashing the system due to resource starvation.
After I run this bomb in Ubuntu 18.04.1 (virtualbox), it seems like the process -resources are being exhausted and other programs can not be started:
According to the manual pages of FreeBSD, On return from a successful wait()
call, the status area contains information about the process that reported a status change will be set. And In the case of a terminated child, performing a wait()
allows the system to release the resources associated with the child.
The fifth question is meaningless.
The shell will be replaced with csh
, but the process(id) preserved:
The shell will be replaced with the ls
program with same process, but since ls
is not an interactive program, the terminal window will close instantly.
void forkthem(int n){
if (n > 0){
fork();
forkthem(n-1);
}
}
main(int argc, char ** argv){
forkthem(5);
}
2^5 = 32
main (int argc, char ** argv) {
int child = fork();
int x = 5;
if (child == 0){
x += 5;
} else {
child = fork();
x += 10;
if(child) {
x+= 5;
}
}
}
How many different copies of the variable x are there? What are their values when their process finishes?
There will be three different copies of the variable x: 5+5=10, 5+10=15, 5+10+5=20.
// Program 1
main() {
int val = 5;
int pid;
if (pid = fork())
wait(pid);
val++;
printf("%d\n", val);
return val;
}
//Program 2
main(){
int val = 5;
int pid;
if (pid = fork())
wait(pid);
else
exit(val);
val++;
printf("%d\n", val);
return val;
}
Program 1: 6\n6\n
Program 2: 6\n
I have implemented a shell which supports foreground and background tasks, as well as job control when I read the csapp 3e – Code and descriptions here(Chinese), so I will just improve it with pipeline support here.
The part of changed code:
/*
* find_second_argv_in_pipe - Find the argv for the second program in
* single-pipe command
*
* If no pipe symbol find, return NULL, else return the second argv
*/
char ** find_second_argv_in_pipe(char *argv[])
{
for(int i = 0; argv[i] != NULL; i++)
{
if(!strcmp(argv[i], "|"))
{
argv[i] = NULL;
return &argv[i+1];
}
}
return NULL;
}
/*
* eval - Evaluate the command line that the user has just typed in
*
* If the user has requested a built-in command (quit, jobs, bg or fg)
* then execute it immediately. Otherwise, fork a child process and
* run the job in the context of the child. If the job is running in
* the foreground, wait for it to terminate and then return. Note:
* each child process must have a unique process group ID so that our
* background children don‘t receive SIGINT (SIGTSTP) from the kernel
* when we type ctrl-c (ctrl-z) at the keyboard.
*
*2018.10.14: single pipe is supported now
*/
void eval(char *cmdline)
{
char *argv[MAXARGS];
char **argv2 = NULL;
int bg_flag;
bg_flag = parseline(cmdline, argv); /* true if the user has requested a BG job, false if the user has requested a FG job. */
argv2 = find_second_argv_in_pipe(argv);
if (builtin_cmd(argv, cmdline)) /* built-in command */
{
return;
}
else /* program (file) */
{
pid_t pid;
sigset_t mask, prev;
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
sigprocmask(SIG_BLOCK, &mask, &prev); /* block SIG_CHLD */
int pipefd[2]; /* pipefd[0] refers to the read end of the pipe.
pipefd[1] refers to the write end of the pipe. */
if (access(argv[0], F_OK)) /* do not fork and addset! */
{
fprintf(stderr, "%s: Command not found\n", argv[0]);
return;
}
if(argv2) /* single pipe command */
{
if (access(argv2[0], F_OK)) /* do not fork and addset! */
{
fprintf(stderr, "%s: Command not found\n", argv2[0]);
return;
}
if(pipe(pipefd))
{
perror("Failed to creat pipe file");
return;
}
}
if ((pid=fork()) == 0) /* child1 */
{
sigprocmask(SIG_SETMASK, &prev, NULL); /* unblock SIG_CHLD */
if (!setpgid(0, 0))
{
if(argv2)
{
if ((pid=fork()) == 0) /* child2 */
{
if((dup2(pipefd[0], STDIN_FILENO)==-1))
{
perror("Failed to dup2 in program2 for pipe operation");
_exit(EXIT_FAILURE);
}
close(pipefd[0]);close(pipefd[1]);
if (execve(argv2[0], argv2, environ))
{
fprintf(stderr, "%s: Failed to execve\n", argv2[0]);
_exit(EXIT_FAILURE);
}
}
if((dup2(pipefd[1], STDOUT_FILENO)==-1))
{
perror("Failed to dup2 in program1 for pipe operation");
_exit(EXIT_FAILURE);
}
close(pipefd[0]);close(pipefd[1]);
}
if (execve(argv[0], argv, environ))
{
fprintf(stderr, "%s: Failed to execve\n", argv[0]);
_exit(EXIT_FAILURE);
}
/* context changed */
}
else
{
fprintf(stderr, "Failed to invoke setpgid(0, 0)\n");
_exit(EXIT_FAILURE);
}
}
else if (pid > 0)/* tsh */
{
if (!bg_flag) /* exec foreground */
{
fg_pid = pid;
fg_pid_reap = 0;
addjob(jobs, pid, FG, cmdline);
sigprocmask(SIG_SETMASK, &prev, NULL); /* unblock SIG_CHLD */
waitfg(pid);
}
else /* exec background */
{
addjob(jobs, pid, BG, cmdline);
sigprocmask(SIG_SETMASK, &prev, NULL); /* unblock SIG_CHLD */
printf("[%d] (%d) %s", maxjid(jobs), pid, cmdline);
}
/* DONT‘T forget to close the pipefd in tsh process
otherwise the second program will stall output until
tsh exits */
close(pipefd[0]);close(pipefd[1]);
return;
}
else
{
unix_error("Failed to fork child");
}
}
return;
}
Please refer to the code above.
Operating Systems Principles and Practice 2nd 3Ch Exercises
标签:before write mina keyboard lua uil several htm request
原文地址:https://www.cnblogs.com/liqiuhao/p/9787404.html