Skip to content

Commit a4adc6c

Browse files
author
Margo
committed
Add code for lecture demonstrations.
1 parent c37ac9e commit a4adc6c

File tree

9 files changed

+385
-0
lines changed

9 files changed

+385
-0
lines changed

shell3/GNUmakefile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
ALLPROG=share own pipe pipe1 pipe2 pipe3 pipeline
2+
all: $(ALLPROG)
3+
O ?= -O2
4+
5+
include ../common/rules.mk
6+
7+
%: %.o $(BUILDSTAMP)
8+
$(CC) $(LDFLAGS) -o $@ $<
9+
10+
%.o: %.c $(BUILDSTAMP)
11+
$(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCFLAGS) $(O) -o $@ -c $<
12+
13+
clean:
14+
rm -f $(ALLPROG) *.o
15+
rm -rf $(DEPSDIR) *.dSYM
16+
17+
.PHONY: all clean

shell3/data.out

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PARENTPARENTchildPARENTchildPARENTchildPARENTchildPARENTchildPARENTPARENTPARENTPARENTchildchildchildchildchild

shell3/own.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include <sys/stat.h>
2+
#include <sys/types.h>
3+
#include <fcntl.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <unistd.h>
8+
9+
int main(int argc, char *argv[]) {
10+
(void)argc;
11+
(void)argv;
12+
13+
14+
// We want the parent and child to each have their own file descriptor.
15+
// So, we will create the file in the parent and then close it; then
16+
// we'll open it after the fork.
17+
int fd = open("data.out", O_CREAT | O_WRONLY, 0644);
18+
if (fd < 0)
19+
exit(1);
20+
close(fd);
21+
22+
pid_t p = fork();
23+
24+
fd = open("data.out", O_WRONLY, 0644);
25+
26+
if (p == 0) {
27+
// Child
28+
const char *buf = "child";
29+
ssize_t len = (ssize_t)strlen(buf);
30+
for (int i = 0; i < 10; i++) {
31+
if (write(fd, buf, strlen(buf)) != len)
32+
exit(1);
33+
usleep(1);
34+
}
35+
} else if (p > 0) {
36+
// Parent
37+
const char *buf = "PARENT";
38+
ssize_t len = (ssize_t)strlen(buf);
39+
for (int i = 0; i < 10; i++) {
40+
if (write(fd, buf, strlen(buf)) != len)
41+
exit(1);
42+
usleep(1);
43+
}
44+
} else
45+
printf("Fork failed!\n");
46+
}

shell3/pipe.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include <sys/stat.h>
2+
#include <sys/types.h>
3+
#include <fcntl.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <unistd.h>
8+
9+
// Pipe from parent to child without proper pipe hygiene
10+
int main(int argc, char *argv[]) {
11+
(void)argc;
12+
(void)argv;
13+
14+
// We want to establish a pipe between the parent and child
15+
// so we have to create the pipe (and therefore open its file
16+
// descriptors) before forking.
17+
int pipefd[2];
18+
19+
if (pipe(pipefd) != 0)
20+
exit(1);
21+
22+
// We now have two open file descriptors that our processes will use
23+
pid_t p = fork();
24+
pid_t mypid = getpid();
25+
26+
if (p == 0) {
27+
// Child: We want the parent to write to the child, so
28+
// that means the child will be the reader.
29+
char buf[1];
30+
printf("Child(%d): ", mypid);
31+
while (read(pipefd[0], buf, 1) > 0)
32+
printf("%c", buf[0]);
33+
printf("\n");
34+
} else if (p > 0) {
35+
// Parent -- will be writer
36+
printf("Parent(%d)\n", mypid);
37+
char *buf = "Message from parent to child\n";
38+
ssize_t len = (ssize_t)strlen(buf);
39+
if (write(pipefd[1], buf, len) != len)
40+
exit(1);
41+
// Close pipe
42+
close(pipefd[1]);
43+
} else
44+
printf("Fork failed!\n");
45+
46+
}

shell3/pipe1.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include <sys/stat.h>
2+
#include <sys/types.h>
3+
#include <fcntl.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <unistd.h>
8+
9+
// In this one, we close the write end of the pipe in the child
10+
int main(int argc, char *argv[]) {
11+
(void)argc;
12+
(void)argv;
13+
14+
// We want to establish a pipe between the parent and child
15+
// so we have to create the pipe (and therefore open its file
16+
// descriptors) before forking.
17+
int pipefd[2];
18+
19+
if (pipe(pipefd) != 0)
20+
exit(1);
21+
22+
// We now have two open file descriptors that our processes will use
23+
pid_t p = fork();
24+
pid_t mypid = getpid();
25+
26+
if (p == 0) {
27+
close(pipefd[1]);
28+
// Child: We want the parent to write to the child, so
29+
// that means the child will be the reader.
30+
char buf[1];
31+
printf("Child(%d): ", mypid);
32+
while (read(pipefd[0], buf, 1) > 0)
33+
printf("%c", buf[0]);
34+
printf("\n");
35+
} else if (p > 0) {
36+
// Parent -- will be writer
37+
printf("Parent(%d)\n", mypid);
38+
char *buf = "Message from parent to child\n";
39+
ssize_t len = (ssize_t)strlen(buf);
40+
if (write(pipefd[1], buf, len) != len)
41+
exit(1);
42+
// Close pipe
43+
close(pipefd[1]);
44+
} else
45+
printf("Fork failed!\n");
46+
47+
48+
printf("%d exiting\n", mypid);
49+
}

shell3/pipe2.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#include <sys/stat.h>
2+
#include <sys/types.h>
3+
#include <fcntl.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <unistd.h>
8+
9+
// In this one, we close the write end of the pipe in the child
10+
// In this one, we close the extra read end too AND we make the pipe
11+
// connect stdout to stdin.
12+
int main(int argc, char *argv[]) {
13+
(void)argc;
14+
(void)argv;
15+
16+
// We want to establish a pipe between the parent and child
17+
// so we have to create the pipe (and therefore open its file
18+
// descriptors) before forking.
19+
int pipefd[2];
20+
21+
if (pipe(pipefd) != 0)
22+
exit(1);
23+
24+
// We now have two open file descriptors that our processes will use
25+
pid_t p = fork();
26+
pid_t mypid = getpid();
27+
28+
if (p == 0) {
29+
close(pipefd[1]);
30+
// Child: We want the parent to write to the child, so
31+
// that means the child will be the reader.
32+
// This makes the pipe read end be the child's stdin,
33+
// closing all the extra file descriptors.
34+
dup2(pipefd[0], STDIN_FILENO);
35+
close(pipefd[0]);
36+
char buf[1];
37+
printf("Child(%d): ", mypid);
38+
while (read(STDIN_FILENO, buf, 1) > 0)
39+
printf("%c", buf[0]);
40+
printf("\n");
41+
} else if (p > 0) {
42+
close(pipefd[0]);
43+
printf("Parent(%d)\n", mypid);
44+
// Parent -- will be writer
45+
// This makes the pipe write end be the parent's stdout,
46+
// closing the old stdout and the extra fd from the pipe.
47+
dup2(pipefd[1], STDOUT_FILENO);
48+
close(pipefd[1]);
49+
char *buf = "Message from parent to child\n";
50+
ssize_t len = (ssize_t)strlen(buf);
51+
if (write(STDOUT_FILENO, buf, len) != len)
52+
exit(1);
53+
} else
54+
printf("Fork failed!\n");
55+
56+
57+
printf("%d exiting\n", mypid);
58+
}

shell3/pipe3.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include <sys/stat.h>
2+
#include <sys/types.h>
3+
#include <fcntl.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <unistd.h>
8+
9+
// In this one, we demonsrate proper pipe hygiene, but use printf/scanf
10+
// to make it obvious that we're redirecting stdin/stdout.
11+
int main(int argc, char *argv[]) {
12+
(void)argc;
13+
(void)argv;
14+
15+
// We want to establish a pipe between the parent and child
16+
// so we have to create the pipe (and therefore open its file
17+
// descriptors) before forking.
18+
int pipefd[2];
19+
20+
if (pipe(pipefd) != 0)
21+
exit(1);
22+
23+
// We now have two open file descriptors that our processes will use
24+
pid_t p = fork();
25+
pid_t mypid = getpid();
26+
27+
if (p == 0) {
28+
printf("Child(%d): ", mypid);
29+
close(pipefd[1]);
30+
// Child: We want the parent to write to the child, so
31+
// that means the child will be the reader.
32+
// This makes the pipe read end be the child's stdin,
33+
// closing the old stdin and the extra pipefd.
34+
dup2(pipefd[0], STDIN_FILENO);
35+
close(pipefd[0]);
36+
char buf[1024];
37+
if (scanf("%s", buf) != 1)
38+
printf("Scanf failed\n");
39+
printf("Child read %s\n", buf);
40+
} else if (p > 0) {
41+
printf("Parent(%d)\n", mypid);
42+
close(pipefd[0]);
43+
// Parent -- will be writer
44+
// This makes the pipe write end be the parent's stdout,
45+
// closing the old stdout.
46+
dup2(pipefd[1], STDOUT_FILENO);
47+
close(pipefd[1]);
48+
printf("Message-from-parent-to-child\n");
49+
} else
50+
printf("Fork failed!\n");
51+
52+
53+
printf("%d exiting\n", mypid);
54+
}

shell3/pipeline.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#include <sys/stat.h>
2+
#include <sys/types.h>
3+
#include <sys/wait.h>
4+
#include <assert.h>
5+
#include <fcntl.h>
6+
#include <stdio.h>
7+
#include <stdlib.h>
8+
#include <string.h>
9+
#include <unistd.h>
10+
11+
// We will create a pipe between two child processes by creating the
12+
// following pipeline: ls | cat.
13+
int main(int argc, char *argv[]) {
14+
(void)argc;
15+
(void)argv;
16+
17+
int pipefd[2];
18+
19+
if (pipe(pipefd) != 0)
20+
exit(1);
21+
22+
// Fork off first child -- its STDOUT should be the write end of
23+
// the pipe.
24+
pid_t p1 = fork();
25+
26+
if (p1 == 0) {
27+
// We are in the first child; we can close off the read end
28+
// of the pipe.
29+
close(pipefd[0]);
30+
31+
// Next, let's hook up our standard out to the pipe, and
32+
// close extra fds.
33+
dup2(pipefd[1], STDOUT_FILENO);
34+
close(pipefd[1]);
35+
36+
// Now, let's exec ls
37+
char *cargv[] = {"ls", 0};
38+
execvp("ls", cargv);
39+
printf("If this ever prints something bad happened\n");
40+
}
41+
42+
// We aren't the child, so let's make sure we didn't error
43+
assert(p1 > 0);
44+
45+
pid_t p2 = fork();
46+
47+
if (p2 == 0) {
48+
// We are in the second child; let's close off the write
49+
// end of the pipe.
50+
close(pipefd[1]);
51+
52+
// Now let's hook up our standard in to the pipe and
53+
// close extra fds.
54+
dup2(pipefd[0], STDIN_FILENO);
55+
close(pipefd[0]);
56+
57+
// Now we should be able to exec sort
58+
char *cargv[] = {"sort", 0};
59+
execvp("sort", cargv);
60+
printf("If we get here the second exec failed\n");
61+
}
62+
63+
assert(p2 > 0);
64+
65+
// We are the parent; let's close the pipe
66+
close(pipefd[0]);
67+
close(pipefd[1]);
68+
69+
// Now let's wait for the second child
70+
int status;
71+
waitpid(p2, &status, 0);
72+
}

shell3/share.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <sys/stat.h>
2+
#include <sys/types.h>
3+
#include <fcntl.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <unistd.h>
8+
9+
int main(int argc, char *argv[]) {
10+
(void)argc;
11+
(void)argv;
12+
13+
14+
// We want the parent and child to share the file descriptor
15+
// so we are going to open it BEFORE forking
16+
int fd = open("data.out", O_CREAT | O_WRONLY, 0644);
17+
if (fd < 0)
18+
exit(1);
19+
20+
pid_t p = fork();
21+
22+
if (p == 0) {
23+
// Child
24+
const char *buf = "child";
25+
ssize_t len = (ssize_t)strlen(buf);
26+
for (int i = 0; i < 10; i++) {
27+
if (write(fd, buf, strlen(buf)) != len)
28+
exit(1);
29+
usleep(1);
30+
}
31+
} else if (p > 0) {
32+
// Parent
33+
const char *buf = "PARENT";
34+
ssize_t len = (ssize_t)strlen(buf);
35+
for (int i = 0; i < 10; i++) {
36+
if (write(fd, buf, strlen(buf)) != len)
37+
exit(1);
38+
usleep(1);
39+
}
40+
} else
41+
printf("Fork failed!\n");
42+
}

0 commit comments

Comments
 (0)