feat: assignment 3

This commit is contained in:
Kiana Sheibani 2025-11-01 22:14:35 -04:00
parent 06fbd2d6ad
commit 3cc3f6332d
Signed by: toki
GPG key ID: 6CB106C25E86A9F7
7 changed files with 281 additions and 0 deletions

21
assignment3/default.nix Normal file
View file

@ -0,0 +1,21 @@
let
basicC = subdir: name: { stdenv }:
stdenv.mkDerivation {
inherit name;
src = ./.;
buildPhase = ''
runHook preBuild
gcc ${subdir}/${name}.c -o ${name}.bin -pthread -lrt
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir -p $out/bin
install ${name}.bin $out/bin/${name}
runHook postInstall
'';
};
in {
a3-producer = basicC "src" "producer";
a3-consumer = basicC "src" "consumer";
}

22
assignment3/src/buffer.h Normal file
View file

@ -0,0 +1,22 @@
#ifndef BUFFER_H_
#define BUFFER_H_
#define BUFFER_SIZE 10
#define SHM_KEY 0x1234
#define SEM_MUTEX "/sem_mutex"
#define SEM_EMPTY "/sem_empty"
#define SEM_FULL "/sem_full"
typedef struct item_t {
int value; // Data value
int producer_id; // Which producer created this
} item_t;
typedef struct shared_buffer_t {
item_t buffer[BUFFER_SIZE];
int head; // Next write position
int tail; // Next read position
int count; // Current items in buffer
} shared_buffer_t;
#endif // BUFFER_H_

View file

@ -0,0 +1,91 @@
#include "buffer.h"
#include <fcntl.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <unistd.h>
shared_buffer_t *buffer = NULL;
sem_t *mutex = NULL;
sem_t *empty = NULL;
sem_t *full = NULL;
int shm_id = -1;
void cleanup() {
// Detach shared memory
if (buffer != NULL) {
shmdt(buffer);
}
// Close semaphores (don't unlink - other processes may be using)
if (mutex != SEM_FAILED)
sem_close(mutex);
if (empty != SEM_FAILED)
sem_close(empty);
if (full != SEM_FAILED)
sem_close(full);
}
void signal_handler(int sig) {
printf("\nProducer: Caught signal %d, cleaning up...\n", sig);
cleanup();
exit(2);
}
int main(int argc, char *argv[]) {
// Argument parsing
if (argc != 3) {
printf("Usage: %s <id> <number of msgs>\n", argv[0]);
return 1;
}
int id = atoi(argv[1]);
int num_items = atoi(argv[2]);
// Setup shared memory
shm_id = shmget(SHM_KEY, sizeof(shared_buffer_t), IPC_CREAT | 0666);
if (shm_id < 0) {
perror("shmget-failed");
return 1;
}
buffer = (shared_buffer_t *)shmat(shm_id, NULL, 0);
if (buffer == (void *)-1) {
perror("shmat-failed");
return 1;
}
// Open semaphores
mutex = sem_open(SEM_MUTEX, 0, 0644, 1);
empty = sem_open(SEM_EMPTY, 0, 0644, BUFFER_SIZE);
full = sem_open(SEM_FULL, 0, 0644, 0);
if (mutex == SEM_FAILED || empty == SEM_FAILED || full == SEM_FAILED) {
perror("sem_open-failed");
return 1;
}
// Primary logic
for (int i = 0; i < num_items; i++) {
sem_wait(full); // Wait for item
sem_wait(mutex); // Enter critical section
// Remove from buffer
item_t item = buffer->buffer[buffer->tail];
buffer->tail = (buffer->tail + 1) % BUFFER_SIZE;
buffer->count--;
printf("Consumer %d: Consumed value %d from Producer %d\n", id, item.value,
item.producer_id);
sem_post(mutex); // Exit critical section
sem_post(empty); // Signal slot available
usleep(rand() % 100000); // Simulate work
}
// Cleanup
printf("Consumer %d: Finished consuming %d items\n", id, num_items);
cleanup();
return 0;
}

View file

@ -0,0 +1,99 @@
#include "buffer.h"
#include <fcntl.h>
#include <semaphore.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <time.h>
#include <unistd.h>
shared_buffer_t *buffer = NULL;
sem_t *mutex = NULL;
sem_t *empty = NULL;
sem_t *full = NULL;
int shm_id = -1;
void cleanup() {
// Detach shared memory
if (buffer != NULL) {
shmdt(buffer);
}
// Close semaphores (don't unlink - other processes may be using)
if (mutex != SEM_FAILED)
sem_close(mutex);
if (empty != SEM_FAILED)
sem_close(empty);
if (full != SEM_FAILED)
sem_close(full);
}
void signal_handler(int sig) {
printf("\nProducer: Caught signal %d, cleaning up...\n", sig);
cleanup();
exit(2);
}
int main(int argc, char *argv[]) {
// Argument parsing
if (argc != 3) {
printf("Usage: %s <id> <number of msgs>\n", argv[0]);
return 1;
}
int id = atoi(argv[1]);
int num_items = atoi(argv[2]);
// Signal handlers
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
// Setup shared memory
shm_id = shmget(SHM_KEY, sizeof(shared_buffer_t), IPC_CREAT | 0666);
if (shm_id < 0) {
perror("shmget-failed");
return 1;
}
buffer = (shared_buffer_t *)shmat(shm_id, NULL, 0);
if (buffer == (void *)-1) {
perror("shmat-failed");
return 1;
}
// Open semaphores
mutex = sem_open(SEM_MUTEX, O_CREAT, 0644, 1);
empty = sem_open(SEM_EMPTY, O_CREAT, 0644, BUFFER_SIZE);
full = sem_open(SEM_FULL, O_CREAT, 0644, 0);
if (mutex == SEM_FAILED || empty == SEM_FAILED || full == SEM_FAILED) {
perror("sem_open-failed");
return 1;
}
// Primary logic
unsigned int seed = time(NULL) + id;
for (int i = 0; i < num_items; i++) {
item_t item = {.producer_id = id, .value = rand_r(&seed) % 1000};
sem_wait(empty); // Wait for empty slot
sem_wait(mutex); // Enter critical section
// Add to buffer
buffer->buffer[buffer->head] = item;
buffer->head = (buffer->head + 1) % BUFFER_SIZE;
buffer->count++;
printf("Producer %d: Produced value %d\n", id, item.value);
sem_post(mutex); // Exit critical section
sem_post(full); // Signal item available
usleep(rand_r(&seed) % 100000); // Simulate work
}
// Cleanup
printf("Producer %d: Finished producing %d items\n", id, num_items);
cleanup();
return 0;
}

38
assignment3/test Executable file
View file

@ -0,0 +1,38 @@
#!/usr/bin/env bash
echo "Building executables..."
cd "${FLAKE:-$(dirname $0)}"
if command -v nix; then
producer="$(nix build --no-link --print-out-paths .#a3-producer)/bin/producer"
consumer="$(nix build --no-link --print-out-paths .#a3-consumer)/bin/consumer"
else
mkdir build
gcc src/producer.c -o build/producer -pthread -lrt
gcc src/consumer.c -o build/consumer -pthread -lrt
producer="./build/producer"
consumer="./build/consumer"
fi
echo -e "\nTEST - Basic Functionality"
"${producer}" 1 5 &
"${consumer}" 1 5 &
wait
echo -e "\nTEST - Multiple Producers"
"${producer}" 1 10 &
"${producer}" 2 10 &
"${producer}" 3 10 &
"${consumer}" 1 30 &
wait
echo -e "\nTEST - Multiple Consumers"
"${producer}" 1 20 &
"${consumer}" 1 10 &
"${consumer}" 2 10 &
wait
# Cleanup
ipcrm -M 0x1234
rm /dev/shm/sem*
rm -rf build

9
assignment3/test.nix Normal file
View file

@ -0,0 +1,9 @@
{
a3 = { runCommandLocal, makeWrapper }:
runCommandLocal "a3-test" { nativeBuildInputs = [ makeWrapper ]; }
''
mkdir -p $out/bin
install ${./test} $out/bin/a3-test
wrapProgram "$out/bin/a3-test" --set FLAKE ${../.}
'';
}

View file

@ -11,6 +11,7 @@
subdirs = [
"assignment1"
"assignment2"
"assignment3"
"project1"
"project2"
];