diff --git a/libc/inc/ipc/sem.h b/libc/inc/ipc/sem.h index d2c9d73..5cf8dea 100644 --- a/libc/inc/ipc/sem.h +++ b/libc/inc/ipc/sem.h @@ -19,7 +19,7 @@ #define SEM_UNDO 0x1000 /* undo the operation on exit */ -/// #brief Commands for semctl +/// @brief Commands for semctl #define GETPID 11 /* get sempid */ #define GETVAL 12 /* get semval */ #define GETALL 13 /* get all semval's */ @@ -27,7 +27,7 @@ #define GETZCNT 15 /* get semzcnt */ #define SETVAL 16 /* set semval */ #define SETALL 17 /* set all semval's */ - +#define OPERATION_NOT_ALLOWED -18 /*return value for blocking operations on semaphores*/ @@ -101,7 +101,7 @@ long sys_semop(int semid, struct sembuf *sops, unsigned nsops); /// @param cmd the command to perform. /// @param arg /// @return 0 on success, -1 on failure and errno is set to indicate the error. -long sys_semctl(int semid, int semnum, int cmd, union semun arg); +long sys_semctl(int semid, int semnum, int cmd, union semun *arg); #else @@ -127,6 +127,6 @@ long semop(int semid, struct sembuf *sops, unsigned nsops); /// @param cmd the command to perform. /// @param arg /// @return 0 on success, -1 on failure and errno is set to indicate the error. -long semctl(int semid, int semnum, int cmd, union semun arg); +long semctl(int semid, int semnum, int cmd, union semun *arg); #endif diff --git a/libc/src/ipc/ipc.c b/libc/src/ipc/ipc.c index af82f51..4590579 100644 --- a/libc/src/ipc/ipc.c +++ b/libc/src/ipc/ipc.c @@ -26,9 +26,11 @@ _syscall3(long, shmctl, int, shmid, int, cmd, struct shmid_ds *, buf) _syscall3(long, semget, key_t, key, int, nsems, int, semflg) -_syscall3(long, semop, int, semid, struct sembuf *, sops, unsigned, nsops) -_syscall4(long, semctl, int, semid, int, semnum, int, cmd, unsigned long, arg) +//we are writing our own user-side semop function +//_syscall3(long, semop, int, semid, struct sembuf *, sops, unsigned, nsops) + +_syscall4(long, semctl, int, semid, int, semnum, int, cmd, union semun*, arg) _syscall2(long, msgget, key_t, key, int, msgflg) @@ -38,6 +40,28 @@ _syscall5(long, msgrcv, int, msqid, struct msgbuf *, msgp, size_t, msgsz, long, _syscall3(long, msgctl, int, msqid, int, cmd, struct msqid_ds *, buf) + +/*user-side semop*/ +long semop(int semid, struct sembuf *sops, unsigned nsops){ + long __res; + + if (nsops<=0 || sops == NULL){ //checking parameters + errno = EINVAL; + return -1; + } + + /*the process continues to try to perform the operation until it completes or receives an error*/ + while (1){ + //calling kernel-side function + __inline_syscall3(__res,semop, semid, sops, nsops); + + if (__res != OPERATION_NOT_ALLOWED)break; + } + + __syscall_return(long, __res); //returning the value +} + + key_t ftok(char *path, int id){ diff --git a/mentos/src/ipc/sem.c b/mentos/src/ipc/sem.c index 82272db..590fa0d 100644 --- a/mentos/src/ipc/sem.c +++ b/mentos/src/ipc/sem.c @@ -16,6 +16,7 @@ #include "system/signal.h" #include "sys/errno.h" #include "system/panic.h" +#include "time.h" /* 03/04 : at the moment we have various functions with their description (see comments). @@ -26,8 +27,18 @@ 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 : 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 int semid_assign = 0; @@ -47,8 +58,8 @@ void semid_init(struct semid_ds * temp, key_t key, int nsems){ temp -> owner = sys_getpid(); temp -> key = key; temp -> semid = ++semid_assign; //temporary -> gonna need a way to compute IPCKEY -> semid - temp -> sem_otime = 0; - temp -> sem_ctime = 0; + temp -> sem_otime = 0; /*default*/ + temp -> sem_ctime = 0; /*default*/ temp -> sem_nsems = nsems; temp -> sems = (struct sem*)kmalloc(sizeof(struct sem)*nsems); for (int i=0; isemid; - } + }*/ + + if (current_semaphores == NULL){ //if this is the first time that the function is called + current_semaphores = list_create(); //we initialize the list + } + if (key == IPC_PRIVATE){ // need to find a unique key int flag = 1; while (1){ //exit when i find a unique key @@ -120,7 +134,6 @@ long sys_semget(key_t key, int nsems, int semflg) } } if (flag==0){ //unique key - if (semflg & IPC_CREAT){ //and i want to create a semaphore set with it temp = (struct semid_ds *)kmalloc(sizeof(struct semid_ds)); semid_init(temp, key, nsems); @@ -141,28 +154,55 @@ long sys_semget(key_t key, int nsems, int semflg) long sys_semop(int semid, struct sembuf *sops, unsigned nsops) { - /* - Check if semid is a valid semaphore set identifier - */ - /* .... */ + 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; + } + } - /* - Handle the sembuf structure and perform the operation (spinlocks?) - */ - /* .... */ + if (!flag){ /*if the semid does not find a match then we set the errno and return -1*/ + errno = EINVAL; + return errno; + } - /* - Update the semaphores values - */ - /* .... */ + if (sops->sem_num<0 || sops->sem_num >= temp->sem_nsems){ //checking parameters + errno = EINVAL; + return -1; + } + temp -> sem_otime = sys_time(NULL); + + if (sops->sem_op < 0){ + /*If the operation is negative then we need to check for possible blocking operation*/ + + /*if the value of the sem were to become negative then we return a special value*/ + if (temp->sems[sops->sem_num].sem_val < (-nsops*(sops->sem_op))){ + return OPERATION_NOT_ALLOWED; //not allowed + }else{ + /*otherwise we can modify the sem_val and all the other parameters of the semaphore*/ + temp->sems[sops->sem_num].sem_val += (nsops*(sops->sem_op)); + temp->sems[sops->sem_num].sem_pid = sys_getpid(); + temp -> sem_ctime = sys_time(NULL); + return 1; //allowed + } + } + else{ + /*the operation is non negative so we can always do it*/ + temp->sems[sops->sem_num].sem_val += (nsops*(sops->sem_op)); + temp->sems[sops->sem_num].sem_pid = sys_getpid(); + temp -> sem_ctime = sys_time(NULL); + return 1; //allowed + } - //TODO("Not implemented"); return 0; } -long sys_semctl(int semid, int semnum, int cmd, union semun arg) +long sys_semctl(int semid, int semnum, int cmd, union semun *arg) { int flag = 0; struct semid_ds *temp; @@ -170,14 +210,14 @@ long sys_semctl(int semid, int semnum, int cmd, union semun arg) 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 (!flag){ /*if the semid does not find a match then we set the errno and return -1*/ errno = EINVAL; return -1; } - switch (cmd) { @@ -193,32 +233,50 @@ 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: - /* code */ - break; + if (arg->buf == NULL || arg->buf->sems == NULL){ /*checking the parameters*/ + errno = EINVAL; + return -1; + } + + //copying all the data + arg->buf->key = temp -> key; + arg->buf->owner = temp -> owner; + arg->buf->semid = temp -> semid; + arg->buf->sem_otime = temp -> sem_otime; + arg->buf->sem_ctime = temp -> sem_ctime; + arg->buf->sem_nsems = temp -> sem_nsems; + for(int i=0; isem_nsems; i++){ + arg->buf->sems[i].sem_val = temp->sems[i].sem_val; + arg->buf->sems[i].sem_pid = temp->sems[i].sem_pid; + arg->buf->sems[i].sem_zcnt = temp->sems[i].sem_zcnt; + } + + return 0; //update selected fields of the semid_ds using values in the buffer pointed to by arg.buf. - case IPC_SET: + //case IPC_SET: /* code */ - break; + //break; //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 - //printf("Errore semnum\n"); //debuggin purposes errno = EINVAL; return -1; } - if(arg.val<0){ + + if(arg->val<0){ //checking if the value is valid errno = ERANGE; return -1; } - temp->sems[semnum].sem_val = arg.val; + //setting the values + temp -> sem_ctime = sys_time(NULL); + temp->sems[semnum].sem_val = arg->val; return 0; //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 - //printf("Errore semnum\n"); //debuggin purposes errno = EINVAL; return -1; } @@ -227,18 +285,30 @@ 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: - /* code */ - break; + if (arg->array == NULL){ /*checking parameters*/ + errno = EINVAL; + return -1; + } + for (int i = 0; isem_nsems; i++){ //setting all the values + temp->sems[i].sem_val = arg->array[i]; + } + temp -> sem_ctime = sys_time(NULL); + return 0; //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: - /* code */ - break; + if (arg->array == NULL){ //checking if the argument passed is valid + errno = EINVAL; + return -1; + } + for (int i = 0; isem_nsems; i++){ + arg->array[i] = temp->sems[i].sem_val; + } + return 0; //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 - //printf("Errore semnum\n"); //debuggin purposes errno = EINVAL; return -1; } @@ -248,7 +318,6 @@ 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 - //printf("Errore semnum\n"); //debuggin purposes errno = EINVAL; return -1; } @@ -257,12 +326,10 @@ long sys_semctl(int semid, int semnum, int cmd, union semun arg) //not a valid argument. default: - //printf("defualt\n"); - errno = EINVAL; // + errno = EINVAL; return -1; } - //TODO("Not implemented"); return 0; } diff --git a/programs/tests/CMakeLists.txt b/programs/tests/CMakeLists.txt index 639b232..c19252b 100644 --- a/programs/tests/CMakeLists.txt +++ b/programs/tests/CMakeLists.txt @@ -86,6 +86,7 @@ set(TESTS t_itimer.c t_gid.c t_semget.c + t_sem1.c ) foreach(TEST ${TESTS}) diff --git a/programs/tests/t_sem1.c b/programs/tests/t_sem1.c new file mode 100644 index 0000000..31718be --- /dev/null +++ b/programs/tests/t_sem1.c @@ -0,0 +1,92 @@ +//test +#include "ipc/sem.h" +#include "stdio.h" +#include "ipc/ipc.h" +#include "sys/errno.h" +#include "sys/wait.h" +#include "stdlib.h" +#include "sys/unistd.h" + + +/* +First test of System V Semaphores. +Correct output should be: Corso di Sistemi Operativi. +*/ + + +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); + 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() +{ + union semun arg; + + struct sembuf sops[6]; + sops[0].sem_num = 0; + sops[0].sem_op = -1; + sops[0].sem_flg = 0; + + sops[1].sem_num = 1; + sops[1].sem_op = -1; + sops[1].sem_flg = 0; + + sops[2].sem_num = 2; + sops[2].sem_op = -1; + sops[2].sem_flg = 0; + + sops[3].sem_num = 0; + sops[3].sem_op = 1; + sops[3].sem_flg = 0; + + sops[4].sem_num = 1; + sops[4].sem_op = 1; + sops[4].sem_flg = 0; + + sops[5].sem_num = 2; + sops[5].sem_op = 1; + sops[5].sem_flg = 0; + + int status; + //create a semaphore set + int semid = semget(IPC_PRIVATE, 4, IPC_CREAT); + //set the values of the semaphores + unsigned short values[] = {0,0,0,1}; + arg.array = values; + if(semctl(semid,0,SETALL,&arg)==-1) + write(1,"errore set dei semafori",24); + + if(!fork()){ + semop(semid, &sops[0], 1); + write(1,"Operativi.\n", 11); + exit(0); + } + if(!fork()){ + semop(semid, &sops[1], 1); + write(1,"Sistemi ", 8); + semop(semid, &sops[3], 1); + exit(0); + } + if(!fork()){ + semop(semid, &sops[2], 1); + write(1," di ", 4); + semop(semid, &sops[4], 1); + exit(0); + } + if(!fork()){ + write(1,"Corso", 5); + semop(semid, &sops[5], 1); + exit(0); + } + for(int n=0; n<4; n++){ + wait(&status); + } + + if(semctl(semid,0,IPC_RMID,0)==-1) + write(1,"err", 3); + return 0; +} \ No newline at end of file diff --git a/programs/tests/t_semget.c b/programs/tests/t_semget.c index 20b79ce..2ad2712 100644 --- a/programs/tests/t_semget.c +++ b/programs/tests/t_semget.c @@ -3,15 +3,32 @@ #include "stdio.h" #include "ipc/ipc.h" #include "sys/errno.h" +#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 +five seconds and then it wakes up his father and then it deletes the semaphore. + +*/ + + +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); + 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() { union semun arg; - arg.val = 150; + arg.val = 1; //key_t i = ftok("/test1.txt", 5); //checking ftok - long id = semget(2,2,0); //first semaphores + long id = semget(2,1,IPC_CREAT); //first semaphores //long id2 = semget(IPC_PRIVATE, 1, IPC_CREAT); //long id2 = semget(2, 2, IPC_EXCL); //need to return -1 bc already exists @@ -19,13 +36,39 @@ int main() //long id4 = semget(100, 2, IPC_CREAT | IPC_EXCL); //need to return 101 (new semaphore) long value; - - if ((value = semctl(id, 1, SETVAL, arg)) == -1){ - printf("%d \n", value); + printf("ID: %d\n", id); + if ((value = semctl(id, 0, SETVAL, &arg)) == -1){ + printf("ERRORE\n"); }else{ - printf("getpid: %d\n", value); + //semid_print(arg.v); + printf("valore sem 0: %d \n", semctl(id, 0, GETVAL, &arg)); } + + + if (!fork()){ + sleep(5); + struct sembuf op2; + op2.sem_num = 0; + op2.sem_op = 150; + op2.sem_flg = 0; + semop(id, &op2, 1); + + semctl(id, 0, IPC_RMID, NULL); + + exit(0); + } + + struct sembuf op; + op.sem_num = 0; + op.sem_op = -1; + op.sem_flg = 0; + if (semop(id, &op, 2) < 0){ + printf("ERRORE\n"); + } + printf("valore sem 0: %d \n", semctl(id, 0, GETVAL, &arg)); + + /*if ((semid = semctl(id, 0, IPC_RMID, 0)) == -1){ printf("%d\n", errno); }else{