Skip to content

Instantly share code, notes, and snippets.

@spacelatte
Last active July 25, 2020 14:23
Show Gist options
  • Save spacelatte/6638d93517bb825dc5ef4cc4e37856d5 to your computer and use it in GitHub Desktop.
Save spacelatte/6638d93517bb825dc5ef4cc4e37856d5 to your computer and use it in GitHub Desktop.
send & receive #pipe pair example in #c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
#include "pipe.h"
typedef struct PidPair {
pid_t reader;
pid_t writer;
} pid_pair_t;
void
sleeper(long id, pipe_t *chan) {
srandomdev();
long period = 1000L + random()%9000L;
char buf[80]; sprintf(buf, "%3ld: sleeping for %ld...", id, period);
pipe_send(chan, buf);
usleep(1000L * period);
return;
}
void handler(int sig) {
fprintf(stderr, "Got %d, exiting... (%d)\n", sig, getpid());
return exit(0);
}
pid_t
main_worker(long id, pipe_t *channel, const char *expr) {
pid_t pid = fork();
if(pid) return pid;
signal(SIGTERM, handler);
signal(SIGINT, handler);
char buf[80];
snprintf(buf, sizeof(buf), "%3ld: calculating: '%s'...", id, expr);
pipe_send(channel, buf);
sleeper(id, channel);
srandomdev();
char res[80];
snprintf(res, sizeof(res), "%3ld: random result for ya: %ld", id, random());
pipe_send(channel, res);
//char *resp = calloc(PIPE_PACKET_SIZE, sizeof(char));
//pipe_recv(channel, &resp);
//fprintf(stdout, "%3ld: recv: '%s'\n", id, resp);
//free(resp);
//sleeper(id, channel);
kill(getppid(), SIGUSR1);
close(channel->io.write);
close(channel->io.read);
return (-id);
}
pid_t
main_decoder(long id, pipe_t *chan) {
pid_t pid = fork();
if(pid) return pid;
signal(SIGPIPE, handler);
while(chan && chan->io.read) {
char *buf = calloc(PIPE_PACKET_SIZE, sizeof(char));
pipe_recv(chan, &buf);
printf("%3ld: recv: '%s'\n", id, buf);
free(buf);
//pipe_send(chan, "got your message bro!");
usleep(1000L);
continue;
}
return (-pid);
}
pid_pair_t
main_program(const char *arg) {
static long monotonic_counter;
pipe_t *pipefd = NULL;
pid_pair_t pair;
monotonic_counter += 1;
if(!pipefd) {
pipefd = malloc(sizeof(pipe_t));
pipe(pipefd->rawfd);
}
pair.reader = main_decoder(monotonic_counter, pipefd);
pair.writer = main_worker(monotonic_counter, pipefd, arg);
return pair;
}
void main_signal_handler(int sig) {
fprintf(stderr, "main-sig: %d\n", sig);
return;
}
int
main(int argc, char const **argv) {
pid_pair_t pairs[argc];
srandomdev();
signal(SIGUSR1, main_signal_handler);
signal(SIGUSR2, main_signal_handler);
//signal(SIGTERM, main_signal_handler);
//signal(SIGCHLD, main_signal_handler);
//signal(SIGPIPE, main_signal_handler);
//signal(SIGINT, main_signal_handler);
for(int i=0; i<argc; i++) {
pid_pair_t child = main_program(argv[i]);
if(child.reader < 0 || child.writer < 0) {
exit(0); break;
}
//fprintf(stderr, "> read:%8d write:%8d\n", child.reader, child.writer);
pairs[i] = child;
continue;
}
fprintf(stderr, "Spawning killer...\n");
pid_t killer = fork();
if(!killer) { // killer kills all processes after timeout
signal(SIGINT, exit);
sleep(11);
fprintf(stderr, "Timeout Reached! Interrupting!\n");
for(int i=0; i<argc; i++) {
kill(pairs[i].reader, SIGINT);
kill(pairs[i].writer, SIGINT);
continue;
}
return 0;
}
for(int i=0; i<argc; i++) waitpid(pairs[i].writer, NULL, 0);
fprintf(stderr, "Program done, killing killer...\n");
kill(killer, SIGINT); // ok, kill the killer :)
return 0;
}
#!/usr/bin/env make -f
CC = cc
LD = ld
CFLAGS = -g -O0
LDFLAGS = -lSystem -arch x86_64 -macosx_version_min 10.9
MODULES = $(addsuffix .o, pipe main)
TARGET = main.exe
all: $(TARGET)
./$(TARGET) hello world some parameters hell yeah
clean:
rm -f $(MODULES) $(TARGET)
$(TARGET): $(MODULES)
$(LD) $(LDFLAGS) -o $@ $^
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $^
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "pipe.h"
static unsigned long pipe_monotonic_counter;
ssize_t
pipe_send(pipe_t *chan, const char *msg) {
data_t data;
data.id = pipe_monotonic_counter++;
data.length = strlen(msg);
strncpy(data.buffer, msg, PIPE_PACKET_SIZE);
return write(chan->io.write, &data, sizeof(data));
}
ssize_t
pipe_recv(pipe_t *chan, char **buffer) {
data_t data;
ssize_t result = read(chan->io.read, &data, sizeof(data));
if(!buffer || !*buffer) {
*buffer = realloc(*buffer, PIPE_PACKET_SIZE);
}
strncpy(*buffer, data.buffer, PIPE_PACKET_SIZE);
return result;
}
#ifndef _PIPE_H_
#define _PIPE_H_
#include <stdint.h>
#include <unistd.h>
#define PIPE_PACKET_SIZE 128
typedef union Pipe {
int rawfd[2];
struct PipeIO {
int read;
int write;
} io;
} pipe_t;
typedef struct Data {
uint32_t id;
uint32_t length;
char buffer[PIPE_PACKET_SIZE];
} data_t;
ssize_t pipe_send(pipe_t *, const char *);
ssize_t pipe_recv(pipe_t *, char **);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment