Add some more comments. Implement sempahore search function. Check correctness of the current semaphore code, and it works as expected.

This commit is contained in:
Enrico Fraccaroli
2023-04-21 17:55:19 +02:00
parent bfe30f797a
commit 8ad4e45b50
4 changed files with 156 additions and 128 deletions
+4 -4
View File
@@ -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);
+2 -3
View File
@@ -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
+89 -85
View File
@@ -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;
+61 -36
View File
@@ -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;
}