Skip to content

Commit d967b5e

Browse files
committed
Add shell1 programs.
1 parent 0b040b7 commit d967b5e

10 files changed

+253
-0
lines changed

shell1/.gitignore

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
filtermultiples
2+
forkmix
3+
forkmix2
4+
manyfork
5+
pipedemo
6+
pipesizer
7+
primesieve

shell1/GNUmakefile

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
PROGRAMS = forkmix forkmix2 manyfork \
2+
pipedemo pipesizer \
3+
filtermultiples primesieve
4+
5+
all: $(PROGRAMS)
6+
7+
include ../common/rules.mk
8+
9+
%.o: %.c $(BUILDSTAMP)
10+
$(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCFLAGS) $(O) -o $@ -c $<
11+
12+
%-profgen: %-profgen.o
13+
$(CC) -fprofile-generate $^ -o $@
14+
15+
$(PROGRAMS): %: %.o
16+
$(CC) $(CFLAGS) $(O) -o $@ $^
17+
18+
19+
clean:
20+
rm -f *.o $(PROGRAMS)
21+
rm -rf $(DEPSDIR) *.dSYM
22+
23+
.PHONY: all clean

shell1/filtermultiples.c

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include "helpers.h"
2+
3+
int main(int argc, char** argv) {
4+
assert(argc >= 2);
5+
int p = strtol(argv[1], NULL, 10);
6+
assert(p > 1);
7+
8+
char buf[BUFSIZ];
9+
while (fgets(buf, BUFSIZ, stdin))
10+
if (isdigit((unsigned char) buf[0])) {
11+
int i = strtol(buf, NULL, 10);
12+
if (i % p != 0)
13+
printf("%d\n", i);
14+
}
15+
}

shell1/forkmix.c

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include "helpers.h"
2+
3+
int main(void) {
4+
pid_t p1 = fork();
5+
assert(p1 >= 0);
6+
7+
const char* text;
8+
if (p1 == 0)
9+
text = "BABY\n";
10+
else
11+
text = "mother\n";
12+
13+
for (int i = 0; i != 1000000; ++i)
14+
fputs(text, stdout);
15+
}

shell1/forkmix2.c

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include "helpers.h"
2+
3+
int main(int argc, char* argv[]) {
4+
assert(argc >= 2);
5+
6+
pid_t p1 = fork();
7+
assert(p1 >= 0);
8+
9+
FILE* f = fopen(argv[1], "w");
10+
11+
const char* text;
12+
if (p1 == 0)
13+
text = "BABY\n";
14+
else
15+
text = "mama\n";
16+
17+
for (int i = 0; i != 1000000; ++i)
18+
fputs(text, f);
19+
}

shell1/helpers.h

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#ifndef HELPERS_H
2+
#define HELPERS_H
3+
#include <unistd.h>
4+
#include <stdio.h>
5+
#include <assert.h>
6+
#include <stdlib.h>
7+
#include <string.h>
8+
#include <ctype.h>
9+
#include <signal.h>
10+
#include <sys/wait.h>
11+
#include <sys/time.h>
12+
#include <sys/select.h>
13+
#include <sched.h>
14+
#include <errno.h>
15+
16+
// timestamp()
17+
// Return the current time as a double.
18+
19+
static inline double timestamp(void) {
20+
struct timeval tv;
21+
gettimeofday(&tv, NULL);
22+
return tv.tv_sec + tv.tv_usec / 1000000.0;
23+
}
24+
25+
26+
// nfork()
27+
// Like `fork()`, but nondeterministically runs the child first.
28+
//
29+
// This is actually no different from `fork`, since the OS is allowed to
30+
// run either process first (or to run them in parallel on multiple
31+
// cores), but in practice it is rare that the child runs first. This
32+
// function is useful for shaking out race conditions.
33+
34+
static inline pid_t nfork(void) {
35+
pid_t p = fork();
36+
if (p > 0) {
37+
struct timeval tv;
38+
gettimeofday(&tv, NULL);
39+
if (tv.tv_usec % 7 < 4)
40+
sched_yield();
41+
}
42+
return p;
43+
}
44+
45+
46+
// handle_signal(signo, handler)
47+
// Install `handler` as the signal handler for `signo`.
48+
// The `handler` is automatically re-installed after signal delivery.
49+
// Has the same interface as `signal()` (`man 2 signal`), but is portable.
50+
51+
static inline int handle_signal(int signo, void (*handler)(int)) {
52+
struct sigaction sa;
53+
sa.sa_handler = handler; // call `handler` on signal
54+
sigemptyset(&sa.sa_mask); // don't block other signals in handler
55+
sa.sa_flags = 0; // don't restart system calls
56+
return sigaction(signo, &sa, NULL);
57+
}
58+
59+
#endif

shell1/manyfork.c

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include "helpers.h"
2+
3+
int main(void) {
4+
int nprocesses = 10000;
5+
double start_time = timestamp();
6+
for (int i = 0; i != nprocesses; ++i) {
7+
pid_t p1 = fork();
8+
assert(p1 >= 0);
9+
if (p1 == 0)
10+
exit(0);
11+
}
12+
double delta = timestamp() - start_time;
13+
printf("%d processes in %g sec (%g proc/sec)\n", nprocesses,
14+
delta, nprocesses / delta);
15+
}

shell1/pipedemo.c

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include "helpers.h"
2+
3+
int main(void) {
4+
int pipefd[2];
5+
int r = pipe(pipefd);
6+
if (r < 0) {
7+
fprintf(stderr, "pipe: %s\n", strerror(errno));
8+
// or, shorter: `perror("pipe");`
9+
exit(1);
10+
}
11+
12+
pid_t p1 = fork();
13+
assert(p1 >= 0);
14+
15+
if (p1 == 0) {
16+
const char* buf = "Hello from your child!\n";
17+
ssize_t nw = write(pipefd[1], buf, strlen(buf));
18+
assert(nw == (ssize_t) strlen(buf));
19+
exit(0);
20+
}
21+
22+
FILE* f = fdopen(pipefd[0], "r");
23+
close(pipefd[1]);
24+
while (!feof(f)) {
25+
char buf[BUFSIZ];
26+
if (fgets(buf, BUFSIZ, f) != NULL)
27+
fprintf(stderr, "pipe says: %s\n", buf);
28+
}
29+
fprintf(stderr, "pipe closed\n");
30+
fclose(f);
31+
}

shell1/pipesizer.c

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include "helpers.h"
2+
3+
int main(void) {
4+
int pipefd[2];
5+
int r = pipe(pipefd);
6+
assert(r >= 0);
7+
8+
size_t x = 0;
9+
while (1) {
10+
ssize_t nr = write(pipefd[1], "!", 1);
11+
assert(nr == 1);
12+
++x;
13+
printf("%zu\n", x);
14+
}
15+
}

shell1/primesieve.c

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include "helpers.h"
2+
3+
int main(void) {
4+
char primebuf[1024];
5+
primebuf[0] = 0;
6+
7+
// sieve of Eratosthenes
8+
while (1) {
9+
// create next child
10+
int pipefd[2];
11+
int r = pipe(pipefd);
12+
assert(r >= 0);
13+
14+
pid_t pid = fork();
15+
assert(pid >= 0);
16+
17+
// run child
18+
if (pid == 0) {
19+
close(pipefd[0]);
20+
dup2(pipefd[1], STDOUT_FILENO);
21+
close(pipefd[1]);
22+
23+
if (strcmp(primebuf, "") == 0) {
24+
// first child: print all numbers starting from 2
25+
char* argv[] = { "seq", "2", "1000000", NULL };
26+
execvp(argv[0], argv);
27+
} else {
28+
// later children: filter multiples of last prime
29+
char* argv[] = { "./filtermultiples", primebuf, NULL };
30+
execv(argv[0], argv);
31+
}
32+
33+
assert(0);
34+
}
35+
36+
// set standard input to read from child
37+
close(pipefd[1]);
38+
dup2(pipefd[0], STDIN_FILENO);
39+
close(pipefd[0]);
40+
41+
// read next prime from standard input
42+
char* buf = primebuf;
43+
ssize_t nread;
44+
while ((nread = read(STDIN_FILENO, buf, 1)) == 1
45+
&& isdigit((unsigned char) *buf))
46+
++buf;
47+
if (nread != 1 || *buf != '\n')
48+
exit(0);
49+
*buf = 0;
50+
51+
// print prime
52+
printf("%s\n", primebuf);
53+
}
54+
}

0 commit comments

Comments
 (0)