From 85ca7ed1d367e31c5868473ab723b39fa6f778b9 Mon Sep 17 00:00:00 2001 From: Yurii Korolkov Date: Mon, 15 Jun 2026 13:50:35 +0300 Subject: [PATCH 1/8] refactor: create IPC token file at runtime --- .gitignore | 9 ++++++ keys/keyAccessBuyingBoard.txt | 0 keys/keyAccessProducts.txt | 0 keys/keyLockWritersBuyingBoard.txt | 0 keys/keyLockWritersProducts.txt | 0 keys/keyOrderBuyingBoard.txt | 0 keys/keyOrderProducts.txt | 0 keys/keyReadersBuyingBoard.txt | 0 keys/keyReadersProducts.txt | 0 keys/keyShMemBuyingBoard.txt | 0 keys/keyShMemCountBoards.txt | 0 keys/keyShMemProducts.txt | 0 shop_simulator.c | 49 ++++++++++++++++++++++-------- 13 files changed, 45 insertions(+), 13 deletions(-) create mode 100644 .gitignore delete mode 100644 keys/keyAccessBuyingBoard.txt delete mode 100644 keys/keyAccessProducts.txt delete mode 100644 keys/keyLockWritersBuyingBoard.txt delete mode 100644 keys/keyLockWritersProducts.txt delete mode 100644 keys/keyOrderBuyingBoard.txt delete mode 100644 keys/keyOrderProducts.txt delete mode 100644 keys/keyReadersBuyingBoard.txt delete mode 100644 keys/keyReadersProducts.txt delete mode 100644 keys/keyShMemBuyingBoard.txt delete mode 100644 keys/keyShMemCountBoards.txt delete mode 100644 keys/keyShMemProducts.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f3634f6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# Local build output +shop-simulator +*.o + +# Runtime-generated IPC token +.runtime/ + +# Simulation output +simulation.log \ No newline at end of file diff --git a/keys/keyAccessBuyingBoard.txt b/keys/keyAccessBuyingBoard.txt deleted file mode 100644 index e69de29..0000000 diff --git a/keys/keyAccessProducts.txt b/keys/keyAccessProducts.txt deleted file mode 100644 index e69de29..0000000 diff --git a/keys/keyLockWritersBuyingBoard.txt b/keys/keyLockWritersBuyingBoard.txt deleted file mode 100644 index e69de29..0000000 diff --git a/keys/keyLockWritersProducts.txt b/keys/keyLockWritersProducts.txt deleted file mode 100644 index e69de29..0000000 diff --git a/keys/keyOrderBuyingBoard.txt b/keys/keyOrderBuyingBoard.txt deleted file mode 100644 index e69de29..0000000 diff --git a/keys/keyOrderProducts.txt b/keys/keyOrderProducts.txt deleted file mode 100644 index e69de29..0000000 diff --git a/keys/keyReadersBuyingBoard.txt b/keys/keyReadersBuyingBoard.txt deleted file mode 100644 index e69de29..0000000 diff --git a/keys/keyReadersProducts.txt b/keys/keyReadersProducts.txt deleted file mode 100644 index e69de29..0000000 diff --git a/keys/keyShMemBuyingBoard.txt b/keys/keyShMemBuyingBoard.txt deleted file mode 100644 index e69de29..0000000 diff --git a/keys/keyShMemCountBoards.txt b/keys/keyShMemCountBoards.txt deleted file mode 100644 index e69de29..0000000 diff --git a/keys/keyShMemProducts.txt b/keys/keyShMemProducts.txt deleted file mode 100644 index e69de29..0000000 diff --git a/shop_simulator.c b/shop_simulator.c index bcfbbf0..05b567d 100644 --- a/shop_simulator.c +++ b/shop_simulator.c @@ -12,8 +12,12 @@ #include #include #include -#include #include +#include +#include + +static const char *const IPC_RUNTIME_DIR = ".runtime"; +static const char *const IPC_TOKEN_FILE = ".runtime/ipc.token"; //======== Semaphores ================================================== key_t getKey(const char *pathname, int proj_id); @@ -164,6 +168,7 @@ void signalHandler(int sig) { } //======== Others ================================================= +void prepareIpcTokenFile(void); void increment(int *value); void decrement(int *value); int getRandomNum(int minNum, int maxNum); @@ -187,19 +192,21 @@ int main(int argc, char const *argv[]) { srand(time(NULL)); - // keys : - key_t keyShMemBuyingBoard = getKey("keys/keyShMemBuyingBoard.txt", 150); - key_t keyShMemCountBoards = getKey("keys/keyShMemCountBoards.txt", 151); - key_t keyAccessBuyingBoard = getKey("keys/keyAccessBuyingBoard.txt", 152); - key_t keyReadersBuyingBoard = getKey("keys/keyReadersBuyingBoard.txt", 153); - key_t keyOrderBuyingBoard = getKey("keys/keyOrderBuyingBoard.txt", 154); - key_t keyWritersBuyingBoard = getKey("keys/keyLockWritersBuyingBoard.txt", 155); + // Prepare the runtime file used to generate System V IPC keys. + prepareIpcTokenFile(); + + key_t keyShMemBuyingBoard = getKey(IPC_TOKEN_FILE, 150); + key_t keyShMemCountBoards = getKey(IPC_TOKEN_FILE, 151); + key_t keyAccessBuyingBoard = getKey(IPC_TOKEN_FILE, 152); + key_t keyReadersBuyingBoard = getKey(IPC_TOKEN_FILE, 153); + key_t keyOrderBuyingBoard = getKey(IPC_TOKEN_FILE, 154); + key_t keyWritersBuyingBoard = getKey(IPC_TOKEN_FILE, 155); - key_t keyProducts = getKey("keys/keyShMemProducts.txt", 160); - key_t keyAccessProducts = getKey("keys/keyAccessProducts.txt", 161); - key_t keyReadersProducts = getKey("keys/keyReadersProducts.txt", 162); - key_t keyOrderProducts = getKey("keys/keyOrderProducts.txt", 163); - key_t keyWritersProducts = getKey("keys/keyLockWritersProducts.txt", 164); + key_t keyProducts = getKey(IPC_TOKEN_FILE, 160); + key_t keyAccessProducts = getKey(IPC_TOKEN_FILE, 161); + key_t keyReadersProducts = getKey(IPC_TOKEN_FILE, 162); + key_t keyOrderProducts = getKey(IPC_TOKEN_FILE, 163); + key_t keyWritersProducts = getKey(IPC_TOKEN_FILE, 164); printf("\nProject info:\n\nCustomers : %2d persons\nSales Agent : %2d persons\nCount Products : %2d items\nSimulation time : %2d sec\n\n", countCustomers, countAgents, countProducts, simulationTime); @@ -1366,6 +1373,22 @@ void* thread_threadMakeDone(void* arg) { } //=========Others================================================== +void prepareIpcTokenFile(void) { + if (mkdir(IPC_RUNTIME_DIR, 0700) == -1 && errno != EEXIST) { + perror("Failed to create IPC runtime directory"); + exit(EXIT_FAILURE); + } + + int tokenFile = open(IPC_TOKEN_FILE, O_CREAT | O_RDWR, 0600); + + if (tokenFile == -1) { + perror("Failed to create IPC token file"); + exit(EXIT_FAILURE); + } + + close(tokenFile); +} + void increment(int* value) { (*value)++; } From 1ef225ce9dfadabe570159c807e937878a3942d1 Mon Sep 17 00:00:00 2001 From: Yurii Korolkov Date: Mon, 15 Jun 2026 15:37:00 +0300 Subject: [PATCH 2/8] fix: validate simulation configuration before spawning processes Validate parsed argument values and allocate child PID storage based on the final customer and sales agent counts. --- shop_simulator.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/shop_simulator.c b/shop_simulator.c index 05b567d..e7559aa 100644 --- a/shop_simulator.c +++ b/shop_simulator.c @@ -186,9 +186,38 @@ int main(int argc, char const *argv[]) { int countCustomers = 4; int countAgents = 2; int childCount = 0; - pid_t childPIDs[countCustomers + countAgents]; - readArguments(&countProducts, &countAgents, &countCustomers, argc, (char **)argv); + readArguments( + &countProducts, + &countAgents, + &countCustomers, + argc, + (char **)argv + ); + + if (countProducts < 1 || countProducts > 10) { + fprintf(stderr, "Product count must be between 1 and 10.\n"); + return EXIT_FAILURE; + } + + if (countAgents < 1) { + fprintf(stderr, "Sales agent count must be greater than zero.\n"); + return EXIT_FAILURE; + } + + if (countCustomers < 1) { + fprintf(stderr, "Customer count must be greater than zero.\n"); + return EXIT_FAILURE; + } + + size_t childCapacity = (size_t)countCustomers + (size_t)countAgents; + + pid_t *childPIDs = calloc(childCapacity, sizeof(*childPIDs)); + + if (childPIDs == NULL) { + perror("Failed to allocate child PID storage"); + return EXIT_FAILURE; + } srand(time(NULL)); @@ -743,6 +772,8 @@ int main(int argc, char const *argv[]) { removeSemaphore(semidOrderBuyingBoard, "rm_OrderBuyingBoard"); removeSemaphore(semidWritersBuyingBoard,"rm_WritersBuyingBoard"); + free(childPIDs); + return 0; } From 392c09162de28ff796106ded7bbd3630116588f6 Mon Sep 17 00:00:00 2001 From: Yurii Korolkov Date: Mon, 15 Jun 2026 16:53:34 +0300 Subject: [PATCH 3/8] fix: correct interprocess readers-writers synchronization Store reader and waiting-writer counters in shared memory. Use blocking System V semaphore operations, initialize semaphore values explicitly, and allow child processes to finish active operations before terminating. --- shop_simulator.c | 183 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 126 insertions(+), 57 deletions(-) diff --git a/shop_simulator.c b/shop_simulator.c index e7559aa..6f8603e 100644 --- a/shop_simulator.c +++ b/shop_simulator.c @@ -19,6 +19,14 @@ static const char *const IPC_RUNTIME_DIR = ".runtime"; static const char *const IPC_TOKEN_FILE = ".runtime/ipc.token"; +struct readersWritersState { + int buyingBoardReaders; + int buyingBoardWaitingWriters; + int productReaders; + int productWaitingWriters; +}; + + //======== Semaphores ================================================== key_t getKey(const char *pathname, int proj_id); int createSemaphore(key_t key, const char *semName); @@ -162,9 +170,8 @@ void* thread_threadMakeDone(void* arg); //======== Sygnal for subprocess ================================= volatile sig_atomic_t stop = 0; void signalHandler(int sig) { + (void)sig; stop = 1; - printf("Process %d received signal %d, terminating...\n", getpid(), sig); - exit(0); } //======== Others ================================================= @@ -200,12 +207,12 @@ int main(int argc, char const *argv[]) { return EXIT_FAILURE; } - if (countAgents < 1) { + if (countAgents < 1 || countAgents > 4) { fprintf(stderr, "Sales agent count must be greater than zero.\n"); return EXIT_FAILURE; } - if (countCustomers < 1) { + if (countCustomers < 1 || countCustomers > 10) { fprintf(stderr, "Customer count must be greater than zero.\n"); return EXIT_FAILURE; } @@ -237,6 +244,8 @@ int main(int argc, char const *argv[]) { key_t keyOrderProducts = getKey(IPC_TOKEN_FILE, 163); key_t keyWritersProducts = getKey(IPC_TOKEN_FILE, 164); + key_t keyReadersWritersState = getKey(IPC_TOKEN_FILE, 170); + printf("\nProject info:\n\nCustomers : %2d persons\nSales Agent : %2d persons\nCount Products : %2d items\nSimulation time : %2d sec\n\n", countCustomers, countAgents, countProducts, simulationTime); printf("Hello! I am the Manager or the \"Main Process\", my pid = %d\n", getpid()); @@ -291,21 +300,52 @@ int main(int argc, char const *argv[]) { memcpy(shared_memory_CountBoards, &countBoards, sizeof(int)); - // Semaphores : - int countReadersBuyingBoard = 0; - int countWritersBuyingBoard = 0; + int shmidReadersWritersState = shmget( + keyReadersWritersState, + sizeof(struct readersWritersState), + IPC_CREAT | 0666 + ); - int semidAccessBuyingBoard = createSemaphore(keyAccessBuyingBoard, "AccessBuyingBoard"); - unlock(semidAccessBuyingBoard, "AccessBuyingBoard"); + if (shmidReadersWritersState == -1) { + perror("shmget_create_ReadersWritersState"); + exit(EXIT_FAILURE); + } - int semidReadersBuyingBoard = createSemaphore(keyReadersBuyingBoard, "ReadersBuyingBoard"); - unlock(semidReadersBuyingBoard, "ReadersBuyingBoard"); + struct readersWritersState *shared_memory_ReadersWritersState = + (struct readersWritersState *)shmat( + shmidReadersWritersState, + NULL, + 0 + ); - int semidOrderBuyingBoard = createSemaphore(keyOrderBuyingBoard, "OrderBuyingBoard"); - unlock(semidOrderBuyingBoard, "OrderBuyingBoard"); + if (shared_memory_ReadersWritersState == (void *)-1) { + perror("shmat_ReadersWritersState"); + exit(EXIT_FAILURE); + } + + memset( + shared_memory_ReadersWritersState, + 0, + sizeof(*shared_memory_ReadersWritersState) + ); + + int *countReadersBuyingBoard = + &shared_memory_ReadersWritersState->buyingBoardReaders; + + int *countWritersBuyingBoard = + &shared_memory_ReadersWritersState->buyingBoardWaitingWriters; + int *countReadersProducts = + &shared_memory_ReadersWritersState->productReaders; + + int *countWritersProducts = + &shared_memory_ReadersWritersState->productWaitingWriters; + + // Semaphores : + int semidAccessBuyingBoard = createSemaphore(keyAccessBuyingBoard, "AccessBuyingBoard"); + int semidReadersBuyingBoard = createSemaphore(keyReadersBuyingBoard, "ReadersBuyingBoard"); + int semidOrderBuyingBoard = createSemaphore(keyOrderBuyingBoard, "OrderBuyingBoard"); int semidWritersBuyingBoard = createSemaphore(keyWritersBuyingBoard, "WritersBuyingBoard"); - unlock(semidWritersBuyingBoard, "WritersBuyingBoard"); //=========Products================================================== // Intialize : @@ -329,20 +369,10 @@ int main(int argc, char const *argv[]) { free(products); // Semaphores : - int countReadersProducts = 0; - int countWritersProducts = 0; - - int semidAccessProducts = createSemaphore(keyAccessProducts, "AccessProducts"); - unlock(semidAccessProducts, "AccessProducts"); - + int semidAccessProducts = createSemaphore(keyAccessProducts, "AccessProducts"); int semidReadersProducts = createSemaphore(keyReadersProducts, "ReadersProducts"); - unlock(semidReadersProducts, "ReadersProducts"); - - int semidOrderProducts = createSemaphore(keyOrderProducts, "OrderProducts"); - unlock(semidOrderProducts, "OrderProducts"); - + int semidOrderProducts = createSemaphore(keyOrderProducts, "OrderProducts"); int semidWritersProducts = createSemaphore(keyWritersProducts, "WritersProducts"); - unlock(semidWritersProducts, "WritersProducts"); //========Check shared memory===================================== @@ -410,8 +440,8 @@ int main(int argc, char const *argv[]) { request0->orderDeskription = "OrderProducts_readMenu"; request0->semidWriters = semidWritersProducts; request0->writersDeskription = "WritersProducts_readMenu"; - request0->countWriters = &countWritersProducts; - request0->countReaders = &countReadersProducts; + request0->countWriters = countWritersProducts; + request0->countReaders = countReadersProducts; request0->countProducts = &countProducts; request0->currentProducts = currentProducts; @@ -450,8 +480,8 @@ int main(int argc, char const *argv[]) { request1->orderDeskription = "OrderBuyingBoards_readBuyingBoards"; request1->semidWriters = semidWritersBuyingBoard; request1->writersDeskription = "WritersBuyingBoards_readBuyingBoards"; - request1->countWriters = &countWritersBuyingBoard; - request1->countReaders = &countReadersBuyingBoard; + request1->countWriters = countWritersBuyingBoard; + request1->countReaders = countReadersBuyingBoard; request1->countBoards = shared_memory_CountBoards; request1->currentCountBoards = ¤tCountBoards; @@ -511,7 +541,7 @@ int main(int argc, char const *argv[]) { request2->orderDeskription = "OrderBuyingBoards_addBuyingBoard"; request2->semidLockWriters = semidWritersBuyingBoard; request2->lockWritersDeskription = "LockWritersBuyingBoards_addBuyingBoard"; - request2->countWriters = &countWritersBuyingBoard; + request2->countWriters = countWritersBuyingBoard; request2->itemId = randomItem; request2->amountOrder = randomAmount; @@ -583,7 +613,7 @@ int main(int argc, char const *argv[]) { request0->orderDeskription = "OrderProducts_updateProducts"; request0->semidLockWriters = semidWritersProducts; request0->lockWritersDeskription = "LockWritersProducts_updateProducts"; - request0->countWriters = &countWritersProducts; + request0->countWriters = countWritersProducts; request0->countProducts = &countProducts; request0->itemId = notDoneItemId; @@ -621,8 +651,8 @@ int main(int argc, char const *argv[]) { request1->orderDeskription = "OrderBuyingBoards_readBuyingBoards"; request1->semidWriters = semidWritersBuyingBoard; request1->writersDeskription = "WritersBuyingBoards_readBuyingBoards"; - request1->countWriters = &countWritersBuyingBoard; - request1->countReaders = &countReadersBuyingBoard; + request1->countWriters = countWritersBuyingBoard; + request1->countReaders = countReadersBuyingBoard; request1->countBoards = shared_memory_CountBoards; request1->currentCountBoards = ¤tCountBoards; @@ -667,7 +697,7 @@ int main(int argc, char const *argv[]) { request2->orderDeskription = "OrderBuyingBoards_makeDone"; request2->semidLockWriters = semidWritersBuyingBoard; request2->lockWritersDeskription = "LockWritersBuyingBoards_makeDone"; - request2->countWriters = &countWritersBuyingBoard; + request2->countWriters = countWritersBuyingBoard; request2->notDoneBoardId = ¬DoneBoardId; request2->notDoneAmount = ¬DoneAmount; @@ -762,6 +792,8 @@ int main(int argc, char const *argv[]) { shmctl(shmidProducts, IPC_RMID, NULL); shmdt(shared_memory_CountBoards); shmctl(shmidCountBoards, IPC_RMID, NULL); + shmdt(shared_memory_ReadersWritersState); + shmctl(shmidReadersWritersState, IPC_RMID, NULL); removeSemaphore(semidAccessProducts, "rm_AccessProducts"); removeSemaphore(semidReadersProducts, "rm_ReadersProducts"); @@ -790,45 +822,82 @@ key_t getKey(const char *pathname, int proj_id) { int createSemaphore(key_t key, const char *semName) { int semid = semget(key, 1, IPC_CREAT | 0666); + if (semid == -1) { - perror(strcat("semget ", semName)); - exit(1); + fprintf( + stderr, + "semget %s failed: %s\n", + semName, + strerror(errno) + ); + exit(EXIT_FAILURE); + } + + if (semctl(semid, 0, SETVAL, 1) == -1) { + fprintf( + stderr, + "semctl SETVAL %s failed: %s\n", + semName, + strerror(errno) + ); + exit(EXIT_FAILURE); } + return semid; } void removeSemaphore(int semid, const char *semName) { if (semctl(semid, 0, IPC_RMID) == -1) { - perror(strcat("semctl IPC_RMID ", semName)); - exit(1); + fprintf( + stderr, + "semctl IPC_RMID %s failed: %s\n", + semName, + strerror(errno) + ); } } void lock(int semid, const char *semName) { - struct sembuf sembuf_operation; - sembuf_operation.sem_num = 0; - sembuf_operation.sem_op = -1; - sembuf_operation.sem_flg = IPC_NOWAIT; - - if (semop(semid, &sembuf_operation, 1) == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - //printf("Semaphore %s is already locked\n", semName); - } else { - perror(strcat("semop ", semName)); - exit(1); + struct sembuf operation = { + .sem_num = 0, + .sem_op = -1, + .sem_flg = 0 + }; + + while (semop(semid, &operation, 1) == -1) { + if (errno == EINTR) { + continue; } + + fprintf( + stderr, + "semop lock %s failed: %s\n", + semName, + strerror(errno) + ); + exit(EXIT_FAILURE); } } void unlock(int semid, const char *semName) { - struct sembuf sembuf_operation; - sembuf_operation.sem_num = 0; - sembuf_operation.sem_op = 1; - sembuf_operation.sem_flg = 0; + struct sembuf operation = { + .sem_num = 0, + .sem_op = 1, + .sem_flg = 0 + }; + + while (semop(semid, &operation, 1) == -1) { + if (errno == EINTR) { + continue; + } - if (semop(semid, &sembuf_operation, 1) == -1) { - perror(strcat("semop ", semName)); - exit(1); + fprintf( + stderr, + "semop unlock %s failed: %s\n", + semName, + strerror(errno) + ); + exit(EXIT_FAILURE); } } From cc3762ec2e5232b1f7126431f1d4bd134ff4e35d Mon Sep 17 00:00:00 2001 From: Yurii Korolkov Date: Mon, 15 Jun 2026 17:01:56 +0300 Subject: [PATCH 4/8] additional small fixes --- .gitignore | 2 +- shop_simulator.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index f3634f6..1bbe946 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ shop-simulator .runtime/ # Simulation output -simulation.log \ No newline at end of file +simulation.log diff --git a/shop_simulator.c b/shop_simulator.c index 6f8603e..4b3c5ff 100644 --- a/shop_simulator.c +++ b/shop_simulator.c @@ -208,12 +208,12 @@ int main(int argc, char const *argv[]) { } if (countAgents < 1 || countAgents > 4) { - fprintf(stderr, "Sales agent count must be greater than zero.\n"); + fprintf(stderr, "Sales agent count must be between 1 and 4.\n"); return EXIT_FAILURE; } if (countCustomers < 1 || countCustomers > 10) { - fprintf(stderr, "Customer count must be greater than zero.\n"); + fprintf(stderr, "Customer count must be between 1 and 10.\n"); return EXIT_FAILURE; } @@ -1576,4 +1576,3 @@ void readArguments(int *countProducts, int *countAgents, int *countCustomers, in printf("Argument 3 is not a valid integer.\n"); } } - From f82ea55befc458d924783932e0f6a6e14eef5e15 Mon Sep 17 00:00:00 2001 From: Yurii Korolkov Date: Mon, 15 Jun 2026 19:37:10 +0300 Subject: [PATCH 5/8] fix: stabilize readers-writers synchronization Use a turnstile-based locking scheme with shared reader state and blocking System V semaphores. Revalidate concurrent order updates and support graceful shutdown for child and manager processes. --- shop_simulator.c | 345 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 250 insertions(+), 95 deletions(-) diff --git a/shop_simulator.c b/shop_simulator.c index 4b3c5ff..728a1a7 100644 --- a/shop_simulator.c +++ b/shop_simulator.c @@ -167,13 +167,19 @@ void* thread_readBuyingBoards(void* arg); void* thread_addBuyingBoard(void* arg); void* thread_threadMakeDone(void* arg); -//======== Sygnal for subprocess ================================= +//======== Signals ================================================= volatile sig_atomic_t stop = 0; -void signalHandler(int sig) { + +void childSignalHandler(int sig) { (void)sig; stop = 1; } +void parentSignalHandler(int sig) { + (void)sig; +} + + //======== Others ================================================= void prepareIpcTokenFile(void); void increment(int *value); @@ -262,11 +268,11 @@ int main(int argc, char const *argv[]) { //=========BuyingBoard================================================== // Intialize : - int done; + struct buyingBoard* buyingBoards = initializeBuyingBoards(&countBoards); for (int i = 0; i < countCustomers; i++) { buyingBoards = addBuyingBoard(buyingBoards, &countBoards, i, 1, 1); - done = makeDone(buyingBoards, &countBoards, i); + makeDone(buyingBoards, &countBoards, i); } // Shared memory : @@ -402,7 +408,7 @@ int main(int argc, char const *argv[]) { for (int j = 0; j < countCustomers; j++) { pid_t pid = fork(); if (pid == 0) { - signal(SIGTERM, signalHandler); + signal(SIGTERM, childSignalHandler); srand(time(NULL) ^ getpid()); int customerId = j; @@ -418,12 +424,12 @@ int main(int argc, char const *argv[]) { struct buyingBoard* currentBuyingBoards = (struct buyingBoard *)malloc(150 * sizeof(struct buyingBoard));; int isLastOrderDone; - struct buyingBoard* local_buyingBoards; - while (!stop) { int randomSleepTime = getRandomNum(3, 6); if (customerFunction == 0) sleep(randomSleepTime); + if (stop) break; + switch (customerFunction) { case 0: // reader problem : read menu and choose item { @@ -566,7 +572,7 @@ int main(int argc, char const *argv[]) { break; } } - exit(0); + _exit(EXIT_SUCCESS); } else if (pid > 0) { childPIDs[childCount++] = pid; printf("Created Customer %d : pid = %d\n", j, pid); @@ -581,7 +587,7 @@ int main(int argc, char const *argv[]) { for (int i = 0; i < countAgents; i++) { pid_t pid = fork(); if (pid == 0) { - signal(SIGTERM, signalHandler); + signal(SIGTERM, childSignalHandler); srand(time(NULL) ^ getpid()); int agentId = i; @@ -599,6 +605,8 @@ int main(int argc, char const *argv[]) { int randomSleepTime = getRandomNum(1, 2); if (agentFunction == 1) sleep(randomSleepTime); + if (stop) break; + switch (agentFunction) { case 0: // writer problem : update Total Orders { @@ -727,7 +735,7 @@ int main(int argc, char const *argv[]) { break; } } - exit(0); + _exit(EXIT_SUCCESS); } else if (pid > 0) { childPIDs[childCount++] = pid; printf("Created Sales Agent %d : pid = %d\n", i, pid); @@ -738,7 +746,8 @@ int main(int argc, char const *argv[]) { } // Set up signal handling for the parent process to terminate child processes - signal(SIGINT, signalHandler); + signal(SIGINT, parentSignalHandler); + signal(SIGTERM, parentSignalHandler); sleep(simulationTime); @@ -766,7 +775,7 @@ int main(int argc, char const *argv[]) { printf("Finish Time : "); struct timespec finish = getCurrentTime(); double finalSemulationTime = timer(start); - printCurrentTime(start); + printCurrentTime(finish); printf("Final Time of the simulation : %f", finalSemulationTime); printf("\n\n"); @@ -901,42 +910,56 @@ void unlock(int semid, const char *semName) { } } -void writerLock(int semidOrder, const char *orderDeskription, - int semidAccess, const char *accessDeskription, - int semidWriters, const char *writersDeskription, - int *waitingWriters) { - - lock(semidWriters, writersDeskription); - increment(waitingWriters); - unlock(semidWriters, writersDeskription); - +void writerLock( + int semidOrder, const char *orderDeskription, + int semidAccess, const char *accessDeskription, + int semidWriters, const char *writersDeskription, + int *waitingWriters +) { + /* + * These parameters belong to the previous waiting-writers protocol. + * They are kept temporarily to avoid changing all call sites before + * the new synchronization scheme is verified. + */ + (void)semidWriters; + (void)writersDeskription; + (void)waitingWriters; + + /* + * Close the turnstile before waiting for exclusive access. + * Existing readers can still leave through readerUnlock(), while + * new readers cannot enter ahead of this writer. + */ lock(semidOrder, orderDeskription); lock(semidAccess, accessDeskription); - - lock(semidWriters, writersDeskription); - decrement(waitingWriters); - unlock(semidWriters, writersDeskription); - unlock(semidOrder, orderDeskription); } -void readerLock(int semidOrder, const char *orderDeskription, - int semidReaders, const char *readersDeskription, - int semidAccess, const char *accessDeskription, - int semidWriters, const char *lockWritersDeskription, - int *countReaders, int *waitingWriters) { - lock(semidWriters, lockWritersDeskription); - while (*waitingWriters > 0) { - unlock(semidWriters, lockWritersDeskription); - usleep(100); - lock(semidWriters, lockWritersDeskription); - } - unlock(semidWriters, lockWritersDeskription); +void readerLock( + int semidOrder, const char *orderDeskription, + int semidReaders, const char *readersDeskription, + int semidAccess, const char *accessDeskription, + int semidWriters, const char *writersDeskription, + int *countReaders, + int *waitingWriters +) { + /* + * These parameters belong to the previous waiting-writers protocol. + * They will be removed after the new scheme is tested. + */ + (void)semidWriters; + (void)writersDeskription; + (void)waitingWriters; lock(semidOrder, orderDeskription); lock(semidReaders, readersDeskription); - if (*countReaders == 0) lock(semidAccess, accessDeskription); + + if (*countReaders == 0) { + lock(semidAccess, accessDeskription); + } + increment(countReaders); + unlock(semidReaders, readersDeskription); unlock(semidOrder, orderDeskription); } @@ -1229,12 +1252,14 @@ void* thread_readMenu(void* arg) { struct item* shared_memory_Products = args->shared_memory_Products; // reader lock: - readerLock(semidOrder, orderDeskription, - semidReaders, readersDeskription, - semidAccess, accessDeskription, - semidWriters, writersDeskription, - waitingWriters, - countReaders); + readerLock( + semidOrder, orderDeskription, + semidReaders, readersDeskription, + semidAccess, accessDeskription, + semidWriters, writersDeskription, + countReaders, + waitingWriters + ); printf("%8.4f sec : thread : Customer id: %d : I'm going to read the menu | pid = %d, ppid = %d\n", timer(start), id, getpid(), getppid()); @@ -1322,12 +1347,14 @@ void* thread_readBuyingBoards(void* arg) { struct buyingBoard *shared_memory_BuyingBoard = args->shared_memory_BuyingBoard; // reader lock: - readerLock(semidOrder, orderDeskription, - semidReaders, readersDeskription, - semidAccess, accessDeskription, - semidWriters, writersDeskription, - waitingWriters, - countReaders); + readerLock( + semidOrder, orderDeskription, + semidReaders, readersDeskription, + semidAccess, accessDeskription, + semidWriters, writersDeskription, + countReaders, + waitingWriters + ); printf("%8.4f sec : thread : %s id: %d : I'm going to read Buying Boards | pid = %d, ppid = %d\n", timer(start), accountType, id, getpid(), getppid()); @@ -1399,8 +1426,10 @@ void* thread_addBuyingBoard(void* arg) { pthread_exit(NULL); } // writer problem: + void* thread_threadMakeDone(void* arg) { - struct updateBuyingBoardsRequest* args = (struct updateBuyingBoardsRequest*)arg; + struct updateBuyingBoardsRequest* args = + (struct updateBuyingBoardsRequest*)arg; struct timespec start = args->start; int id = args->id; @@ -1410,66 +1439,176 @@ void* thread_threadMakeDone(void* arg) { int semidOrder = args->semidOrder; char* orderDeskription = args->orderDeskription; int semidLockWriters = args->semidLockWriters; - const char *lockWritersDeskription = args->lockWritersDeskription; - int *waitingWriters = args->countWriters; - - int *notDoneBoardId = args->notDoneBoardId; - int *notDoneAmount = args->notDoneAmount; - int *notDoneItemId = args->notDoneItemId; + const char* lockWritersDeskription = + args->lockWritersDeskription; + int* waitingWriters = args->countWriters; + + int* notDoneBoardId = args->notDoneBoardId; + int* notDoneAmount = args->notDoneAmount; + int* notDoneItemId = args->notDoneItemId; + + int* shared_memory_CountBoards = + args->shared_memory_CountBoards; + struct buyingBoard* shared_memory_BuyingBoard = + args->shared_memory_BuyingBoard; + + writerLock( + semidOrder, + orderDeskription, + semidAccess, + accessDeskription, + semidLockWriters, + lockWritersDeskription, + waitingWriters + ); - int *shared_memory_CountBoards = args->shared_memory_CountBoards; - struct buyingBoard *shared_memory_BuyingBoard = args->shared_memory_BuyingBoard; + printf( + "%8.4f sec : thread : Agent id: %d : " + "I'm going to make Order id: %d Done " + "| pid = %d, ppid = %d\n", + timer(start), + id, + *notDoneBoardId, + getpid(), + getppid() + ); int currentCountBoards; + memcpy( + ¤tCountBoards, + shared_memory_CountBoards, + sizeof(currentCountBoards) + ); - // writer lock: - writerLock(semidOrder, orderDeskription, - semidAccess, accessDeskription, - semidLockWriters, lockWritersDeskription, - waitingWriters); + struct buyingBoard* currentBuyingBoards = malloc( + (size_t)currentCountBoards * + sizeof(*currentBuyingBoards) + ); - printf("%8.4f sec : thread : Agent id: %d : I'm going to make Order id: %d Done | pid = %d, ppid = %d\n", - timer(start), id, *notDoneBoardId, getpid(), getppid()); + if (currentBuyingBoards == NULL) { + fprintf( + stderr, + "Agent %d failed to allocate buying-board storage.\n", + id + ); - usleep(100); - //sleep(1); + *notDoneBoardId = -1; + unlock(semidAccess, accessDeskription); + return NULL; + } - memcpy(¤tCountBoards, shared_memory_CountBoards, sizeof(int)); + memcpy( + currentBuyingBoards, + shared_memory_BuyingBoard, + (size_t)currentCountBoards * + sizeof(*currentBuyingBoards) + ); - struct buyingBoard* currentBuyingBoards = (struct buyingBoard*)malloc(currentCountBoards * sizeof(struct buyingBoard)); + int requestedBoardId = *notDoneBoardId; - memcpy(currentBuyingBoards, shared_memory_BuyingBoard, currentCountBoards * sizeof(struct buyingBoard)); + int completionResult = makeDone( + currentBuyingBoards, + ¤tCountBoards, + requestedBoardId + ); + + if (completionResult == 0) { + /* + * Another sales agent completed the order after both agents + * had read the same snapshot. Revalidate while still holding + * exclusive writer access and process another pending order. + */ + int nextBoardId = getNotDoneProductId( + currentBuyingBoards, + ¤tCountBoards + ); - int isDone = makeDone(currentBuyingBoards, ¤tCountBoards, *notDoneBoardId); - if (isDone == 0) { - int tmp_boardId = *notDoneBoardId; - *notDoneBoardId = getNotDoneProductId(currentBuyingBoards, ¤tCountBoards); - if (*notDoneBoardId == -1) { - printf("%8.4f sec : thread : Agent id: %d : I've found that the Order id: %d is already Done and there are any New Order | pid = %d, ppid = %d\n", - timer(start), id, tmp_boardId, getpid(), getppid()); + if (nextBoardId == -1) { + printf( + "%8.4f sec : thread : Agent id: %d : " + "Order id: %d was already done and no pending " + "orders remain | pid = %d, ppid = %d\n", + timer(start), + id, + requestedBoardId, + getpid(), + getppid() + ); + + *notDoneBoardId = -1; } else { - *notDoneAmount = getAmountByBoardId(currentBuyingBoards, ¤tCountBoards, *notDoneBoardId); - isDone = makeDone(currentBuyingBoards, ¤tCountBoards, *notDoneBoardId); - - if (isDone != -1) printf("%8.4f sec : thread : Agent id: %d : Error Update Done | pid = %d, ppid = %d", timer(start), id, getpid(), getppid()); - else { - *notDoneItemId = getItemIdByBoardId(currentBuyingBoards, ¤tCountBoards, *notDoneBoardId); - printf("%8.4f sec : thread : Agent id: %d : I've found that the Order id: %d is already Done but I've found the New Order ID : %d : item : %d : amount : %d | pid = %d, ppid = %d\n", - timer(start), id, tmp_boardId, *notDoneBoardId, *notDoneItemId, *notDoneAmount, getpid(), getppid()); + int nextAmount = getAmountByBoardId( + currentBuyingBoards, + ¤tCountBoards, + nextBoardId + ); + + int nextItemId = getItemIdByBoardId( + currentBuyingBoards, + ¤tCountBoards, + nextBoardId + ); + + int nextCompletionResult = makeDone( + currentBuyingBoards, + ¤tCountBoards, + nextBoardId + ); + + if (nextCompletionResult == 1) { + *notDoneBoardId = nextBoardId; + *notDoneAmount = nextAmount; + *notDoneItemId = nextItemId; + + printf( + "%8.4f sec : thread : Agent id: %d : " + "Order id: %d was already done; processed " + "pending Order id: %d, item: %d, amount: %d " + "| pid = %d, ppid = %d\n", + timer(start), + id, + requestedBoardId, + nextBoardId, + nextItemId, + nextAmount, + getpid(), + getppid() + ); + } else { + fprintf( + stderr, + "Agent %d failed to complete fallback " + "order %d.\n", + id, + nextBoardId + ); + + *notDoneBoardId = -1; } } - } else if (isDone == -1) printf("%8.4f sec : thread : Agent id: %d : Error : I havent found board ID : %d in the Boards List | pid = %d, ppid = %d", - timer(start), id, *notDoneBoardId, getpid(), getppid()); - + } else if (completionResult == -1) { + fprintf( + stderr, + "Agent %d could not find order %d.\n", + id, + requestedBoardId + ); - memcpy(shared_memory_BuyingBoard, currentBuyingBoards, currentCountBoards * sizeof(struct buyingBoard)); + *notDoneBoardId = -1; + } + + memcpy( + shared_memory_BuyingBoard, + currentBuyingBoards, + (size_t)currentCountBoards * + sizeof(*currentBuyingBoards) + ); free(currentBuyingBoards); - // writer unlock: unlock(semidAccess, accessDeskription); - pthread_exit(NULL); + return NULL; } //=========Others================================================== @@ -1542,6 +1681,18 @@ int isInteger(const char *str) { } void readArguments(int *countProducts, int *countAgents, int *countCustomers, int argc, char *argv[]) { + if (argc == 1) { + return; + } + + if (argc != 4) { + fprintf( + stderr, + "Usage: %s [products sales-agents customers]\n", + argv[0] + ); + exit(EXIT_FAILURE); + } if (isInteger(argv[1])) { int countProductsReceived = atoi(argv[1]); @@ -1556,10 +1707,14 @@ void readArguments(int *countProducts, int *countAgents, int *countCustomers, in if (isInteger(argv[2])) { int countAgentsReceived = atoi(argv[2]); - if (countAgentsReceived > 0 && countAgentsReceived < 4) { + if (countAgentsReceived > 0 && countAgentsReceived <= 4) { *countAgents = countAgentsReceived; } else { - printf("Argument 2 = %d : amount of Sales Agents can not be less than 1 and more than 3 : Default value : 2\n", countAgentsReceived); + printf( + "Argument 2 = %d : amount of Sales Agents can not be " + "less than 1 and more than 4 : Default value : 2\n", + countAgentsReceived + ); } } else { printf("Argument 2 is not a valid integer.\n"); From 5c57d0db43b8077de776fa39104153461342b590 Mon Sep 17 00:00:00 2001 From: Yurii Korolkov Date: Mon, 15 Jun 2026 21:58:13 +0300 Subject: [PATCH 6/8] refactor: remove legacy writer synchronization state Remove unused waiting-writer counters, writer semaphores, and obsolete request parameters after adopting the turnstile-based readers-writers scheme. --- shop_simulator.c | 170 +++++++++++------------------------------------ 1 file changed, 38 insertions(+), 132 deletions(-) diff --git a/shop_simulator.c b/shop_simulator.c index 728a1a7..8724f34 100644 --- a/shop_simulator.c +++ b/shop_simulator.c @@ -19,11 +19,9 @@ static const char *const IPC_RUNTIME_DIR = ".runtime"; static const char *const IPC_TOKEN_FILE = ".runtime/ipc.token"; -struct readersWritersState { +struct readersState { int buyingBoardReaders; - int buyingBoardWaitingWriters; int productReaders; - int productWaitingWriters; }; @@ -34,17 +32,17 @@ void removeSemaphore(int semid, const char *semName); void lock(int semid, const char *semName); void unlock(int semid, const char *semName); -void writerLock(int semidOrder, const char *orderDeskription, - int semidAccess, const char *accessDeskription, - int semidLockWriters, const char *lockWritersDeskription, - int *waitingWriters); +void writerLock( + int semidOrder, const char *orderDeskription, + int semidAccess, const char *accessDeskription +); -void readerLock(int semidOrder, const char *orderDeskription, - int semidReaders, const char *readersDeskription, - int semidAccess, const char *accessDeskription, - int semidLockWriters, const char *lockWritersDeskription, - int *countReaders, - int *waitingWriters); +void readerLock( + int semidOrder, const char *orderDeskription, + int semidReaders, const char *readersDeskription, + int semidAccess, const char *accessDeskription, + int *countReaders +); void readerUnlock(int semidReaders, const char *readersDeskription, int semidAccess, const char *accessDeskription, @@ -96,9 +94,6 @@ struct readBuyingBoardsRequest { char *readersDeskription; int semidOrder; char *orderDeskription; - int semidWriters; - const char *writersDeskription; - int *countWriters; int *countReaders; int *countBoards; int *currentCountBoards; @@ -114,10 +109,6 @@ struct updateBuyingBoardsRequest { char *accessDeskription; int semidOrder; char *orderDeskription; - int semidLockWriters; - const char *lockWritersDeskription; - int *countWriters; - int *currentCountBoards; int itemId; int amountOrder; int *notDoneBoardId; @@ -136,9 +127,6 @@ struct readMenuRequest { char *readersDeskription; int semidOrder; char *orderDeskription; - int semidWriters; - const char *writersDeskription; - int *countWriters; int *countReaders; int *countProducts; struct item *currentProducts; @@ -152,9 +140,6 @@ struct UpdateProductsRequest { char *accessDeskription; int semidOrder; char *orderDeskription; - int semidLockWriters; - const char *lockWritersDeskription; - int *countWriters; int *countProducts; int itemId; int amountOrder; @@ -242,15 +227,13 @@ int main(int argc, char const *argv[]) { key_t keyAccessBuyingBoard = getKey(IPC_TOKEN_FILE, 152); key_t keyReadersBuyingBoard = getKey(IPC_TOKEN_FILE, 153); key_t keyOrderBuyingBoard = getKey(IPC_TOKEN_FILE, 154); - key_t keyWritersBuyingBoard = getKey(IPC_TOKEN_FILE, 155); key_t keyProducts = getKey(IPC_TOKEN_FILE, 160); key_t keyAccessProducts = getKey(IPC_TOKEN_FILE, 161); key_t keyReadersProducts = getKey(IPC_TOKEN_FILE, 162); key_t keyOrderProducts = getKey(IPC_TOKEN_FILE, 163); - key_t keyWritersProducts = getKey(IPC_TOKEN_FILE, 164); - key_t keyReadersWritersState = getKey(IPC_TOKEN_FILE, 170); + key_t keyReadersState = getKey(IPC_TOKEN_FILE, 170); printf("\nProject info:\n\nCustomers : %2d persons\nSales Agent : %2d persons\nCount Products : %2d items\nSimulation time : %2d sec\n\n", countCustomers, countAgents, countProducts, simulationTime); @@ -306,52 +289,45 @@ int main(int argc, char const *argv[]) { memcpy(shared_memory_CountBoards, &countBoards, sizeof(int)); - int shmidReadersWritersState = shmget( - keyReadersWritersState, - sizeof(struct readersWritersState), + int shmidReadersState = shmget( + keyReadersState, + sizeof(struct readersState), IPC_CREAT | 0666 ); - if (shmidReadersWritersState == -1) { - perror("shmget_create_ReadersWritersState"); + if (shmidReadersState == -1) { + perror("shmget_create_readersState"); exit(EXIT_FAILURE); } - struct readersWritersState *shared_memory_ReadersWritersState = - (struct readersWritersState *)shmat( - shmidReadersWritersState, + struct readersState *shared_memory_readersState = + (struct readersState *)shmat( + shmidReadersState, NULL, 0 ); - if (shared_memory_ReadersWritersState == (void *)-1) { - perror("shmat_ReadersWritersState"); + if (shared_memory_readersState == (void *)-1) { + perror("shmat_readersState"); exit(EXIT_FAILURE); } memset( - shared_memory_ReadersWritersState, + shared_memory_readersState, 0, - sizeof(*shared_memory_ReadersWritersState) + sizeof(*shared_memory_readersState) ); int *countReadersBuyingBoard = - &shared_memory_ReadersWritersState->buyingBoardReaders; - - int *countWritersBuyingBoard = - &shared_memory_ReadersWritersState->buyingBoardWaitingWriters; + &shared_memory_readersState->buyingBoardReaders; int *countReadersProducts = - &shared_memory_ReadersWritersState->productReaders; - - int *countWritersProducts = - &shared_memory_ReadersWritersState->productWaitingWriters; + &shared_memory_readersState->productReaders; // Semaphores : int semidAccessBuyingBoard = createSemaphore(keyAccessBuyingBoard, "AccessBuyingBoard"); int semidReadersBuyingBoard = createSemaphore(keyReadersBuyingBoard, "ReadersBuyingBoard"); int semidOrderBuyingBoard = createSemaphore(keyOrderBuyingBoard, "OrderBuyingBoard"); - int semidWritersBuyingBoard = createSemaphore(keyWritersBuyingBoard, "WritersBuyingBoard"); //=========Products================================================== // Intialize : @@ -378,7 +354,6 @@ int main(int argc, char const *argv[]) { int semidAccessProducts = createSemaphore(keyAccessProducts, "AccessProducts"); int semidReadersProducts = createSemaphore(keyReadersProducts, "ReadersProducts"); int semidOrderProducts = createSemaphore(keyOrderProducts, "OrderProducts"); - int semidWritersProducts = createSemaphore(keyWritersProducts, "WritersProducts"); //========Check shared memory===================================== @@ -444,9 +419,6 @@ int main(int argc, char const *argv[]) { request0->readersDeskription = "ReadersProducts_readMenu"; request0->semidOrder = semidOrderProducts; request0->orderDeskription = "OrderProducts_readMenu"; - request0->semidWriters = semidWritersProducts; - request0->writersDeskription = "WritersProducts_readMenu"; - request0->countWriters = countWritersProducts; request0->countReaders = countReadersProducts; request0->countProducts = &countProducts; @@ -484,9 +456,6 @@ int main(int argc, char const *argv[]) { request1->readersDeskription = "ReadersBuyingBoards_readBuyingBoards"; request1->semidOrder = semidOrderBuyingBoard; request1->orderDeskription = "OrderBuyingBoards_readBuyingBoards"; - request1->semidWriters = semidWritersBuyingBoard; - request1->writersDeskription = "WritersBuyingBoards_readBuyingBoards"; - request1->countWriters = countWritersBuyingBoard; request1->countReaders = countReadersBuyingBoard; request1->countBoards = shared_memory_CountBoards; @@ -545,13 +514,9 @@ int main(int argc, char const *argv[]) { request2->accessDeskription = "AccessBuyingBoards_addBuyingBoard"; request2->semidOrder = semidOrderBuyingBoard; request2->orderDeskription = "OrderBuyingBoards_addBuyingBoard"; - request2->semidLockWriters = semidWritersBuyingBoard; - request2->lockWritersDeskription = "LockWritersBuyingBoards_addBuyingBoard"; - request2->countWriters = countWritersBuyingBoard; request2->itemId = randomItem; request2->amountOrder = randomAmount; - request2->currentCountBoards = &countBoards; request2->shared_memory_CountBoards = shared_memory_CountBoards; request2->shared_memory_BuyingBoard = shared_memory_BuyingBoard; @@ -619,9 +584,6 @@ int main(int argc, char const *argv[]) { request0->accessDeskription = "AccessProducts_updateProducts"; request0->semidOrder = semidOrderProducts; request0->orderDeskription = "OrderProducts_updateProducts"; - request0->semidLockWriters = semidWritersProducts; - request0->lockWritersDeskription = "LockWritersProducts_updateProducts"; - request0->countWriters = countWritersProducts; request0->countProducts = &countProducts; request0->itemId = notDoneItemId; @@ -657,9 +619,6 @@ int main(int argc, char const *argv[]) { request1->readersDeskription = "ReadersBuyingBoards_readBuyingBoards"; request1->semidOrder = semidOrderBuyingBoard; request1->orderDeskription = "OrderBuyingBoards_readBuyingBoards"; - request1->semidWriters = semidWritersBuyingBoard; - request1->writersDeskription = "WritersBuyingBoards_readBuyingBoards"; - request1->countWriters = countWritersBuyingBoard; request1->countReaders = countReadersBuyingBoard; request1->countBoards = shared_memory_CountBoards; @@ -703,9 +662,6 @@ int main(int argc, char const *argv[]) { request2->accessDeskription = "AccessBuyingBoards_makeDone"; request2->semidOrder = semidOrderBuyingBoard; request2->orderDeskription = "OrderBuyingBoards_makeDone"; - request2->semidLockWriters = semidWritersBuyingBoard; - request2->lockWritersDeskription = "LockWritersBuyingBoards_makeDone"; - request2->countWriters = countWritersBuyingBoard; request2->notDoneBoardId = ¬DoneBoardId; request2->notDoneAmount = ¬DoneAmount; @@ -801,17 +757,15 @@ int main(int argc, char const *argv[]) { shmctl(shmidProducts, IPC_RMID, NULL); shmdt(shared_memory_CountBoards); shmctl(shmidCountBoards, IPC_RMID, NULL); - shmdt(shared_memory_ReadersWritersState); - shmctl(shmidReadersWritersState, IPC_RMID, NULL); + shmdt(shared_memory_readersState); + shmctl(shmidReadersState, IPC_RMID, NULL); removeSemaphore(semidAccessProducts, "rm_AccessProducts"); removeSemaphore(semidReadersProducts, "rm_ReadersProducts"); removeSemaphore(semidOrderProducts, "rm_OrderProducts"); - removeSemaphore(semidWritersProducts, "rm_kWritersProducts"); removeSemaphore(semidAccessBuyingBoard, "rm_AccessBuyingBoard"); removeSemaphore(semidReadersBuyingBoard,"rm_ReadersBuyingBoard"); removeSemaphore(semidOrderBuyingBoard, "rm_OrderBuyingBoard"); - removeSemaphore(semidWritersBuyingBoard,"rm_WritersBuyingBoard"); free(childPIDs); @@ -911,24 +865,13 @@ void unlock(int semid, const char *semName) { } void writerLock( - int semidOrder, const char *orderDeskription, - int semidAccess, const char *accessDeskription, - int semidWriters, const char *writersDeskription, - int *waitingWriters + int semidOrder, const char *orderDeskription, + int semidAccess, const char *accessDeskription ) { - /* - * These parameters belong to the previous waiting-writers protocol. - * They are kept temporarily to avoid changing all call sites before - * the new synchronization scheme is verified. - */ - (void)semidWriters; - (void)writersDeskription; - (void)waitingWriters; - /* * Close the turnstile before waiting for exclusive access. - * Existing readers can still leave through readerUnlock(), while - * new readers cannot enter ahead of this writer. + * Existing readers may leave, while new readers cannot + * bypass the waiting writer. */ lock(semidOrder, orderDeskription); lock(semidAccess, accessDeskription); @@ -939,18 +882,8 @@ void readerLock( int semidOrder, const char *orderDeskription, int semidReaders, const char *readersDeskription, int semidAccess, const char *accessDeskription, - int semidWriters, const char *writersDeskription, - int *countReaders, - int *waitingWriters + int *countReaders ) { - /* - * These parameters belong to the previous waiting-writers protocol. - * They will be removed after the new scheme is tested. - */ - (void)semidWriters; - (void)writersDeskription; - (void)waitingWriters; - lock(semidOrder, orderDeskription); lock(semidReaders, readersDeskription); @@ -1242,9 +1175,6 @@ void* thread_readMenu(void* arg) { char* readersDeskription = args->readersDeskription; int semidOrder = args->semidOrder; char* orderDeskription = args->orderDeskription; - int semidWriters = args->semidWriters; - const char *writersDeskription = args->writersDeskription; - int *waitingWriters = args->countWriters; int* countReaders = args->countReaders; int* countProducts = args->countProducts; @@ -1256,9 +1186,7 @@ void* thread_readMenu(void* arg) { semidOrder, orderDeskription, semidReaders, readersDeskription, semidAccess, accessDeskription, - semidWriters, writersDeskription, - countReaders, - waitingWriters + countReaders ); printf("%8.4f sec : thread : Customer id: %d : I'm going to read the menu | pid = %d, ppid = %d\n", @@ -1286,9 +1214,6 @@ void* thread_updateTotalOrders(void* arg) { char* accessDeskription = args->accessDeskription; int semidOrder = args->semidOrder; char* orderDeskription = args->orderDeskription; - int semidLockWriters = args->semidLockWriters; - const char *lockWritersDeskription = args->lockWritersDeskription; - int *waitingWriters = args->countWriters; int* countProducts = args->countProducts; int itemId = args->itemId; int amountOrder = args->amountOrder; @@ -1297,9 +1222,7 @@ void* thread_updateTotalOrders(void* arg) { // writer lock: writerLock(semidOrder, orderDeskription, - semidAccess, accessDeskription, - semidLockWriters, lockWritersDeskription, - waitingWriters); + semidAccess, accessDeskription); printf("%8.4f sec : thread : Sales Agent id: %d : I'm going to update the total orders of the item : %d; amount : %d items | pid = %d, ppid = %d\n", timer(start), id, itemId, amountOrder, getpid(), getppid()); @@ -1335,9 +1258,6 @@ void* thread_readBuyingBoards(void* arg) { char* readersDeskription = args->readersDeskription; int semidOrder = args->semidOrder; char* orderDeskription = args->orderDeskription; - int semidWriters = args->semidWriters; - const char *writersDeskription = args->writersDeskription; - int *waitingWriters = args->countWriters; int* countReaders = args->countReaders; int *countBoards = args->countBoards; @@ -1351,9 +1271,7 @@ void* thread_readBuyingBoards(void* arg) { semidOrder, orderDeskription, semidReaders, readersDeskription, semidAccess, accessDeskription, - semidWriters, writersDeskription, - countReaders, - waitingWriters + countReaders ); printf("%8.4f sec : thread : %s id: %d : I'm going to read Buying Boards | pid = %d, ppid = %d\n", @@ -1384,9 +1302,6 @@ void* thread_addBuyingBoard(void* arg) { char* accessDeskription = args->accessDeskription; int semidOrder = args->semidOrder; char* orderDeskription = args->orderDeskription; - int semidLockWriters = args->semidLockWriters; - const char *lockWritersDeskription = args->lockWritersDeskription; - int *waitingWriters = args->countWriters; int itemId = args->itemId; int amountOrder = args->amountOrder; @@ -1397,9 +1312,7 @@ void* thread_addBuyingBoard(void* arg) { // writer lock: writerLock(semidOrder, orderDeskription, - semidAccess, accessDeskription, - semidLockWriters, lockWritersDeskription, - waitingWriters); + semidAccess, accessDeskription); printf("%8.4f sec : thread : Customer id: %d : I'm going to add new Buying Board of the item : %d; amount : %d items | pid = %d, ppid = %d\n", timer(start), id, itemId, amountOrder, getpid(), getppid()); @@ -1438,10 +1351,6 @@ void* thread_threadMakeDone(void* arg) { char* accessDeskription = args->accessDeskription; int semidOrder = args->semidOrder; char* orderDeskription = args->orderDeskription; - int semidLockWriters = args->semidLockWriters; - const char* lockWritersDeskription = - args->lockWritersDeskription; - int* waitingWriters = args->countWriters; int* notDoneBoardId = args->notDoneBoardId; int* notDoneAmount = args->notDoneAmount; @@ -1456,10 +1365,7 @@ void* thread_threadMakeDone(void* arg) { semidOrder, orderDeskription, semidAccess, - accessDeskription, - semidLockWriters, - lockWritersDeskription, - waitingWriters + accessDeskription ); printf( From f3cb011e025d157cfe240ffd4bfe25e84d2c1754 Mon Sep 17 00:00:00 2001 From: Yurii Korolkov Date: Mon, 15 Jun 2026 22:05:37 +0300 Subject: [PATCH 7/8] ci: add shop simulation workflow --- .github/workflows/shop-simulation.yml | 147 ++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 .github/workflows/shop-simulation.yml diff --git a/.github/workflows/shop-simulation.yml b/.github/workflows/shop-simulation.yml new file mode 100644 index 0000000..c944aa2 --- /dev/null +++ b/.github/workflows/shop-simulation.yml @@ -0,0 +1,147 @@ +name: Shop Simulation + +on: + push: + branches: + - main + - feature/shop-simulation-demo + + pull_request: + branches: + - main + + workflow_dispatch: + inputs: + products: + description: "Number of products (1-10)" + required: true + default: 5 + type: number + + sales_agents: + description: "Number of sales agents (1-4)" + required: true + default: 2 + type: number + + customers: + description: "Number of customers (1-10)" + required: true + default: 4 + type: number + +permissions: + contents: read + +jobs: + build: + name: Build simulator + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Compile with GCC + run: | + gcc \ + -std=gnu11 \ + -Wall \ + -Wextra \ + -Wpedantic \ + -Werror \ + -pthread \ + shop_simulator.c \ + -o shop-simulator + + - name: Upload compiled simulator + uses: actions/upload-artifact@v7 + with: + name: shop-simulator-binary + path: shop-simulator + retention-days: 7 + + run: + name: Run simulation + needs: build + runs-on: ubuntu-latest + timeout-minutes: 2 + + steps: + - name: Download compiled simulator + uses: actions/download-artifact@v8 + with: + name: shop-simulator-binary + + - name: Make simulator executable + run: chmod +x shop-simulator + + - name: Select simulation arguments + id: arguments + shell: bash + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + products="${{ inputs.products }}" + sales_agents="${{ inputs.sales_agents }}" + customers="${{ inputs.customers }}" + else + products=5 + sales_agents=2 + customers=4 + fi + + if (( products < 1 || products > 10 )); then + echo "Products must be between 1 and 10." + exit 1 + fi + + if (( sales_agents < 1 || sales_agents > 4 )); then + echo "Sales agents must be between 1 and 4." + exit 1 + fi + + if (( customers < 1 || customers > 10 )); then + echo "Customers must be between 1 and 10." + exit 1 + fi + + echo "products=$products" >> "$GITHUB_OUTPUT" + echo "sales_agents=$sales_agents" >> "$GITHUB_OUTPUT" + echo "customers=$customers" >> "$GITHUB_OUTPUT" + + echo "Selected configuration:" + echo " Products: $products" + echo " Sales agents: $sales_agents" + echo " Customers: $customers" + + - name: Run shop simulation + shell: bash + run: | + set -o pipefail + + timeout 45s stdbuf -oL -eL \ + ./shop-simulator \ + "${{ steps.arguments.outputs.products }}" \ + "${{ steps.arguments.outputs.sales_agents }}" \ + "${{ steps.arguments.outputs.customers }}" \ + 2>&1 | tee simulation.log + + - name: Verify simulation result + shell: bash + run: | + grep -q "Simulation is finished" simulation.log + grep -q "Result of the Simulation" simulation.log + grep -q "Total income" simulation.log + grep -q "Total orders" simulation.log + + echo "Simulation completed and produced the expected summary." + + - name: Upload simulation log + if: always() + uses: actions/upload-artifact@v7 + with: + name: shop-simulation-log + path: simulation.log + if-no-files-found: warn + retention-days: 14 From dc2576e0288c02dfe022af863d249af1ea9cab09 Mon Sep 17 00:00:00 2001 From: Yurii Korolkov Date: Mon, 15 Jun 2026 22:11:03 +0300 Subject: [PATCH 8/8] ci: update checkout action to Node.js 24 --- .github/workflows/shop-simulation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/shop-simulation.yml b/.github/workflows/shop-simulation.yml index c944aa2..055f401 100644 --- a/.github/workflows/shop-simulation.yml +++ b/.github/workflows/shop-simulation.yml @@ -41,7 +41,7 @@ jobs: steps: - name: Check out repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Compile with GCC run: |