309 lines
9.9 KiB
C
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
|
|
|
|
}
|