//Autor: Roman Necas #include #include #include #include #include #include #include #include #include #include #include #include // 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 }