diff --git a/libc/inc/ipc/ipc.h b/libc/inc/ipc/ipc.h index 6cea578..9b4a067 100644 --- a/libc/inc/ipc/ipc.h +++ b/libc/inc/ipc/ipc.h @@ -34,8 +34,8 @@ struct ipc_perm { unsigned short __seq; }; -/// @brief Returns a possible key -/// @param path file path -/// @param id integer -/// @return IPC key +/// @brief Returns a possible IPC key based upon the filepath and the id. +/// @param path The file path. +/// @param id the project id. +/// @return the IPC key. key_t ftok(char *path, int id); diff --git a/libc/src/ipc/ipc.c b/libc/src/ipc/ipc.c index b6a1404..4cc9da8 100644 --- a/libc/src/ipc/ipc.c +++ b/libc/src/ipc/ipc.c @@ -7,12 +7,11 @@ #include "system/syscall_types.h" #include "sys/errno.h" #include "stddef.h" - #include "ipc/sem.h" #include "ipc/shm.h" #include "ipc/msg.h" - #include "sys/stat.h" +#include "io/debug.h" _syscall3(void *, shmat, int, shmid, const void *, shmaddr, int, shmflg) @@ -62,7 +61,7 @@ key_t ftok(char *path, int id) struct stat_t st; if (stat(path, &st) < 0) { errno = ENOENT; - //printf("Error finding the serial number, check Errno...\n"); + pr_debug("Error finding the serial number, check Errno...\n"); return -1; } // Taking the upper 8 bits from the lower 8 bits of id, the second upper 8 diff --git a/mentos/src/ipc/sem.c b/mentos/src/ipc/sem.c index 047269d..5c2c538 100644 --- a/mentos/src/ipc/sem.c +++ b/mentos/src/ipc/sem.c @@ -2,12 +2,33 @@ /// @brief /// @copyright (c) 2014-2023 This file is distributed under the MIT License. /// See LICENSE.md for details. -///! @cond Doxygen_Suppress - -#include "ipc/sem.h" -#include "klib/list.h" -#include "process/process.h" -#include "sys/errno.h" +/// @details +/// # 03/04/2023 +/// At the moment we have various functions with their description (see +/// comments). The first time that the function semget is called, we are going +/// to generate the list and the first semaphore set with the assumption that we +/// are not given a IPC_PRIVATE key (temporary ofc). +/// We are able to create new semaphores set and generate unique keys +/// (IPC_PRIVATE) with a counter that searches for the first possible key to +/// assign. +/// Temporary idea: +/// - IPC_CREAT flag, it should be working properly, it creates a semaphore set +/// with the given key. +/// - IPC_EXCL flag, it should be working properly, it returns -1 and sets the +/// errno if the key is already used. +/// +/// # 11/04/2023 +/// Right now we have a first version of working semaphores in MentOS. +/// We have completed the semctl function and we have implemented the first +/// version of the semop function both user and kernel side. +/// The way it works is pretty straightforward, the user tries to perform an +/// operation and based on the value of the semaphore the kernel returns certain +/// values. If the operation cannot be performed then the user will stay in a +/// while loop. The cycle ends with a positive return value (the operation has +/// been taken care of) or in case of errors. +/// For testing purposes -> you can try the t_semget and the t_sem1 tests. They +/// both use semaphores and blocking / non blocking operations. t_sem1 is also +/// an exercise that was assingned by Professor Drago in the OS course. // ============================================================================ // Setup the logging for this file (do this before any other include). @@ -17,49 +38,43 @@ #include "io/debug.h" // Include debugging functions. // ============================================================================ -/* - 03/04 : at the moment we have various functions with their description (see comments). - The first time that the function semget is called, we are going to generate the list and the first semaphore set - with the assumption that we are not given a IPC_PRIVATE key (temporary ofc). - We are able to create new semaphores set and generate unique keys (IPC_PRIVATE) with - a counter that searches for the first possible key to assign. -> temporary idea - IPC_CREAT flag, it should be working properly, it creates a semaphore set with the given key. - IPC_EXCL flag, it should be working properly, it returns -1 and sets the errno if the - key is already used +#include "ipc/sem.h" +#include "klib/list.h" +#include "process/process.h" +#include "sys/errno.h" +#include "assert.h" - 11/04 : right now we have a first version of working semaphores in MentOS. - We have completed the semctl function and we have implemented the first version of the semop function - both user and kernel side. The way it works is pretty straightforward, the user tries to perform an operation - and based on the value of the semaphore the kernel returns certain values. If the operation cannot be performed - then the user will stay in a while loop. The cycle ends with a positive return value (the operation has been taken care of) - or in case of errors. - For testing purposes -> you can try the t_semget and the t_sem1 tests. They both use semaphores and blocking / non blocking operations. - t_sem1 is also an exercise that was assingned by Professor Drago in the OS course. -*/ - -///@brief a value to compute the semid value +///@brief A value to compute the semid value. int semid_assign = 0; -/// @brief to initialize a single semaphore -/// @param temp the pointer to the struct of the semaphore +/// @brief list of all current active semaphores +list_t *current_semaphores; + +/// @brief [temporary] To implement the IPC_PRIVATE mechanism. +int count_ipc_private = 2; + +/// @brief Initializes a single semaphore. +/// @param temp the pointer to the struct of the semaphore. static inline void __sem_init(struct sem *temp) { - temp->sem_val = 0; /*default*/ + temp->sem_val = 0; temp->sem_pid = sys_getpid(); - temp->sem_zcnt = 0; /*default*/ + temp->sem_zcnt = 0; } /// @brief Initializes a semid struct (set of semaphores). -/// @param temp the pointer to the semid struct +/// @param temp the pointer to the semid struct. /// @param key IPC_KEY associated with the set of semaphores /// @param nsems number of semaphores to initialize +/// @todo The way we compute the semid is a temporary solution. static inline void __semid_init(struct semid_ds *temp, key_t key, int nsems) { + assert(temp && "Received NULL semid data structure."); temp->owner = sys_getpid(); temp->key = key; - temp->semid = ++semid_assign; //temporary -> gonna need a way to compute IPCKEY -> semid - temp->sem_otime = 0; /*default*/ - temp->sem_ctime = 0; /*default*/ + temp->semid = ++semid_assign; + temp->sem_otime = 0; + temp->sem_ctime = 0; temp->sem_nsems = nsems; temp->sems = (struct sem *)kmalloc(sizeof(struct sem) * nsems); for (int i = 0; i < nsems; i++) { @@ -67,10 +82,30 @@ static inline void __semid_init(struct semid_ds *temp, key_t key, int nsems) } } +/// @brief Searches for the semaphore with the given id. +/// @param semid the id we are searching. +/// @return the semaphore with the given id. +static inline struct semid_ds *__find_semaphore(int semid) +{ + struct semid_ds *semaphore, *entry; + // Iterate through the list of semaphores. + listnode_foreach(listnode, current_semaphores) + { + // Get the current entry. + entry = (struct semid_ds *)listnode->value; + // If the entry is valid, check the id. + if (entry && (entry->semid == semid)) + return entry; + } + return NULL; +} + /// @brief for debugging purposes, print all the stats of the semid_ds /// @param temp the pointer to the semid struct void semid_print(struct semid_ds *temp) { + assert(temp && "Received NULL semid data structure."); + pr_debug("pid, IPC_KEY, Semid, semop, change: %d, %d, %d, %d, %d\n", temp->owner, temp->key, temp->semid, temp->sem_otime, temp->sem_ctime); for (int i = 0; i < (temp->sem_nsems); i++) { pr_debug("%d semaphore:\n", i + 1); @@ -80,11 +115,6 @@ void semid_print(struct semid_ds *temp) } } -/// @brief list of all current active semaphores -list_t *current_semaphores; - -int count_ipc_private = 2; //temporary -> to implement the IPC_PRIVATE mechanism - long sys_semget(key_t key, int nsems, int semflg) { struct semid_ds *temp = NULL; @@ -157,25 +187,16 @@ long sys_semget(key_t key, int nsems, int semflg) long sys_semop(int semid, struct sembuf *sops, unsigned nsops) { - int flag = 0; struct semid_ds *temp; - listnode_foreach(listnode, current_semaphores) - { //iterate through the list - if (((struct semid_ds *)listnode->value)->semid == semid) { //if we find a semid with the given key - flag = 1; - temp = ((struct semid_ds *)listnode->value); - break; - } - } - - if (!flag) { /*if the semid does not find a match then we set the errno and return -1*/ - errno = EINVAL; - return errno; + // Search for the semaphore. + temp = __find_semaphore(semid); + // If the semaphore is NULL, stop. + if (!temp) { + return -EINVAL; } if (sops->sem_num < 0 || sops->sem_num >= temp->sem_nsems) { //checking parameters - errno = EINVAL; - return -1; + return -EINVAL; } temp->sem_otime = sys_time(NULL); @@ -206,20 +227,12 @@ long sys_semop(int semid, struct sembuf *sops, unsigned nsops) long sys_semctl(int semid, int semnum, int cmd, union semun *arg) { - int flag = 0; struct semid_ds *temp; - listnode_foreach(listnode, current_semaphores) - { //iterate through the list - if (((struct semid_ds *)listnode->value)->semid == semid) { //if we find a semid with the given key - flag = 1; - temp = ((struct semid_ds *)listnode->value); - break; - } - } - - if (!flag) { /*if the semid does not find a match then we set the errno and return -1*/ - errno = EINVAL; - return -1; + // Search for the semaphore. + temp = __find_semaphore(semid); + // If the semaphore is NULL, stop. + if (!temp) { + return -EINVAL; } switch (cmd) { @@ -235,8 +248,7 @@ long sys_semctl(int semid, int semnum, int cmd, union semun *arg) //place a copy of the semid_ds data structure in the buffer pointed to by arg.buf. case IPC_STAT: if (arg->buf == NULL || arg->buf->sems == NULL) { /*checking the parameters*/ - errno = EINVAL; - return -1; + return -EINVAL; } //copying all the data @@ -262,13 +274,11 @@ long sys_semctl(int semid, int semnum, int cmd, union semun *arg) //the value of the semnum-th semaphore in the set is initialized to the value specified in arg.val. case SETVAL: if (semnum < 0 || semnum >= (temp->sem_nsems)) { //if the index is valid - errno = EINVAL; - return -1; + return -EINVAL; } if (arg->val < 0) { //checking if the value is valid - errno = ERANGE; - return -1; + return -EINVAL; } //setting the values temp->sem_ctime = sys_time(NULL); @@ -278,8 +288,7 @@ long sys_semctl(int semid, int semnum, int cmd, union semun *arg) //returns the value of the semnum-th semaphore in the set specified by semid; no argument required. case GETVAL: if (semnum < 0 || semnum >= (temp->sem_nsems)) { //if the index is valid - errno = EINVAL; - return -1; + return -EINVAL; } return temp->sems[semnum].sem_val; @@ -287,8 +296,7 @@ long sys_semctl(int semid, int semnum, int cmd, union semun *arg) //initialize all semaphore in the set referred to by semid, using the values supplied in the array pointed to by arg.array. case SETALL: if (arg->array == NULL) { /*checking parameters*/ - errno = EINVAL; - return -1; + return -EINVAL; } for (int i = 0; i < temp->sem_nsems; i++) { //setting all the values temp->sems[i].sem_val = arg->array[i]; @@ -299,8 +307,7 @@ long sys_semctl(int semid, int semnum, int cmd, union semun *arg) //retrieve the values of all of the semaphores in the set referred to by semid, placing them in the array pointed to by arg.array. case GETALL: if (arg->array == NULL) { //checking if the argument passed is valid - errno = EINVAL; - return -1; + return -EINVAL; } for (int i = 0; i < temp->sem_nsems; i++) { arg->array[i] = temp->sems[i].sem_val; @@ -310,8 +317,7 @@ long sys_semctl(int semid, int semnum, int cmd, union semun *arg) //return the process ID of the last process to perform a semop on the semnum-th semaphore. case GETPID: if (semnum < 0 || semnum >= (temp->sem_nsems)) { //if the index is valid - errno = EINVAL; - return -1; + return -EINVAL; } return temp->sems[semnum].sem_pid; @@ -319,16 +325,14 @@ long sys_semctl(int semid, int semnum, int cmd, union semun *arg) //return the number of processes currently waiting for the value of the semnum-th semaphore to become 0. case GETZCNT: if (semnum < 0 || semnum >= (temp->sem_nsems)) { //if the index is valid - errno = EINVAL; - return -1; + return -EINVAL; } return temp->sems[semnum].sem_zcnt; //not a valid argument. default: - errno = EINVAL; - return -1; + return -EINVAL; } return 0; diff --git a/programs/tests/t_semget.c b/programs/tests/t_semget.c index 2ad2712..9d503f3 100644 --- a/programs/tests/t_semget.c +++ b/programs/tests/t_semget.c @@ -6,7 +6,6 @@ #include "stdlib.h" #include "sys/unistd.h" - /* Testing Semaphores. This program creates a son and then performs a blocking operation on a semaphore. The son sleeps for @@ -14,68 +13,95 @@ five seconds and then it wakes up his father and then it deletes the semaphore. */ - -void semid_print(struct semid_ds *temp){ +void semid_print(struct semid_ds *temp) +{ printf("pid, IPC_KEY, Semid, semop, change: %d, %d, %d, %d, %d\n", temp->owner, temp->key, temp->semid, temp->sem_otime, temp->sem_ctime); - for(int i=0; i<(temp->sem_nsems); i++){ - printf("%d semaphore:\n", i+1); + for (int i = 0; i < (temp->sem_nsems); i++) { + printf("%d semaphore:\n", i + 1); printf("value: %d, pid %d, process waiting %d\n", temp->sems[i].sem_val, temp->sems[i].sem_pid, temp->sems[i].sem_zcnt); } } int main() -{ +{ + struct sembuf op; union semun arg; - arg.val = 1; - //key_t i = ftok("/test1.txt", 5); //checking ftok - long id = semget(2,1,IPC_CREAT); //first semaphores + long ret, id; + key_t key; + + // Checking if ftok works. + key = ftok("/home/user/test7.txt", 5); + printf("Key : %d\n", key); + + // Create the first semaphore. + id = semget(2, 1, IPC_CREAT); + printf("Id: %d\n", id); + //long id2 = semget(IPC_PRIVATE, 1, IPC_CREAT); //long id2 = semget(2, 2, IPC_EXCL); //need to return -1 bc already exists - //long id3 = semget(2, 2, 0); //need to return 3 (semid of the first) - //long id4 = semget(100, 2, IPC_CREAT | IPC_EXCL); //need to return 101 (new semaphore) - long value; - printf("ID: %d\n", id); - if ((value = semctl(id, 0, SETVAL, &arg)) == -1){ - printf("ERRORE\n"); - }else{ - //semid_print(arg.v); - printf("valore sem 0: %d \n", semctl(id, 0, GETVAL, &arg)); + + // Set the value of the semaphore in the structure. + arg.val = 1; + // Setting the semaphore value. + printf("Set Value (%d): %d\n", id, arg.val); + ret = semctl(id, 0, SETVAL, &arg); + if (ret == -1) { + perror("Failed to set value of semaphore."); + return 1; } + // Check if we successfully set the value of the semaphore. + ret = semctl(id, 0, GETVAL, &arg); + printf("Check Value (%d): %d\n", id, ret); - - if (!fork()){ + // Create child process. + if (!fork()) { + // Make the child process sleep. sleep(5); - struct sembuf op2; - op2.sem_num = 0; - op2.sem_op = 150; - op2.sem_flg = 0; - semop(id, &op2, 1); + // Initialize the operation structure. + op.sem_num = 0; // Operate on semaphore 0. + op.sem_op = 1; // Increment value by 1. + op.sem_flg = 0; // No flags. + + // This should allow the father process to decrement the semaphore by 2. + + // Perform the operation. + semop(id, &op, 1); + + // Remove the semaphore. semctl(id, 0, IPC_RMID, NULL); - exit(0); + // Exit with the child process. + return 0; } - struct sembuf op; - op.sem_num = 0; - op.sem_op = -1; - op.sem_flg = 0; - if (semop(id, &op, 2) < 0){ + // Initialize the operation structure. + op.sem_num = 0; // Operate on semaphore 0. + op.sem_op = -2; // Decrement value by 2. + op.sem_flg = 0; // No flags. + + // We set the semaphore at the beginning at 1, and the child process will + // increment the semaphore by 1, allowing us to decrement the semaphore by + // 2. + + // Perform the operation. + if (semop(id, &op, 1) < 0) { printf("ERRORE\n"); } - printf("valore sem 0: %d \n", semctl(id, 0, GETVAL, &arg)); - + // Check if we successfully set the value of the semaphore. + ret = semctl(id, 0, GETVAL, &arg); + printf("Check Value (%d): %d\n", id, ret); + /*if ((semid = semctl(id, 0, IPC_RMID, 0)) == -1){ printf("%d\n", errno); }else{ printf("found %d\n", semid); }*/ - //long id2 = semget(IPC_PRIVATE, 2, 0); //long id3 = semget(IPC_PRIVATE, 2, 0); //printf("id %d id2 %d id3 %d id4 %d\n", id, id2, id3, id4); @@ -83,7 +109,6 @@ int main() printf("Error with IPC_KEY\n"); return -1; }*/ - - + return 0; } \ No newline at end of file