Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions pipes/ping-pong/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
SHELL:=/usr/bin/env bash

CC = gcc
CFLAGS =
LDFLAGS =

pipong: pipong.c
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)

clean:
rm -f pipong
131 changes: 131 additions & 0 deletions pipes/ping-pong/pipong.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

/*
* pipong is a program that uses UNIX system calls to “ping-pong” a byte between
* two processes over a pair of pipes, one for each direction. Measure the
* program’s performance, in ex- changes per second.
*
* it's an exercise from:
* <https://pdos.csail.mit.edu/6.1810/2024/xv6/book-riscv-rev4.pdf>
* */


//struct pp_child {
// int out_fd[2];
// int in[2];
// int result_pipe_fd[2];
//};

/*
* this is one side of the pingpong game, it
* out -> end of the pipe to write output (fd)
* */
void timed_pingpong(float delayInSeconds, int in_fd, int out_fd, int result_fd) {
time_t startTime;
time_t now;
float elapsedTime = 0;
float setTime = delayInSeconds;

char c;
int count = 0;

time(&startTime);
while (elapsedTime < setTime) {
if (read(in_fd, &c, 1) != 1) /* read 1 byte from in_fd (ping) */
break;
write(out_fd, &c, 1); /* write 1 byte to out_fd (pong) */
count++;
now = time(NULL);
elapsedTime = difftime(now, startTime);
}
// write the total number of bytes written
write(result_fd, &count, sizeof(count));
close(result_fd);
}

int main(int argc, char *argv[])
{
pid_t c1, c2;

// pipe descriptors
int p2c[2]; /* parent to child */
int up[2];
int down[2];
int r1[2], r2[2];

if ((pipe(up) == -1) || (pipe(down)) ||
(pipe(r1) == -1) || (pipe(r2))) {
perror("pipe");
exit(EXIT_FAILURE);
}

// internal buffers for children
char buf1, buf2;

// counters for checking how many bytes are written
int counter = 0;

if (argc != 3) {
fprintf(stderr, "Usage: %s <string> <runtime (sec)>\n", argv[0]);
exit(EXIT_FAILURE);
}

/* could add check here to make sure arv[1] is only a single byte */
/* but maybe it's easier to always just play with one byte */

float delay_sec = atof(argv[2]);

if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) {
perror("signal");
exit(EXIT_FAILURE);
}
/* spawn two child processes */
c1 = fork();
if (c1 == -1) {
perror("fork");
}
if (c1 == 0) {
// close fds that we don't need here
close(down[1]);
close(up[0]);
close(r1[0]);
// read down stdin, write up stdout
timed_pingpong(delay_sec, down[0], up[1], r1[1]);
exit(0);
}


c2 = fork();
if (c2 == -1) {
perror("fork");
}
if (c2 == 0) {
// close unneeded fds
close(up[1]);
close(down[0]);
close(r2[0]);
// read up stdin, write down stdout
timed_pingpong(delay_sec, up[0], down[1], r2[1]);
exit(0);
}

/* Parent writes the initial byte from argv[1] to up_pipe */
write(up[1], argv[1], 1);

long c1_count = 0, c2_count = 0;
read(r1[0], &c1_count, sizeof(c1_count));
read(r2[0], &c2_count, sizeof(c2_count));

waitpid(c1, NULL, 0);
waitpid(c2, NULL, 0);

printf("Child 1: %ld, child 2: %ld bytes in %.2f seconds\n", c1_count, c2_count, delay_sec);
exit(EXIT_SUCCESS);
}
17 changes: 17 additions & 0 deletions pipes/ping-pong/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# ping pong with pipes

Note to self... remember to fix the hole in your pipe!

Two child processes talk to each other via a set of pipes, ping-ponging
a byte back and fourth. The program measures how many times the byte is
transferred between processes in a time interval specified by the user.

```
+->ifd > [ c1 ] > ofd->--|
| +-------<-----+
+----<-----|---<------+--+
+-----<----+ |
| |
+-> ifd > [ c2 ] > ofd --+

```
2 changes: 2 additions & 0 deletions pipes/ping-pong/result.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Child 1 21172600 bytes in 100.00 seconds
Child 2 21172601 bytes in 100.00 seconds
24 changes: 24 additions & 0 deletions pipes/ping-pong/scripts/benchmark.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/sh

if [ "$#" -ne 1 ]; then
echo "usage: ${BASH_SOURCE[0]} <location>"
exit 1
fi
LOCATION="$1"

echo "running on ${LOCATION} - pipong will transfer a byte back and forth between two processes via a set of pipes..."

count=0
total=0
for sec in 1.0 2.0 4.0 8.0 16.0 32.0;
do
run=$(./pipong A "$sec" | awk '{tot = $3 + $6} END {print tot / $9}' )
total=$((total + run))
count=$((count+1))
done


# Average
result=$((total / count))
printf "no of bytes transferred: %s (b/sec) \n" "$result"

22 changes: 22 additions & 0 deletions pipes/ping-pong/scripts/pingpong_a.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/sh

# two named pipes
if [ ! -f p1 ]; then
mkfifo p1
fi
if [ ! -f p2 ]; then
mkfifo p2
fi

# proc A
while true;
do
while IFS= read -r msg;
do
echo "$msg"
if [ "$msg" == "pong" ]; then
echo ping > ./p2
sleep 1
fi
done <<<$(cat ./p1)
done
14 changes: 14 additions & 0 deletions pipes/ping-pong/scripts/pingpong_b.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/sh

# proc B
while true;
do
while IFS= read -r msg;
do
echo "$msg"
if [ "$msg" == "ping" ]; then
echo pong > ./p1
sleep 1
fi
done <<<$(cat ./p2)
done
20 changes: 20 additions & 0 deletions pipes/ping-pong/scripts/repl.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/bash

PID=""

while inotifywait -q ./pipong.c; do
echo -e "\n\n"

# If a previous instance is running, kill it
if [[ -n "$PID" ]] && kill -0 "$PID" 2>/dev/null; then
echo "Killing running instance ($PID)…"
kill "$PID"
wait "$PID" 2>/dev/null
fi

echo "Starting new instance…"
make clean && make
./pipong A &
PID=$!
done

24 changes: 24 additions & 0 deletions pipes/ping-pong/scripts/single.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env bash

player1 () {
while true
do read n
if "$n" == "ping"; then
echo pong > fifo2
fi
done <<<$(cat fifo1)
}

player2 () {
while true
do read n
if "$n" == "pong"; then
echo ping > fifo1
fi
done <<<$(cat fifo2)
}

mkfifo fifo1
mkfifo fifo2

(echo "ping" > fifo1; (player1; player2))