Projects/1BIT/summer-semester/IOS-2/proj2.c
2026-04-14 19:28:46 +02:00

309 lines
9.9 KiB
C

//Autor: Roman Necas
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
// Macros for memory mapping
#define MMAP(ptr) {(ptr) = mmap(NULL, sizeof(*(ptr)), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);}
#define UNMAP(ptr) {munmap((ptr), sizeof(*(ptr)));}
// Shared memory variables
int *order = NULL; // Order of execution for print statements
int *bus_stop; // Array to store bus stop IDs for each skier
// Semaphores
sem_t *sem_mutex = NULL; // Mutex semaphore for critical sections
sem_t *sem_boarded = NULL; // Semaphore for skiers boarding the bus
sem_t *sem_order = NULL; // Semaphore for print order
sem_t *sem_ubus = NULL; // Semaphore for skiers unboarding the bus
sem_t *sem_unboard = NULL; // Semaphore for skiers unboarding the bus
sem_t **sem_busstops = NULL; // Array of semaphores for each bus stop
FILE *output; // File pointer for output
// Function prototypes
void bus_loop(int Z, int K, int TB, int L);
void skier_loop(int idL, int idZ, int TL);
int main(int argc, char* argv[]) {
// Check for correct number of arguments
if (argc != 6) {
fprintf(stderr, "Usage: %s L Z K TL TB\n", argv[0]);
return 1;
}
// Parse command-line arguments
int L = atoi(argv[1]); // Number of skiers
int Z = atoi(argv[2]); // Number of bus stops
int K = atoi(argv[3]); // Maximum skiers on the bus
int TL = atoi(argv[4]); // Maximum time for a skier to reach the bus stop
int TB = atoi(argv[5]); // Maximum time for the bus to travel between stops
// Validate argument values
if (L < 0 || L >= 20000 || Z <= 0 || Z > 10 || K < 10 || K > 100 || TL < 0 || TL > 10000 || TB < 0 || TB > 1000) {
fprintf(stderr, "Invalid arguments\n");
return 1;
}
output = fopen("proj2.out", "w");
// Memory mapping for shared variables
MMAP(order);
bus_stop = mmap(NULL, sizeof(*bus_stop) * L, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
for (int i = 0; i < L; i++) {
bus_stop[i] = 0; // Initialize bus stop array
}
*order = 1; // Initialize order
// Create semaphores
if (( sem_mutex = sem_open("/xnecasr00_sem_mutex", O_CREAT | O_EXCL, 0666, 1)) == SEM_FAILED) {
fprintf(stderr, "Error: Opening sem_mutex failed.\n");
return 1;
}
if ((sem_boarded = sem_open("/xnecasr00_sem_boarded", O_CREAT | O_EXCL, 0666, 0)) == SEM_FAILED) {
fprintf(stderr, "Error: Opening sem_boarded failed.\n");
return 1;
}
if ((sem_order = sem_open("/xnecasr00_sem_order", O_CREAT | O_EXCL, 0666, 1)) == SEM_FAILED) {
fprintf(stderr, "Error: Opening sem_order failed.\n");
return 1;
}
if ((sem_ubus = sem_open("/xnecasr00_sem_ubus", O_CREAT | O_EXCL, 0666, 0)) == SEM_FAILED) {
fprintf(stderr, "Error: Opening sem_ubus failed.\n");
return 1;
}
if ((sem_unboard = sem_open("/xnecasr00_sem_unboard", O_CREAT | O_EXCL, 0666, 0)) == SEM_FAILED) {
fprintf(stderr, "Error: Opening sem_unboard failed.\n");
return 1;
}
// Create semaphores for each bus stop
MMAP(sem_busstops);
for (int i = 0; i < Z; i++) {
char sem_name[35];
snprintf(sem_name, sizeof(sem_name), "/xnecasr00_sem_busstop_%d", i + 1);
if ((sem_busstops[i] = sem_open(sem_name, O_CREAT | O_EXCL, 0666, 0)) == SEM_FAILED) {
fprintf(stderr, "Error: Opening semaphore %s failed.\n", sem_name);
return 1;
}
}
// Fork for bus process
pid_t bus_pid = fork();
if (bus_pid == -1) {
perror("fork");
return 1;
} else if (bus_pid == 0) {
bus_loop(Z, K, TB, L);
exit(0);
}
// Fork for skier processes
for (int i = 1; i <= L; i++) {
pid_t skier_pid = fork();
if (skier_pid == -1) {
perror("fork");
return 1;
} else if (skier_pid == 0) {
srand(time(0) * getpid());
int idZ = rand() % Z + 1; // Randomly assign bus stop ID
skier_loop(i, idZ, TL);
exit(0);
}
}
// Wait for all child processes to finish
for (int i = 0; i <= L; i++) {
wait(NULL);
}
// Clean up shared memory and semaphores
UNMAP(order);
munmap(bus_stop, sizeof(*bus_stop)*L);
sem_close(sem_mutex);
sem_unlink("/xnecasr00_sem_mutex");
sem_close(sem_boarded);
sem_unlink("/xnecasr00_sem_boarded");
sem_close(sem_order);
sem_unlink("/xnecasr00_sem_order");
sem_close(sem_ubus);
sem_unlink("/xnecasr00_sem_ubus");
sem_close(sem_unboard);
sem_unlink("/xnecasr00_sem_unboard");
// Close and unlink semaphores for each bus stop
for (int i = 0; i < Z; i++) {
char sem_name[35];
snprintf(sem_name, sizeof(sem_name), "/xnecasr00_sem_busstop_%d", i + 1);
sem_close(sem_busstops[i]);
sem_unlink(sem_name);
}
fclose(output);
return 0;
}
void bus_loop(int Z, int K, int TB, int L) {
srand(time(0) * getpid());
// Print bus started
sem_wait(sem_order);
setbuf(output, NULL);
fprintf(output, "%d: BUS: started\n", *order);
*order += 1;
sem_post(sem_order);
int boarded = 0; // Number of skiers on the bus
int idZ = 1; // Current bus stop ID
int skiing = 0;
while (1) {
// Sleep for a random time before arriving at the next stop
usleep(rand() % (TB + 1));
// Print bus arrival at the current stop
sem_wait(sem_order);
setbuf(output, NULL);
fprintf(output, "%d: BUS: arrived to %d\n",*order, idZ);
*order += 1;
sem_post(sem_order);
// Board skiers waiting at the current stop
sem_wait(sem_mutex);
int waiting_at_stop = 0;
for (int i = 0; i < L; i++) {
if ((bus_stop[i] == idZ) && waiting_at_stop < K) {
bus_stop[i] = 0; // Reset bus stop ID for skiers who boarded
waiting_at_stop++;
sem_post(sem_busstops[idZ - 1]); // Signal skiers at the current stop to board
sem_wait(sem_boarded); // Wait for skiers to board
}
}
boarded += waiting_at_stop; // Increment the number of skiers on the bus
sem_post(sem_mutex);
// Print bus leaving the current stop
sem_wait(sem_order);
setbuf(output, NULL);
fprintf(output, "%d: BUS: leaving %d\n",*order, idZ);
*order += 1;
sem_post(sem_order);
// If the bus has reached the final stop
if (idZ == Z) {
usleep(rand() % (TB + 1)); // Sleep for a random time before arriving at the final stop
// Print bus arrival at the final stop
sem_wait(sem_order);
setbuf(output, NULL);
fprintf(output, "%d: BUS: arrived to final\n", *order);
*order += 1;
sem_post(sem_order);
// Unboard skiers at the final stop
for (int i = 0; i < boarded; i++) {
sem_post(sem_ubus); // Signal skiers to unboard
sem_wait(sem_unboard); // Wait for skiers to unboard
skiing++;
}
// Print bus leaving the final stop
sem_wait(sem_order);
setbuf(output, NULL);
fprintf(output, "%d: BUS: leaving final\n", *order);
*order += 1;
sem_post(sem_order);
idZ = 1; // Reset bus stop ID to the first stop
boarded = 0; // Reset the number of skiers on the bus
sem_wait(sem_mutex);
// Check if there are any remaining skiers at the bus stops
int remaining = 0;
for (int i = 0; i < L; i++) {
if (bus_stop[i] != 0) {
remaining++;
}
}
sem_post(sem_mutex);
// If there are no remaining skiers, print finish and exit the loop
if (remaining == 0 && skiing == L) {
sem_wait(sem_order);
setbuf(output, NULL);
fprintf(output, "%d: BUS: finish\n", *order);
*order += 1;
sem_post(sem_order);
break;
}
} else {
idZ++; // Move to the next bus stop
}
}
}
void skier_loop(int idL, int idZ, int TL) {
srand(time(0) * getpid());
// Print skier started
sem_wait(sem_order);
setbuf(output, NULL);
fprintf(output, "%d: L %d: started\n",*order, idL);
*order += 1;
sem_post(sem_order);
// Sleep for a random time before arriving at the bus stop
usleep(rand() % (TL + 1));
// Print skier arrival at the bus stop
sem_wait(sem_order);
setbuf(output, NULL);
fprintf(output, "%d: L %d: arrived to %d\n",*order, idL, idZ);
*order += 1;
sem_post(sem_order);
// Store the skier's bus stop ID and increment the waiting count
sem_wait(sem_mutex);
bus_stop[idL - 1] = idZ;
sem_post(sem_mutex);
// Wait for the bus to arrive at the skier's bus stop
sem_wait(sem_busstops[idZ - 1]);
// Print skier boarding the bus
sem_wait(sem_order);
setbuf(output, NULL);
fprintf(output, "%d: L %d: boarding\n",*order, idL);
*order += 1;
sem_post(sem_order);
sem_post(sem_boarded); // Signal that the skier has boarded
// Wait for the bus to reach the final stop
sem_wait(sem_ubus);
// Print skier going to ski
sem_wait(sem_order);
setbuf(output, NULL);
fprintf(output, "%d: L %d: going to ski\n",*order, idL);
*order += 1;
sem_post(sem_order);
sem_post(sem_unboard); // Signal that the skier has unboarded
}