Merge branch 'feature/Feature-Semaphores' into develop

This commit is contained in:
Enrico Fraccaroli (Galfurian)
2023-06-02 13:50:20 -04:00
46 changed files with 1767 additions and 332 deletions
+4 -1
View File
@@ -116,4 +116,7 @@ src/initscp/initfscp
files/bin/**
# ISO creation files.
iso/boot/*.bin
iso/boot/*.bin
# ClangD stuff.
.cache
-6
View File
@@ -1,6 +0,0 @@
{
"files.associations": {
"*.h": "c",
"*.c": "c"
},
}
+5
View File
@@ -0,0 +1,5 @@
SYNOPSIS
ipcs [options]
DESCRIPTION
Ipcs shows information on System V inter-process communication facilities.
+1 -1
View File
@@ -100,7 +100,7 @@ add_library(
${PROJECT_SOURCE_DIR}/src/io/mm_io.c
${PROJECT_SOURCE_DIR}/src/io/port_io.c
${PROJECT_SOURCE_DIR}/src/io/debug.c
${PROJECT_SOURCE_DIR}/src/ipc/ipc.c
${PROJECT_SOURCE_DIR}/src/sys/ipc.c
${PROJECT_SOURCE_DIR}/src/sys/unistd.c
${PROJECT_SOURCE_DIR}/src/sys/errno.c
${PROJECT_SOURCE_DIR}/src/sys/utsname.c
+12 -12
View File
@@ -22,18 +22,18 @@
#define S_ISUID 0x0800 ///< Set user id on execution
#define S_ISGID 0x0400 ///< Set group id on execution
#define S_ISVTX 0x0200 ///< Save swapped text even after use (Sticky Bit)
#define S_IRWXU 0x01C0 ///< rwx------- : User can read/write/execute
#define S_IRUSR 0x0100 ///< -r-------- : User can read
#define S_IWUSR 0x0080 ///< --w------- : User can write
#define S_IXUSR 0x0040 ///< ---x------ : User can execute
#define S_IRWXG 0x0038 ///< ----rwx--- : Group can read/write/execute
#define S_IRGRP 0x0020 ///< ----r----- : Group can read
#define S_IWGRP 0x0010 ///< -----w---- : Group can write
#define S_IXGRP 0x0008 ///< ------x--- : Group can execute
#define S_IRWXO 0x0007 ///< -------rwx : Others can read/write/execute
#define S_IROTH 0x0004 ///< -------r-- : Others can read
#define S_IWOTH 0x0002 ///< --------w- : Others can write
#define S_IXOTH 0x0001 ///< ---------x : Others can execute
#define S_IRWXU 0x01C0 ///< rwx------ : User can read/write/execute
#define S_IRUSR 0x0100 ///< r-------- : User can read
#define S_IWUSR 0x0080 ///< -w------- : User can write
#define S_IXUSR 0x0040 ///< --x------ : User can execute
#define S_IRWXG 0x0038 ///< ---rwx--- : Group can read/write/execute
#define S_IRGRP 0x0020 ///< ---r----- : Group can read
#define S_IWGRP 0x0010 ///< ----w---- : Group can write
#define S_IXGRP 0x0008 ///< -----x--- : Group can execute
#define S_IRWXO 0x0007 ///< ------rwx : Others can read/write/execute
#define S_IROTH 0x0004 ///< ------r-- : Others can read
#define S_IWOTH 0x0002 ///< -------w- : Others can write
#define S_IXOTH 0x0001 ///< --------x : Others can execute
#define S_ISDIR(m) (((m)&0170000) == 0040000) ///< directory.
#define S_ISCHR(m) (((m)&0170000) == 0020000) ///< char special
-24
View File
@@ -1,24 +0,0 @@
/// @file ipc.h
/// @brief Inter-Process Communication (IPC) structures.
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#pragma once
/// @brief Permission details of an IPC object.
struct ipc_perm {
/// Key supplied to msgget(2).
key_t __key;
/// Effective UID of owner.
uid_t uid;
/// Effective GID of owner.
gid_t gid;
/// Effective UID of creator.
uid_t cuid;
/// Effective GID of creator.
gid_t cgid;
/// Permissions.
unsigned short mode;
/// Sequence number.
unsigned short __seq;
};
+1 -1
View File
@@ -127,4 +127,4 @@ int fscanf(int fd, const char *fmt, ...);
/// @brief Prints a system error message.
/// @param s the message we prepend to the actual error message.
void perror(const char *s);
void perror(const char *s);
+15 -11
View File
@@ -5,6 +5,8 @@
#pragma once
#ifndef __KERNEL__
#include "stddef.h"
#define EXIT_SUCCESS 0 ///< Successful execution of a program.
@@ -41,17 +43,6 @@ void *realloc(void *ptr, size_t size);
/// @param ptr The pointer to the allocated memory.
void free(void *ptr);
/// The maximum value returned by the rand function.
#define RAND_MAX ((1U << 31U) - 1U)
/// @brief Allows to set the seed of the random value generator.
/// @param x The new seed.
void srand(int x);
/// @brief Generates a random value.
/// @return The random value.
int rand();
/// @brief Cause an abnormal program termination with core-dump.
void abort();
@@ -71,3 +62,16 @@ int unsetenv(const char *name);
/// @param name Name of the variable.
/// @return A pointer to the value, or NULL if there is no match.
char *getenv(const char *name);
#endif
/// The maximum value returned by the rand function.
#define RAND_MAX ((1U << 31U) - 1U)
/// @brief Allows to set the seed of the random value generator.
/// @param x The new seed.
void srand(int x);
/// @brief Generates a random value.
/// @return The random value.
int rand();
+1 -1
View File
@@ -20,7 +20,7 @@ extern int *__geterrno();
#define ENOEXEC 8 ///< Exec format error.
#define EBADF 9 ///< Bad file number.
#define ECHILD 10 ///< No child processes.
#define EAGAIN 11 ///< Try again.
#define EAGAIN 11 ///< Resource temporarily unavailable.
#define ENOMEM 12 ///< Out of memory.
#define EACCES 13 ///< Permission denied.
#define EFAULT 14 ///< Bad address.
+43
View File
@@ -0,0 +1,43 @@
/// @file ipc.h
/// @brief Inter-Process Communication (IPC) structures.
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#pragma once
#include "sys/types.h"
#include "stddef.h"
#define IPC_CREAT 01000 ///< Create key if key does not exist.
#define IPC_EXCL 02000 ///< Fail if key exists.
#define IPC_NOWAIT 04000 ///< Return error on wait.
#define IPC_RMID 0 ///< Remove identifier.
#define IPC_SET 1 ///< Set `ipc_perm' options.
#define IPC_STAT 2 ///< Get `ipc_perm' options.
#define IPC_INFO 3 ///< See ipcs.
#define IPC_PRIVATE ((key_t)0) ///< assures getting a new ipc_key.
/// @brief Permission details of an IPC object.
struct ipc_perm {
/// Key associated to the IPC.
key_t key;
/// Effective UID of owner.
uid_t uid;
/// Effective GID of owner.
gid_t gid;
/// Effective UID of creator.
uid_t cuid;
/// Effective GID of creator.
gid_t cgid;
/// Permissions.
unsigned short mode;
/// Sequence number.
unsigned short __seq;
};
/// @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 -1
View File
@@ -5,10 +5,11 @@
#pragma once
#include "sys/ipc.h"
#include "sys/types.h"
#include "stddef.h"
#include "time.h"
#include "ipc.h"
/// Type for storing the number of messages in a message queue.
typedef unsigned int msgqnum_t;
+69 -6
View File
@@ -6,22 +6,85 @@
#pragma once
#include "sys/types.h"
#include "sys/ipc.h"
#include "stddef.h"
#include "time.h"
#include "ipc.h"
#define SEM_UNDO 0x1000 ///< Undo the operation on exit.
/// @defgroup SemaphoreCommands semctl commands
/// @brief List of commands for semctl function.
/// @{
#define GETPID 11 ///< Get sempid.
#define GETVAL 12 ///< Get semval.
#define GETALL 13 ///< Get all semval's.
#define GETNCNT 14 ///< Get semncnt.
#define GETZCNT 15 ///< Get semzcnt.
#define SETVAL 16 ///< Set semval.
#define SETALL 17 ///< Set all semval's.
#define SEM_STAT 18 ///< Return a semid_ds structure.
#define SEM_INFO 19 ///< Return a seminfo structure.
/// }@
#define SEM_SET_MAX 256
/// @brief Optional argument for semctl() function
union semun {
/// @brief Value for SETVAL.
int val;
/// @brief Buffer for IPC_STAT & IPC_SET.
struct semid_ds *buf;
/// @brief Array for GETALL & SETALL.
unsigned short *array;
/// @brief Buffer for IPC_INFO.
struct seminfo *__buf;
};
/// @brief Single Semaphore.
struct sem {
/// @brief Process ID of the last operation.
pid_t sem_pid;
/// @brief Semaphore Value.
unsigned short sem_val;
/// @brief Number of processes waiting for the semaphore.
unsigned short sem_ncnt;
/// @brief Number of processes waiting for the value to become 0
unsigned short sem_zcnt;
};
/// @brief Semaphore set
struct semid_ds {
/// @brief Ownership and permissions.
struct ipc_perm sem_perm;
/// @brief Last semop time.
time_t sem_otime;
/// @brief Last change time.
time_t sem_ctime;
/// @brief List of all the semaphores.
struct sem *sem_base;
/// @brief Number of semaphores in set.
unsigned short sem_nsems;
};
/// @brief Buffer to use with the semaphore IPC.
struct sembuf {
/// Semaphore index in array.
/// @brief Semaphore index in array.
unsigned short sem_num;
/// Semaphore operation.
/// @brief Semaphore operation.
short sem_op;
/// Operation flags.
/// @brief Operation flags.
short sem_flg;
};
#ifdef __KERNEL__
/// @brief Initializes the semaphore system.
/// @return int
int sem_init();
/// @brief Get a System V semaphore set identifier.
/// @param key can be used either to obtain the identifier of a previously
/// created semaphore set, or to create a new set.
@@ -44,7 +107,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, unsigned long arg);
long sys_semctl(int semid, int semnum, int cmd, union semun *arg);
#else
@@ -70,6 +133,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, unsigned long arg);
long semctl(int semid, int semnum, int cmd, union semun *arg);
#endif
+2 -2
View File
@@ -5,10 +5,11 @@
#pragma once
#include "sys/ipc.h"
#include "sys/types.h"
#include "stddef.h"
#include "time.h"
#include "ipc.h"
/// Data type for storing the number of attaches.
typedef unsigned long shmatt_t;
@@ -39,7 +40,6 @@ struct shmid_ds {
#if 0
#include "ipc.h"
#include "debug.h"
#include "time.h"
#include "kheap.h"
-35
View File
@@ -1,35 +0,0 @@
/// @file ipc.c
/// @brief Inter-Process Communication (IPC) system call implementation.
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#include "sys/unistd.h"
#include "system/syscall_types.h"
#include "sys/errno.h"
#include "stddef.h"
#include "ipc/sem.h"
#include "ipc/shm.h"
#include "ipc/msg.h"
_syscall3(void *, shmat, int, shmid, const void *, shmaddr, int, shmflg)
_syscall3(long, shmget, key_t, key, size_t, size, int, flag)
_syscall1(long, shmdt, const void *, shmaddr)
_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)
_syscall2(long, msgget, key_t, key, int, msgflg)
_syscall4(long, msgsnd, int, msqid, struct msgbuf *, msgp, size_t, msgsz, int, msgflg)
_syscall5(long, msgrcv, int, msqid, struct msgbuf *, msgp, size_t, msgsz, long, msgtyp, int, msgflg)
_syscall3(long, msgctl, int, msqid, int, cmd, struct msqid_ds *, buf)
+3 -1
View File
@@ -216,4 +216,6 @@ void perror(const char *s)
putchar(' ');
}
puts(strerror(errno));
}
puts("\n");
puts("\n");
}
+1 -1
View File
@@ -76,7 +76,7 @@ char *strerror(int errnum)
#endif
#ifdef EAGAIN
case EAGAIN:
strcpy(error, "No more processes");
strcpy(error, "Resource temporarily unavailable");
break;
#endif
#ifdef ENOMEM
+104
View File
@@ -0,0 +1,104 @@
/// @file ipc.c
/// @brief Inter-Process Communication (IPC) system call implementation.
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#include "sys/unistd.h"
#include "sys/errno.h"
#include "sys/stat.h"
#include "sys/sem.h"
#include "sys/shm.h"
#include "sys/msg.h"
#include "system/syscall_types.h"
#include "stddef.h"
#include "string.h"
#include "io/debug.h"
#include "stdio.h"
#include "stdlib.h"
#include "io/debug.h"
#include "stdio.h"
_syscall3(void *, shmat, int, shmid, const void *, shmaddr, int, shmflg)
_syscall3(long, shmget, key_t, key, size_t, size, int, flag)
_syscall1(long, shmdt, const void *, shmaddr)
_syscall3(long, shmctl, int, shmid, int, cmd, struct shmid_ds *, buf)
_syscall3(long, semget, key_t, key, int, nsems, int, semflg)
_syscall4(long, semctl, int, semid, int, semnum, int, cmd, union semun *, arg)
_syscall2(long, msgget, key_t, key, int, msgflg)
_syscall4(long, msgsnd, int, msqid, struct msgbuf *, msgp, size_t, msgsz, int, msgflg)
_syscall5(long, msgrcv, int, msqid, struct msgbuf *, msgp, size_t, msgsz, long, msgtyp, int, msgflg)
_syscall3(long, msgctl, int, msqid, int, cmd, struct msqid_ds *, buf)
long semop(int semid, struct sembuf *sops, unsigned nsops)
{
struct sembuf *op;
long __res;
// The pointer to the operation is NULL.
if (!sops) {
pr_err("The pointer to the operation is NULL.\n");
errno = EINVAL;
return -1;
}
// The value of nsops is negative.
if (nsops <= 0) {
pr_err("The value of nsops is negative.\n");
errno = EINVAL;
return -1;
}
// This should be performed for each sops.
for (size_t i = 0; i < nsops; i++) {
// Get the operation.
op = &sops[i];
// The process continues to try to perform the operation until it completes
// or receives an error.
while (1) {
// Calling the kernel-side function.
__inline_syscall3(__res, semop, semid, op, 1);
// If we get an error, the operation has been taken care of we stop
// the loop. We also stop the loop if the operation is not allowed
// and the IPC_NOWAIT flag is 1
if ((__res != -EAGAIN) || (op->sem_flg & IPC_NOWAIT))
break;
}
// If the operation couldn't be performed and we had the IPC_NOWAIT set
// to 1 then we return.
if ((__res == -EAGAIN) && (op->sem_flg & IPC_NOWAIT)) {
errno = EAGAIN;
return -1;
}
}
// Now, we can return the value.
__syscall_return(long, __res);
}
key_t ftok(char *path, int id)
{
// Create a struct containing the serial number and the device number of the
// file we use to generate the key.
struct stat_t st;
if (stat(path, &st) < 0) {
pr_err("Cannot stat the file `%s`...\n", path);
errno = ENOENT;
return -1;
}
// Taking the upper 8 bits from the lower 8 bits of id, the second upper 8
// bits from the lower 8 bits of the device number of the provided pathname,
// and the lower 16 bits from the lower 16 bits of the inode number of the
// provided pathname.
return (st.st_ino & 0xffff) | ((st.st_dev & 0xff) << 16) | ((id & 0xffu) << 24);
}
+3
View File
@@ -129,7 +129,9 @@ set(KERNEL_SOURCES
${PROJECT_SOURCE_DIR}/src/io/proc_running.c
${PROJECT_SOURCE_DIR}/src/io/proc_feedback.c
${PROJECT_SOURCE_DIR}/src/io/proc_system.c
${PROJECT_SOURCE_DIR}/src/io/proc_ipc.c
${PROJECT_SOURCE_DIR}/src/io/vga/vga.c
${PROJECT_SOURCE_DIR}/src/ipc/ipc.c
${PROJECT_SOURCE_DIR}/src/ipc/msg.c
${PROJECT_SOURCE_DIR}/src/ipc/sem.c
${PROJECT_SOURCE_DIR}/src/ipc/shm.c
@@ -146,6 +148,7 @@ set(KERNEL_SOURCES
${PROJECT_SOURCE_DIR}/src/klib/math.c
${PROJECT_SOURCE_DIR}/src/klib/fcvt.c
${PROJECT_SOURCE_DIR}/src/klib/spinlock.c
${PROJECT_SOURCE_DIR}/src/klib/stdlib.c
${PROJECT_SOURCE_DIR}/src/klib/rbtree.c
${PROJECT_SOURCE_DIR}/src/klib/ndtree.c
${PROJECT_SOURCE_DIR}/src/klib/hashmap.c
+6
View File
@@ -15,4 +15,10 @@ int procv_module_init();
/// @return 0 on success, 1 on failure.
int procs_module_init();
/// @brief Initializes the scheduler feedback system.
/// @return 0 on success, 1 on failure.
int procfb_module_init();
/// @brief Initializes the IPC information system.
/// @return 0 on success, 1 on failure.
int procipc_module_init();
+16
View File
@@ -0,0 +1,16 @@
/// @file ipc.h
/// @brief Vital IPC structures and functions kernel side.
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#pragma once
#include "sys/ipc.h"
#ifndef __KERNEL__
#error "How did you include this file... include `libc/inc/sys/ipc.h` instead!"
#endif
int ipc_valid_permissions(int flags, struct ipc_perm *perm);
struct ipc_perm register_ipc(key_t key, mode_t mode);
-34
View File
@@ -1,34 +0,0 @@
/// @file ipc.h
/// @brief
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#pragma once
#include "stddef.h"
#define IPC_CREAT 01000 ///< Create key if key does not exist.
#define IPC_EXCL 02000 ///< Fail if key exists.
#define IPC_NOWAIT 04000 ///< Return error on wait.
#define IPC_RMID 0 ///< Remove identifier.
#define IPC_SET 1 ///< Set `ipc_perm' options.
#define IPC_STAT 2 ///< Get `ipc_perm' options.
#define IPC_INFO 3 ///< See ipcs.
/// @brief Holds details about IPCs.
typedef struct ipc_perm_t {
/// Creator user id.
uid_t cuid;
/// Creator group id.
gid_t cgid;
/// User id.
uid_t uid;
/// Group id.
gid_t gid;
/// r/w permission.
ushort mode;
/// Sequence # (to generate unique msg/sem/shm id).
ushort seq;
/// User specified msg/sem/shm key.
key_t key;
} ipc_perm_t;
+5 -4
View File
@@ -437,13 +437,14 @@ static inline uint8_t ata_status_wait(ata_device_t *dev, int timeout)
uint8_t status;
if (timeout > 0) {
while (timeout--) {
if (!bit_check((status = inportb(dev->io_reg.status)), ata_status_bsy))
status = inportb(dev->io_reg.status);
if (!bit_check(status, ata_status_bsy))
break;
}
} else {
while (bit_check((status = inportb(dev->io_reg.status)), ata_status_bsy)) {
cpu_relax();
}
do {
status = inportb(dev->io_reg.status);
} while (bit_check(status, ata_status_bsy));
}
return status;
}
+68 -58
View File
@@ -4,10 +4,10 @@
/// See LICENSE.md for details.
// Setup the logging for this file (do this before any other include).
#include "sys/kernel_levels.h" // Include kernel log levels.
#define __DEBUG_HEADER__ "[EXT2 ]" ///< Change header.
#include "sys/kernel_levels.h" // Include kernel log levels.
#define __DEBUG_HEADER__ "[EXT2 ]" ///< Change header.
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level.
#include "io/debug.h" // Include debugging functions.
#include "io/debug.h" // Include debugging functions.
#include "fs/ext2.h"
#include "process/scheduler.h"
@@ -478,46 +478,52 @@ static const char *time_to_string(uint32_t time)
return s;
}
static inline int __ext2_valid_permissions(
const task_struct *task,
const mode_t mask,
const uid_t uid,
const gid_t gid,
const int usr,
const int grp,
const int oth)
{
// The task is the owner.
if ((mask & usr) && (task->uid == uid))
return 1;
// The task belongs to the correct group.
if ((mask & grp) && (task->gid == gid))
return 1;
// The task is not the owner and does not belong to the correct group.
if ((mask & oth) && (task->uid != uid) && (task->gid != gid))
return 1;
return 0;
}
/// @brief Checks if the requests in flags are valid.
/// @param flags the flags to check.
/// @param mask the mask to check against.
/// @param uid the uid of the owner.
/// @param gid the gid of the owner.
/// @return true on success, false otherwise.
static bool_t ext2_valid_permissions(int flags, mode_t mask, uid_t uid, gid_t gid)
/// @return 1 on success, 0 otherwise.
static int ext2_valid_permissions(int flags, mode_t mask, uid_t uid, gid_t gid)
{
// Check the permissions.
task_struct *task = scheduler_get_current_process();
if (task == NULL) {
pr_warning("Failed to get the current running process, assuming we are booting.\n");
return true;
return 1;
}
// The current task is the owner.
if (task->uid == uid) {
if (!bitmask_check(mask, S_IRUSR))
return false;
if (bitmask_check(flags, O_WRONLY) && !bitmask_check(mask, S_IWUSR))
return false;
if (bitmask_check(flags, O_RDWR) && (!bitmask_check(mask, S_IRUSR) || !bitmask_check(mask, S_IWUSR)))
return false;
}
if (task->gid == gid) {
if (!bitmask_check(mask, S_IRGRP))
return false;
if (bitmask_check(flags, O_WRONLY) && !bitmask_check(mask, S_IWGRP))
return false;
if (bitmask_check(flags, O_RDWR) && (!bitmask_check(mask, S_IRGRP) || !bitmask_check(mask, S_IWGRP)))
return false;
}
if ((task->uid != uid) && (task->gid != gid)) {
if (!bitmask_check(mask, S_IROTH))
return false;
if (bitmask_check(flags, O_WRONLY) && !bitmask_check(mask, S_IWOTH))
return false;
if (bitmask_check(flags, O_RDWR) && (!bitmask_check(mask, S_IROTH) || !bitmask_check(mask, S_IWOTH)))
return false;
}
return true;
// Init, and all root processes have full permissions.
if ((task->pid == 0) || (task->uid == 0) || (task->gid == 0))
return 1;
if (((flags & O_RDONLY) == O_RDONLY) && __ext2_valid_permissions(task, mask, uid, gid, S_IRUSR, S_IRGRP, S_IROTH))
return 1;
if (((flags & O_WRONLY) == O_WRONLY) && __ext2_valid_permissions(task, mask, uid, gid, S_IWUSR, S_IWGRP, S_IWOTH))
return 1;
if (((flags & O_RDWR) == O_RDWR) && __ext2_valid_permissions(task, mask, uid, gid, S_IRUSR | S_IWUSR, S_IRGRP | S_IWGRP, S_IROTH | S_IWOTH))
return 1;
return 0;
}
/// @brief Dumps on debugging output the superblock.
@@ -756,12 +762,12 @@ static void ext2_set_bitmap_bit(uint8_t *buffer, uint32_t linear_index, ext2_blo
/// @param fs the ext2 filesystem structure.
/// @param cache the cache from which we read the bgdt data.
/// @param linear_index the output variable where we store the linear indes to the free inode.
/// @return true if we found a free inode, false otherwise.
static inline bool_t ext2_find_free_inode_in_group(
/// @return 1 if we found a free inode, 0 otherwise.
static inline int ext2_find_free_inode_in_group(
ext2_filesystem_t *fs,
uint8_t *cache,
uint32_t *linear_index,
bool_t skip_reserved)
int skip_reserved)
{
for ((*linear_index) = 0; (*linear_index) < fs->superblock.inodes_per_group; ++(*linear_index)) {
// If we need to skip the reserved inodes, we skip the round if the
@@ -770,9 +776,9 @@ static inline bool_t ext2_find_free_inode_in_group(
continue;
// Check if the entry is free.
if (!ext2_check_bitmap_bit(cache, *linear_index))
return true;
return 1;
}
return false;
return 0;
}
/// @brief Searches for a free inode inside the Block Group Descriptor Table (BGDT).
@@ -780,8 +786,8 @@ static inline bool_t ext2_find_free_inode_in_group(
/// @param cache the cache from which we read the bgdt data.
/// @param group_index the output variable where we store the group index.
/// @param linear_index the output variable where we store the linear indes to the free inode.
/// @return true if we found a free inode, false otherwise.
static inline bool_t ext2_find_free_inode(
/// @return 1 if we found a free inode, 0 otherwise.
static inline int ext2_find_free_inode(
ext2_filesystem_t *fs,
uint8_t *cache,
uint32_t *group_index,
@@ -795,7 +801,7 @@ static inline bool_t ext2_find_free_inode(
// Find the first free inode. We need to ask to skip reserved inodes,
// only if we are in group 0.
if (ext2_find_free_inode_in_group(fs, cache, linear_index, (*group_index) == 0))
return true;
return 1;
}
// Get the group and bit index of the first free block.
for ((*group_index) = 0; (*group_index) < fs->block_groups_count; ++(*group_index)) {
@@ -804,15 +810,15 @@ static inline bool_t ext2_find_free_inode(
// Read the block bitmap.
if (ext2_read_block(fs, fs->block_groups[(*group_index)].inode_bitmap, cache) < 0) {
pr_err("Failed to read the inode bitmap for group `%d`.\n", (*group_index));
return false;
return 0;
}
// Find the first free inode. We need to ask to skip reserved
// inodes, only if we are in group 0.
if (ext2_find_free_inode_in_group(fs, cache, linear_index, (*group_index) == 0))
return true;
return 1;
}
}
return false;
return 0;
}
/// @brief Searches for a free block inside the group data loaded inside the cache.
@@ -820,23 +826,23 @@ static inline bool_t ext2_find_free_inode(
/// @param cache the cache from which we read the bgdt data.
/// @param group_index the output variable where we store the group index.
/// @param linear_index the output variable where we store the linear indes to the free block.
/// @return true if we found a free block, false otherwise.
static inline bool_t ext2_find_free_block_in_group(ext2_filesystem_t *fs, uint8_t *cache, uint32_t *linear_index)
/// @return 1 if we found a free block, 0 otherwise.
static inline int ext2_find_free_block_in_group(ext2_filesystem_t *fs, uint8_t *cache, uint32_t *linear_index)
{
for ((*linear_index) = 0; (*linear_index) < fs->superblock.blocks_per_group; ++(*linear_index)) {
// Check if the entry is free.
if (!ext2_check_bitmap_bit(cache, *linear_index))
return true;
return 1;
}
return false;
return 0;
}
/// @brief Searches for a free block.
/// @param fs the ext2 filesystem structure.
/// @param cache the cache from which we read the bgdt data.
/// @param linear_index the output variable where we store the linear indes to the free block.
/// @return true if we found a free block, false otherwise.
static inline bool_t ext2_find_free_block(
/// @return 1 if we found a free block, 0 otherwise.
static inline int ext2_find_free_block(
ext2_filesystem_t *fs,
uint8_t *cache,
uint32_t *group_index,
@@ -849,14 +855,14 @@ static inline bool_t ext2_find_free_block(
// Read the block bitmap.
if (ext2_read_block(fs, fs->block_groups[(*group_index)].block_bitmap, cache) < 0) {
pr_err("Failed to read the block bitmap for group `%d`.\n", (*group_index));
return false;
return 0;
}
// Find the first free block.
if (ext2_find_free_block_in_group(fs, cache, linear_index))
return true;
return 1;
}
}
return false;
return 0;
}
/// @brief Reads the superblock from the block device associated with this filesystem.
@@ -1614,8 +1620,8 @@ ext2_dirent_t *ext2_direntry_iterator_get(ext2_direntry_iterator_t *iterator)
/// @brief Check if the iterator is valid.
/// @param iterator the iterator to check.
/// @return true if valid, false otherwise.
bool_t ext2_direntry_iterator_valid(ext2_direntry_iterator_t *iterator)
/// @return 1 if valid, 0 otherwise.
int ext2_direntry_iterator_valid(ext2_direntry_iterator_t *iterator)
{
return iterator->direntry != NULL;
}
@@ -1679,14 +1685,14 @@ void ext2_direntry_iterator_next(ext2_direntry_iterator_t *iterator)
iterator->direntry = ext2_direntry_iterator_get(iterator);
}
static inline bool_t ext2_directory_is_empty(ext2_filesystem_t *fs, uint8_t *cache, ext2_inode_t *inode)
static inline int ext2_directory_is_empty(ext2_filesystem_t *fs, uint8_t *cache, ext2_inode_t *inode)
{
ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, inode);
for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it)) {
if (it.direntry->inode != 0)
return false;
return 0;
}
return true;
return 1;
}
// ============================================================================
@@ -2344,6 +2350,7 @@ static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode)
pr_err("A file or directory already exists at `%s` (O_CREAT | O_EXCL).\n", absolute_path);
return NULL;
} else if (bitmask_check(flags, O_DIRECTORY) && (direntry.file_type != ext2_file_type_directory)) {
pr_err("That is not a directory.");
errno = ENOTDIR;
return NULL;
}
@@ -2366,7 +2373,10 @@ static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode)
return NULL;
}
ext2_dump_inode(&inode);
if (!ext2_valid_permissions(flags, inode.mode, inode.uid, inode.gid)) {
pr_err("Task does not have access permission.\n");
errno = EACCES;
return NULL;
}
@@ -2664,7 +2674,7 @@ static ssize_t ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_
return -ENOENT;
}
uint32_t current = 0;
ssize_t written = 0;
ssize_t written = 0;
// Allocate the cache.
uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL);
// Clean the cache.
+10 -10
View File
@@ -736,7 +736,7 @@ static inline ssize_t procfs_getdents(vfs_file_t *file, dirent_t *dirp, off_t do
// Advance the size we just iterated.
iterated_size += sizeof(dirent_t);
// Check if the iterated size is still below the offset.
if (iterated_size < doff) {
if (iterated_size <= doff) {
continue;
}
// Check if the last character of the entry is a slash.
@@ -851,14 +851,14 @@ proc_dir_entry_t *proc_mkdir(const char *name, proc_dir_entry_t *parent)
strcat(entry_path, name);
// Check if the entry exists.
if (procfs_find_entry_path(entry_path) != NULL) {
pr_err("proc_destroy_entry(%s): Proc entry already exists.\n", entry_path);
pr_err("proc_mkdir(%s): Proc entry already exists.\n", entry_path);
errno = EEXIST;
return NULL;
}
// Create the new procfs file.
procfs_file_t *procfs_file = procfs_create_file(entry_path, DT_DIR);
if (!procfs_file) {
pr_err("proc_destroy_entry(%s): Cannot create proc entry.\n", entry_path);
pr_err("proc_mkdir(%s): Cannot create proc entry.\n", entry_path);
errno = ENFILE;
return NULL;
}
@@ -877,25 +877,25 @@ int proc_rmdir(const char *name, proc_dir_entry_t *parent)
// Check if the entry exists.
procfs_file_t *procfs_file = procfs_find_entry_path(entry_path);
if (procfs_file == NULL) {
pr_err("proc_destroy_entry(%s): Cannot find proc entry.\n", entry_path);
pr_err("proc_rmdir(%s): Cannot find proc entry.\n", entry_path);
return -ENOENT;
}
if ((procfs_file->flags & DT_DIR) == 0) {
pr_err("proc_destroy_entry(%s): Proc entry is not a directory.\n", entry_path);
pr_err("proc_rmdir(%s): Proc entry is not a directory.\n", entry_path);
return -ENOTDIR;
}
// Check if its empty.
if (procfs_check_if_empty(procfs_file->name)) {
pr_err("procfs_rmdir(%s): The directory is not empty.\n", entry_path);
pr_err("proc_rmdir(%s): The directory is not empty.\n", entry_path);
return -ENOTEMPTY;
}
// Check if the procfs file has still some file associated.
if (!list_head_empty(&procfs_file->files)) {
pr_err("proc_destroy_entry(%s): Proc entry is busy.\n", entry_path);
pr_err("proc_rmdir(%s): Proc entry is busy.\n", entry_path);
return -EBUSY;
}
if (procfs_destroy_file(procfs_file)) {
pr_err("proc_destroy_entry(%s): Failed to remove file.\n", entry_path);
pr_err("proc_rmdir(%s): Failed to remove file.\n", entry_path);
return -ENOENT;
}
return 0;
@@ -912,14 +912,14 @@ proc_dir_entry_t *proc_create_entry(const char *name, proc_dir_entry_t *parent)
strcat(entry_path, name);
// Check if the entry exists.
if (procfs_find_entry_path(entry_path) != NULL) {
pr_err("proc_destroy_entry(%s): Proc entry already exists.\n", entry_path);
pr_err("proc_create_entry(%s): Proc entry already exists.\n", entry_path);
errno = EEXIST;
return NULL;
}
// Create the new procfs file.
procfs_file_t *procfs_file = procfs_create_file(entry_path, DT_REG);
if (!procfs_file) {
pr_err("proc_destroy_entry(%s): Cannot create proc entry.\n", entry_path);
pr_err("proc_create_entry(%s): Cannot create proc entry.\n", entry_path);
errno = ENFILE;
return NULL;
}
+3 -3
View File
@@ -4,10 +4,10 @@
/// See LICENSE.md for details.
// Setup the logging for this file (do this before any other include).
#include "sys/kernel_levels.h" // Include kernel log levels.
#define __DEBUG_HEADER__ "[VFS ]" ///< Change header.
#include "sys/kernel_levels.h" // Include kernel log levels.
#define __DEBUG_HEADER__ "[VFS ]" ///< Change header.
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level.
#include "io/debug.h" // Include debugging functions.
#include "io/debug.h" // Include debugging functions.
#include "fs/vfs.h"
#include "process/scheduler.h"
+7
View File
@@ -11,6 +11,13 @@
static ssize_t procfb_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte)
{
if (!file) {
pr_err("Received a NULL file.\n");
return -ENOENT;
}
if (!strcmp(file->name, "/proc/feedback")) {
pr_alert("Return scheduling feedback information.\n");
}
return 0;
}
+105
View File
@@ -0,0 +1,105 @@
/// @file proc_ipc.c
/// @brief Contains callbacks for procfs system files.
/// @copyright (c) 2014-2022 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#include "process/process.h"
#include "sys/errno.h"
#include "fs/procfs.h"
#include "io/debug.h"
#include "sys/msg.h"
#include "sys/sem.h"
#include "sys/shm.h"
#include "string.h"
extern ssize_t procipc_msg_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte);
extern ssize_t procipc_sem_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte);
extern ssize_t procipc_shm_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte);
/// Filesystem general operations.
static vfs_sys_operations_t procipc_sys_operations = {
.mkdir_f = NULL,
.rmdir_f = NULL,
.stat_f = NULL
};
/// Filesystem file operations for message queues.
static vfs_file_operations_t procipc_msg_fs_operations = {
.open_f = NULL,
.unlink_f = NULL,
.close_f = NULL,
.read_f = procipc_msg_read,
.write_f = NULL,
.lseek_f = NULL,
.stat_f = NULL,
.ioctl_f = NULL,
.getdents_f = NULL
};
/// Filesystem file operations for semaphores.
static vfs_file_operations_t procipc_sem_fs_operations = {
.open_f = NULL,
.unlink_f = NULL,
.close_f = NULL,
.read_f = procipc_sem_read,
.write_f = NULL,
.lseek_f = NULL,
.stat_f = NULL,
.ioctl_f = NULL,
.getdents_f = NULL
};
/// Filesystem file operations for shared memry.
static vfs_file_operations_t procipc_shm_fs_operations = {
.open_f = NULL,
.unlink_f = NULL,
.close_f = NULL,
.read_f = procipc_shm_read,
.write_f = NULL,
.lseek_f = NULL,
.stat_f = NULL,
.ioctl_f = NULL,
.getdents_f = NULL
};
int procipc_module_init()
{
proc_dir_entry_t *folder = NULL, *entry = NULL;
// First, we need to create the `/proc/ipc` folder.
if ((folder = proc_mkdir("ipc", NULL)) == NULL) {
pr_err("Cannot create the `/proc/ipc` directory.\n");
return 1;
}
// Create the `/proc/ipc/msg` entry.
if ((entry = proc_create_entry("msg", folder)) == NULL) {
pr_err("Cannot create the `/proc/ipc/msg` file.\n");
return 1;
}
// Set the specific operations.
entry->sys_operations = &procipc_sys_operations;
entry->fs_operations = &procipc_msg_fs_operations;
// Create the `/proc/ipc/sem` entry.
if ((entry = proc_create_entry("sem", folder)) == NULL) {
pr_err("Cannot create the `/proc/ipc/sem` file.\n");
return 1;
}
// Set the specific operations.
entry->sys_operations = &procipc_sys_operations;
entry->fs_operations = &procipc_sem_fs_operations;
// Create the `/proc/ipc/shm` entry.
if ((entry = proc_create_entry("shm", folder)) == NULL) {
pr_err("Cannot create the `/proc/ipc/shm` file.\n");
return 1;
}
// Set the specific operations.
entry->sys_operations = &procipc_sys_operations;
entry->fs_operations = &procipc_shm_fs_operations;
return 0;
}
+77
View File
@@ -0,0 +1,77 @@
/// @file ipc.c
/// @brief Vital IPC structures and functions kernel side.
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#include "ipc/ipc.h"
#include "process/scheduler.h"
#include "io/debug.h"
#include "assert.h"
#include "fcntl.h"
int ipc_check_perm(
task_struct *task,
struct ipc_perm *perm,
int usr,
int grp,
int oth)
{
assert(task && "Received a NULL task.");
assert(perm && "Received a NULL perm.");
int check_parent = (perm->key < 0) && task->parent && (task->parent->pid != 0);
if (perm->mode & usr) {
if ((perm->uid == task->uid) || (perm->cuid == task->uid))
return 1;
if (check_parent && ((perm->uid == task->parent->uid) || (perm->cuid == task->parent->uid)))
return 1;
}
if (perm->mode & grp) {
if ((perm->gid == task->gid) || (perm->cgid == task->gid))
return 1;
if (check_parent && ((perm->gid == task->parent->gid) || (perm->cgid == task->parent->gid)))
return 1;
}
if (perm->mode & oth) {
if (check_parent && ((perm->uid != task->parent->uid) || (perm->cuid != task->parent->uid)))
return 1;
if (check_parent && ((perm->gid != task->parent->gid) || (perm->cgid != task->parent->gid)))
return 1;
}
return 0;
}
int ipc_valid_permissions(int flags, struct ipc_perm *perm)
{
// Get the calling task.
task_struct *task = scheduler_get_current_process();
assert(task && "Failed to get the current running process.");
// Init, and all root processes have full permissions.
if ((task->pid == 0) || (task->uid == 0) || (task->gid == 0))
return 1;
// Check permissions.
if (((flags & O_RDONLY) == O_RDONLY) && ipc_check_perm(task, perm, S_IRUSR, S_IRGRP, S_IROTH))
return 1;
if (((flags & O_WRONLY) == O_WRONLY) && ipc_check_perm(task, perm, S_IWUSR, S_IWGRP, S_IWOTH))
return 1;
if (((flags & O_RDWR) == O_RDWR) && ipc_check_perm(task, perm, S_IRUSR | S_IWUSR, S_IRGRP | S_IWGRP, S_IROTH | S_IWOTH))
return 1;
return 0;
}
struct ipc_perm register_ipc(key_t key, mode_t mode)
{
struct ipc_perm ip;
// Get the current task.
task_struct *task = scheduler_get_current_process();
assert(task && "Failed to get the current running process.");
// Initialize the structure.
ip.key = key;
ip.uid = task->uid;
ip.gid = task->gid;
ip.cuid = task->uid;
ip.cgid = task->gid;
ip.mode = mode;
ip.__seq = 0;
return ip;
}
+39 -1
View File
@@ -4,14 +4,21 @@
/// See LICENSE.md for details.
///! @cond Doxygen_Suppress
// ============================================================================
// Setup the logging for this file (do this before any other include).
#include "sys/kernel_levels.h" // Include kernel log levels.
#define __DEBUG_HEADER__ "[IPCmsg]" ///< Change header.
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level.
#include "io/debug.h" // Include debugging functions.
// ============================================================================
#include "ipc/msg.h"
#include "process/process.h"
#include "system/panic.h"
#include "sys/errno.h"
#include "sys/msg.h"
#include "string.h"
#include "assert.h"
#include "stdio.h"
long sys_msgget(key_t key, int msgflg)
{
@@ -37,4 +44,35 @@ long sys_msgctl(int msqid, int cmd, struct msqid_ds *buf)
return 0;
}
ssize_t procipc_msg_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte)
{
if (!file) {
pr_err("Received a NULL file.\n");
return -ENOENT;
}
size_t buffer_len = 0, read_pos = 0, write_count = 0, ret = 0;
struct semid_ds *entry = NULL;
char buffer[BUFSIZ];
// Prepare a buffer.
memset(buffer, 0, BUFSIZ);
// Prepare the header.
ret = sprintf(buffer, "key msqid ...\n");
// Implementation goes here...
sprintf(buffer + ret, "\n");
// Perform read.
buffer_len = strlen(buffer);
read_pos = offset;
if (read_pos < buffer_len) {
while ((write_count < nbyte) && (read_pos < buffer_len)) {
buf[write_count] = buffer[read_pos];
// Move the pointers.
++read_pos, ++write_count;
}
}
return write_count;
}
///! @endcond
+517 -9
View File
@@ -2,33 +2,541 @@
/// @brief
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
///! @cond Doxygen_Suppress
/// @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).
#include "sys/kernel_levels.h" // Include kernel log levels.
#define __DEBUG_HEADER__ "[IPCsem]" ///< Change header.
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level.
#include "io/debug.h" // Include debugging functions.
// ============================================================================
#include "ipc/sem.h"
#include "system/panic.h"
#include "sys/sem.h"
#include "ipc/ipc.h"
#include "process/scheduler.h"
#include "process/process.h"
#include "klib/list.h"
#include "sys/errno.h"
#include "stdlib.h"
#include "string.h"
#include "assert.h"
#include "stdio.h"
#include "fcntl.h"
///@brief A value to compute the semid value.
int __sem_id = 0;
/// @brief Semaphore management structure.
typedef struct {
/// @brief Semaphore ID associated to the semaphore set.
int id;
/// @brief The semaphore data strcutre.
struct semid_ds semid;
/// Reference inside the list of semaphore management structures.
list_head list;
} sem_info_t;
/// @brief List of all current active semaphores.
list_head semaphores_list;
// ============================================================================
// MEMORY MANAGEMENT (Private)
// ============================================================================
/// @brief Allocates the memory for semaphore management structure.
/// @param key IPC_KEY associated with the set of semaphores.
/// @param nsems number of semaphores to initialize.
/// @param semflg flags used to create the set of semaphores.
/// @return a pointer to the allocated semaphore management structure.
static inline sem_info_t *__sem_info_alloc(key_t key, int nsems, int semflg)
{
// Allocate the memory.
sem_info_t *sem_info = (sem_info_t *)kmalloc(sizeof(sem_info_t));
// Check the allocated memory.
assert(sem_info && "Failed to allocate memory for a semaphore management structure.");
// Clean the memory.
memset(sem_info, 0, sizeof(sem_info_t));
// Allocate the memory for semaphores.
sem_info->semid.sem_base = (struct sem *)kmalloc(sizeof(struct sem) * nsems);
// Check the allocated memory.
assert(sem_info->semid.sem_base && "Failed to allocate memory for a set of semaphores.");
// Clean the memory.
memset(sem_info->semid.sem_base, 0, sizeof(struct sem) * nsems);
// Initialize its values.
sem_info->id = ++__sem_id;
sem_info->semid.sem_perm = register_ipc(key, semflg & 0x1FF);
sem_info->semid.sem_otime = 0;
sem_info->semid.sem_ctime = 0;
sem_info->semid.sem_nsems = nsems;
for (int i = 0; i < nsems; i++) {
sem_info->semid.sem_base[i].sem_pid = sys_getpid();
sem_info->semid.sem_base[i].sem_val = 0;
sem_info->semid.sem_base[i].sem_ncnt = 0;
sem_info->semid.sem_base[i].sem_zcnt = 0;
}
// Return the semaphore management structure.
return sem_info;
}
/// @brief Frees the memory of a semaphore management structure.
/// @param sem_info pointer to the semaphore management structure.
static inline void __sem_info_dealloc(sem_info_t *sem_info)
{
assert(sem_info && "Received a NULL pointer.");
// Deallocate the array of semaphores.
kfree(sem_info->semid.sem_base);
// Deallocate the semid memory.
kfree(sem_info);
}
// ============================================================================
// SEARCH FUNCTIONS (Private)
// ============================================================================
/// @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 sem_info_t *__list_find_sem_info_by_id(int semid)
{
sem_info_t *sem_info;
// Iterate through the list of semaphore set.
list_for_each_decl(it, &semaphores_list)
{
// Get the current entry.
sem_info = list_entry(it, sem_info_t, list);
// If semaphore set is valid, check the id.
if (sem_info && (sem_info->id == semid))
return sem_info;
}
return NULL;
}
/// @brief Searches for the semaphore with the given key.
/// @param key the key we are searching.
/// @return the semaphore with the given key.
static inline sem_info_t *__list_find_sem_info_by_key(key_t key)
{
sem_info_t *sem_info;
// Iterate through the list of semaphore set.
list_for_each_decl(it, &semaphores_list)
{
// Get the current entry.
sem_info = list_entry(it, sem_info_t, list);
// If semaphore set is valid, check the id.
if (sem_info && (sem_info->semid.sem_perm.key == key))
return sem_info;
}
return NULL;
}
static inline void __list_add_sem_info(sem_info_t *sem_info)
{
assert(sem_info && "Received a NULL pointer.");
// Add the new sem_info at the end.
list_head_insert_before(&sem_info->list, &semaphores_list);
}
static inline void __list_remove_sem_info(sem_info_t *sem_info)
{
assert(sem_info && "Received a NULL pointer.");
// Delete the sem_info from the list.
list_head_remove(&sem_info->list);
}
// ============================================================================
// SYSTEM FUNCTIONS
// ============================================================================
int sem_init()
{
list_head_init(&semaphores_list);
return 0;
}
long sys_semget(key_t key, int nsems, int semflg)
{
TODO("Not implemented");
return 0;
sem_info_t *sem_info = NULL;
// Check if nsems is less than 0 or greater than the maximum number of
// semaphores per semaphore set.
if ((nsems < 0) || (nsems > SEM_SET_MAX)) {
pr_err("Wrong number of semaphores for semaphore set.\n");
return -EINVAL;
}
// Need to find a unique key.
if (key == IPC_PRIVATE) {
// Exit when i find a unique key.
do {
key = -rand();
} while (__list_find_sem_info_by_key(key));
// We have a unique key, create the semaphore set.
sem_info = __sem_info_alloc(key, nsems, semflg);
// Add the semaphore set to the list.
__list_add_sem_info(sem_info);
} else {
// Get the semaphore set if it exists.
sem_info = __list_find_sem_info_by_key(key);
// Check if a semaphore set with the given key already exists, but nsems is
// larger than the number of semaphores in that set.
if (sem_info && (nsems > sem_info->semid.sem_nsems)) {
pr_err("Wrong number of semaphores for and existing semaphore set.\n");
return -EINVAL;
}
// Check if no semaphore set exists for the given key and semflg did not
// specify IPC_CREAT.
if (!sem_info && !(semflg & IPC_CREAT)) {
pr_err("No semaphore set exists for the given key and semflg did not specify IPC_CREAT.\n");
return -ENOENT;
}
// Check if IPC_CREAT and IPC_EXCL were specified in semflg, but a semaphore
// set already exists for key.
if (sem_info && (semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
pr_err("IPC_CREAT and IPC_EXCL were specified in semflg, but a semaphore set already exists for key.\n");
return -EEXIST;
}
// Check if the semaphore set exists for the given key, but the calling
// process does not have permission to access the set.
if (sem_info && !ipc_valid_permissions(semflg, &sem_info->semid.sem_perm)) {
pr_err("The semaphore set exists for the given key, but the calling process does not have permission to access the set.\n");
return -EACCES;
}
// If the semaphore set does not exist we need to create a new one.
if (sem_info == NULL) {
// Create the semaphore set.
sem_info = __sem_info_alloc(key, nsems, semflg);
// Add the semaphore set to the list.
__list_add_sem_info(sem_info);
}
}
// Return the id of the semaphore set.
return sem_info->id;
}
long sys_semop(int semid, struct sembuf *sops, unsigned nsops)
{
TODO("Not implemented");
sem_info_t *sem_info = NULL;
// The semid is less than zero.
if (semid < 0) {
pr_err("The semid is less than zero.\n");
return -EINVAL;
}
// The pointer to the operation is NULL.
if (!sops) {
pr_err("The pointer to the operation is NULL.\n");
return -EINVAL;
}
// The value of nsops is negative.
if (nsops <= 0) {
pr_err("The value of nsops is negative.\n");
return -EINVAL;
}
// Search for the semaphore.
sem_info = __list_find_sem_info_by_id(semid);
// The semaphore set doesn't exist.
if (!sem_info) {
pr_err("The semaphore set doesn't exist.\n");
return -EINVAL;
}
// The value of sem_num is less than 0 or greater than or equal to the number of semaphores in the set.
if ((sops->sem_num < 0) || (sops->sem_num >= sem_info->semid.sem_nsems)) {
pr_err("The value of sem_num is less than 0 or greater than or equal to the number of semaphores in the set.\n");
return -EFBIG;
}
// Check if the semaphore set exists for the given key, but the calling
// process does not have permission to access the set.
if (sem_info && !ipc_valid_permissions(O_RDWR, &sem_info->semid.sem_perm)) {
pr_err("The semaphore set exists for the given key, but the calling process does not have permission to access the set.\n");
return -EACCES;
}
// Update semop time.
sem_info->semid.sem_otime = sys_time(NULL);
// 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 (((int)sem_info->semid.sem_base[sops->sem_num].sem_val + (int)sops->sem_op) < 0) {
// The value would become negative, we cannot perform the operation.
return -EAGAIN;
}
// Update the semaphore value.
sem_info->semid.sem_base[sops->sem_num].sem_val += sops->sem_op;
// Update the pid of the process that did last op.
sem_info->semid.sem_base[sops->sem_num].sem_pid = sys_getpid();
// Update the time.
sem_info->semid.sem_ctime = sys_time(NULL);
return 0;
}
long sys_semctl(int semid, int semnum, int cmd, unsigned long arg)
long sys_semctl(int semid, int semnum, int cmd, union semun *arg)
{
TODO("Not implemented");
sem_info_t *sem_info = NULL;
task_struct *task = NULL;
// Search for the semaphore.
sem_info = __list_find_sem_info_by_id(semid);
// The semaphore set doesn't exist.
if (!sem_info) {
pr_err("The semaphore set doesn't exist.\n");
return -EINVAL;
}
// Get the calling task.
task = scheduler_get_current_process();
assert(task && "Failed to get the current running process.");
if (cmd == IPC_RMID) {
// Remove the semaphore set; any processes blocked is awakened (errno set to
// EIDRM); no argument required.
if ((sem_info->semid.sem_perm.uid != task->uid) && (sem_info->semid.sem_perm.cuid != task->uid)) {
pr_err("The calling process is not the creator or the owner of the semaphore set.\n");
return -EPERM;
}
// Remove the set from the list.
__list_remove_sem_info(sem_info);
// Delete the set.
__sem_info_dealloc(sem_info);
} else if (cmd == SETVAL) {
// The value of the semnum-th semaphore in the set is initialized to the
// value specified in arg.val.
// Check if the index is valid.
if ((semnum < 0) || (semnum >= (sem_info->semid.sem_nsems))) {
pr_err("Semaphore number out of bound (%d not in [%d, %d])\n", semnum, 0, sem_info->semid.sem_nsems);
return -EINVAL;
}
// Check if the argument is a null pointer.
if (!arg) {
pr_err("The argument is NULL.\n");
return -EINVAL;
}
// Checking if the value is valid.
if (arg->val < 0) {
pr_err("The value to set is not valid %d.\n", arg->val);
return -EINVAL;
}
// Check permissions.
if (!ipc_valid_permissions(O_WRONLY, &sem_info->semid.sem_perm)) {
pr_err("The calling process does not have read permission to access the set.\n");
return -EACCES;
}
// Setting the value.
sem_info->semid.sem_base[semnum].sem_val = arg->val;
// Update the last change time.
sem_info->semid.sem_ctime = sys_time(NULL);
} else if (cmd == SETALL) {
// Initialize all semaphore in the set referred to by semid, using the
// values supplied in the array pointed to by arg.array.
// Check if the argument is a null pointer.
if (!arg) {
pr_err("The argument is NULL.\n");
return -EINVAL;
}
// Check if the array is valid.
if (!arg->array) {
pr_err("The array is NULL.\n");
return -EINVAL;
}
// Check permissions.
if (!ipc_valid_permissions(O_WRONLY, &sem_info->semid.sem_perm)) {
pr_err("The calling process does not have read permission to access the set.\n");
return -EACCES;
}
// Setting the values.
for (unsigned i = 0; i < sem_info->semid.sem_nsems; ++i) {
sem_info->semid.sem_base[i].sem_val = arg->array[i];
}
// Update the last change time.
sem_info->semid.sem_ctime = sys_time(NULL);
} else if (cmd == IPC_STAT) {
// Place a copy of the semid_ds data structure in the buffer pointed to by
// arg.buf.
// Check if the argument is a null pointer.
if (!arg) {
pr_err("The argument is NULL.\n");
return -EINVAL;
}
// Check if the buffer is a null pointer.
if (!arg->buf) {
pr_err("The buffer is NULL.\n");
return -EINVAL;
}
// Check permissions.
if (!ipc_valid_permissions(O_RDONLY, &sem_info->semid.sem_perm)) {
pr_err("The calling process does not have read permission to access the set.\n");
return -EACCES;
}
// Copying all the data.
memcpy(arg->buf, &sem_info->semid, sizeof(struct semid_ds));
} else if (cmd == GETALL) {
// 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.
// Check if the argument is a null pointer.
if (!arg) {
pr_err("The argument is NULL.\n");
return -EINVAL;
}
// Check if the array is valid.
if (!arg->array) {
pr_err("The array is NULL.\n");
return -EINVAL;
}
for (unsigned i = 0; i < sem_info->semid.sem_nsems; ++i) {
arg->array[i] = sem_info->semid.sem_base[i].sem_val;
}
} else if (cmd == GETVAL) {
// Returns the value of the semnum-th semaphore in the set specified by
// semid; no argument required.
// Check if the index is valid.
if ((semnum < 0) || (semnum >= (sem_info->semid.sem_nsems))) {
pr_err("Semaphore number out of bound (%d not in [%d, %d])\n", semnum, 0, sem_info->semid.sem_nsems);
return -EINVAL;
}
// Check permissions.
if (!ipc_valid_permissions(O_RDONLY, &sem_info->semid.sem_perm)) {
pr_err("The calling process does not have read permission to access the set.\n");
return -EACCES;
}
return sem_info->semid.sem_base[semnum].sem_val;
} else if (cmd == GETPID) {
// Return the process ID of the last process to perform a semop on the
// semnum-th semaphore.
// Check if the index is valid.
if ((semnum < 0) || (semnum >= (sem_info->semid.sem_nsems))) {
pr_err("Semaphore number out of bound (%d not in [%d, %d])\n", semnum, 0, sem_info->semid.sem_nsems);
return -EINVAL;
}
// Check permissions.
if (!ipc_valid_permissions(O_RDONLY, &sem_info->semid.sem_perm)) {
pr_err("The calling process does not have read permission to access the set.\n");
return -EACCES;
}
return sem_info->semid.sem_base[semnum].sem_pid;
} else if (cmd == GETNCNT) {
// Return the number of processes currently waiting for the resources to
// become available.
// Check if the index is valid.
if ((semnum < 0) || (semnum >= (sem_info->semid.sem_nsems))) {
pr_err("Semaphore number out of bound (%d not in [%d, %d])\n", semnum, 0, sem_info->semid.sem_nsems);
return -EINVAL;
}
// Check permissions.
if (!ipc_valid_permissions(O_RDONLY, &sem_info->semid.sem_perm)) {
pr_err("The calling process does not have read permission to access the set.\n");
return -EACCES;
}
return sem_info->semid.sem_base[semnum].sem_ncnt;
} else if (cmd == GETZCNT) {
// Return the number of processes currently waiting for the value of the
// semnum-th semaphore to become 0.
// Check if the index is valid.
if ((semnum < 0) || (semnum >= (sem_info->semid.sem_nsems))) {
pr_err("Semaphore number out of bound (%d not in [%d, %d])\n", semnum, 0, sem_info->semid.sem_nsems);
return -EINVAL;
}
// Check permissions.
if (!ipc_valid_permissions(O_RDONLY, &sem_info->semid.sem_perm)) {
pr_err("The calling process does not have read permission to access the set.\n");
return -EACCES;
}
return sem_info->semid.sem_base[semnum].sem_zcnt;
} else if (cmd == SEM_STAT) {
pr_err("Not implemented.\n");
return -ENOSYS;
} else if (cmd == SEM_INFO) {
pr_err("Not implemented.\n");
return -ENOSYS;
} else {
return -EINVAL;
}
return 0;
}
///! @endcond
// ============================================================================
// PROCFS FUNCTIONS
// ============================================================================
ssize_t procipc_sem_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte)
{
if (!file) {
pr_err("Received a NULL file.\n");
return -ENOENT;
}
size_t buffer_len = 0, read_pos = 0, ret = 0;
ssize_t write_count = 0;
sem_info_t *sem_info = NULL;
char buffer[BUFSIZ];
// Prepare a buffer.
memset(buffer, 0, BUFSIZ);
// Prepare the header.
ret = sprintf(buffer, "key semid perms nsems uid gid cuid cgid otime ctime\n");
// Iterate through the list of semaphore set.
list_for_each_decl(it, &semaphores_list)
{
// Get the current entry.
sem_info = list_entry(it, sem_info_t, list);
// Add the line.
ret += sprintf(
buffer + ret, "%8d %5d %10d %7d %5d %4d %5d %9d %10d %d\n",
abs(sem_info->semid.sem_perm.key),
sem_info->id,
sem_info->semid.sem_perm.mode,
sem_info->semid.sem_nsems,
sem_info->semid.sem_perm.uid,
sem_info->semid.sem_perm.gid,
sem_info->semid.sem_perm.cuid,
sem_info->semid.sem_perm.cgid,
sem_info->semid.sem_otime,
sem_info->semid.sem_ctime);
}
sprintf(buffer + ret, "\n");
// Perform read.
buffer_len = strlen(buffer);
read_pos = offset;
if (read_pos < buffer_len) {
while ((write_count < nbyte) && (read_pos < buffer_len)) {
buf[write_count] = buffer[read_pos];
// Move the pointers.
++read_pos, ++write_count;
}
}
return write_count;
}
+39 -2
View File
@@ -4,14 +4,21 @@
/// See LICENSE.md for details.
///! @cond Doxygen_Suppress
// ============================================================================
// Setup the logging for this file (do this before any other include).
#include "sys/kernel_levels.h" // Include kernel log levels.
#define __DEBUG_HEADER__ "[IPCshm]" ///< Change header.
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level.
#include "io/debug.h" // Include debugging functions.
// ============================================================================
#include "ipc/shm.h"
#include "sys/shm.h"
#include "system/panic.h"
#include "process/process.h"
#include "sys/errno.h"
#include "string.h"
#include "assert.h"
#include "stdio.h"
#if 0
struct shmid_ds *head = NULL;
@@ -374,7 +381,7 @@ struct shmid_ds *find_shm_fromvaddr(void *shmvaddr)
}
#endif
void * sys_shmat(int shmid, const void *shmaddr, int shmflg)
void *sys_shmat(int shmid, const void *shmaddr, int shmflg)
{
TODO("Not implemented");
return 0;
@@ -398,4 +405,34 @@ long sys_shmctl(int shmid, int cmd, struct shmid_ds *buf)
return 0;
}
ssize_t procipc_shm_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte)
{
if (!file) {
pr_err("Received a NULL file.\n");
return -ENOENT;
}
size_t buffer_len = 0, read_pos = 0, write_count = 0, ret = 0;
char buffer[BUFSIZ];
// Prepare a buffer.
memset(buffer, 0, BUFSIZ);
// Prepare the header.
ret = sprintf(buffer, "key shmid ...\n");
// Implementation goes here...
sprintf(buffer + ret, "\n");
// Perform read.
buffer_len = strlen(buffer);
read_pos = offset;
if (read_pos < buffer_len) {
while ((write_count < nbyte) && (read_pos < buffer_len)) {
buf[write_count] = buffer[read_pos];
// Move the pointers.
++read_pos, ++write_count;
}
}
return write_count;
}
///! @endcond
+41 -26
View File
@@ -9,38 +9,32 @@
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level.
#include "io/debug.h" // Include debugging functions.
#include "io/proc_modules.h"
#include "mem/vmem_map.h"
#include "fs/procfs.h"
#include "devices/pci.h"
#include "drivers/ata.h"
#include "descriptor_tables/idt.h"
#include "kernel.h"
#include "mem/zone_allocator.h"
#include "descriptor_tables/gdt.h"
#include "system/syscall.h"
#include "version.h"
#include "io/video.h"
#include "hardware/pic8259.h"
#include "drivers/fdc.h"
#include "fs/ext2.h"
#include "klib/irqflags.h"
#include "descriptor_tables/idt.h"
#include "drivers/keyboard/keyboard.h"
#include "drivers/keyboard/keymap.h"
#include "drivers/ps2.h"
#include "process/scheduler.h"
#include "process/scheduler_feedback.h"
#include "hardware/timer.h"
#include "fs/vfs.h"
#include "devices/fpu.h"
#include "system/printk.h"
#include "sys/module.h"
#include "drivers/ata.h"
#include "drivers/rtc.h"
#include "stdio.h"
#include "assert.h"
#include "drivers/ps2.h"
#include "process/scheduler_feedback.h"
#include "process/scheduler.h"
#include "mem/zone_allocator.h"
#include "mem/vmem_map.h"
#include "hardware/pic8259.h"
#include "hardware/timer.h"
#include "system/syscall.h"
#include "sys/module.h"
#include "sys/sem.h"
#include "io/proc_modules.h"
#include "io/vga/vga.h"
#include "string.h"
#include "fcntl.h"
#include "io/video.h"
#include "fs/vfs.h"
#include "fs/procfs.h"
#include "fs/ext2.h"
#include "version.h"
#include "stdio.h"
/// Describe start address of grub multiboot modules.
char *module_start[MAX_MODULES];
@@ -298,6 +292,27 @@ int kmain(boot_info_t *boot_informations)
}
print_ok();
//==========================================================================
pr_notice("Initialize IPC information system...\n");
printf("Initialize IPC information system...");
if (procipc_module_init()) {
print_fail();
pr_emerg("Failed to initialize the IPC information system!\n");
return 1;
}
print_ok();
//==========================================================================
pr_notice("Initialize IPC/SEM system...\n");
printf("Initialize IPC/SEM system...");
if (sem_init()) {
print_fail();
pr_emerg("Failed to initialize the IPC/SEM system!\n");
return 1;
}
print_ok();
//==========================================================================
pr_notice("Setting up PS/2 driver...\n");
printf("Setting up PS/2 driver...");
+19
View File
@@ -0,0 +1,19 @@
/// @file stdlib.c
/// @brief
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#include "stdlib.h"
/// Seed used to generate random numbers.
static int rseed = 0;
void srand(int x)
{
rseed = x;
}
int rand()
{
return rseed = (rseed * 1103515245U + 12345U) & RAND_MAX;
}
+3 -3
View File
@@ -4,10 +4,10 @@
/// See LICENSE.md for details.
// Setup the logging for this file (do this before any other include).
#include "sys/kernel_levels.h" // Include kernel log levels.
#define __DEBUG_HEADER__ "[PROC ]" ///< Change header.
#include "sys/kernel_levels.h" // Include kernel log levels.
#define __DEBUG_HEADER__ "[PROC ]" ///< Change header.
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level.
#include "io/debug.h" // Include debugging functions.
#include "io/debug.h" // Include debugging functions.
#include "process/process.h"
#include "process/scheduler.h"
+19 -25
View File
@@ -9,24 +9,17 @@
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level.
#include "io/debug.h" // Include debugging functions.
#include "assert.h"
#include "strerror.h"
#include "fs/vfs.h"
#include "descriptor_tables/tss.h"
#include "devices/fpu.h"
#include "process/scheduler_feedback.h"
#include "process/scheduler.h"
#include "process/prio.h"
#include "process/wait.h"
#include "mem/kheap.h"
#include "system/panic.h"
#include "time.h"
#include "sys/errno.h"
#include "klib/list_head.h"
#include "mem/paging.h"
#include "descriptor_tables/tss.h"
#include "hardware/timer.h"
#include "math.h"
#include "stdio.h"
#include "system/panic.h"
#include "sys/errno.h"
#include "strerror.h"
#include "assert.h"
#include "fs/vfs.h"
/// @brief Assembly function setting the kernel stack to jump into
/// location in Ring 3 mode (USER mode).
@@ -102,6 +95,7 @@ task_struct *scheduler_get_running_process(pid_t pid)
void scheduler_enqueue_task(task_struct *process)
{
assert(process && "Received a NULL process.");
// If current_process is NULL, then process is the current process.
if (runqueue.curr == NULL) {
runqueue.curr = process;
@@ -116,6 +110,7 @@ void scheduler_enqueue_task(task_struct *process)
void scheduler_dequeue_task(task_struct *process)
{
assert(process && "Received a NULL process.");
scheduler_feedback_task_remove(process->pid);
// Delete the process from the list of running processes.
list_head_remove(&process->run_list);
@@ -215,7 +210,7 @@ void scheduler_enter_user_jmp(uintptr_t location, uintptr_t stack)
/// @param mode The type of wait (TASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE).
/// @param sync Specifies if the wakeup should be synchronous.
/// @return 1 on success, 0 on failure.
static inline int try_to_wake_up(task_struct *process, int mode, int sync)
static inline int try_to_wake_up(task_struct *process, unsigned mode, int sync)
{
// Only tasks in the state TASK_UNINTERRUPTIBLE can be woke up
if (process->state == TASK_UNINTERRUPTIBLE || process->state == TASK_STOPPED) {
@@ -236,27 +231,26 @@ wait_queue_entry_t *sleep_on(wait_queue_head_t *wq)
{
// Save the sleeping process registers state
task_struct *sleeping_task = scheduler_get_current_process();
// Stops task from runqueue making it unrunnable.
sleeping_task->state = TASK_UNINTERRUPTIBLE;
#if 0
pt_regs* f = get_current_interrupt_stack_frame();
// Get the interrupt registers.
pt_regs *f = get_current_interrupt_stack_frame();
// Store its context.
scheduler_store_context(f, sleeping_task);
// Select next process in the runqueue as the current, restore it's context,
// we assume that the first process is init wich does not sleep (I hope).
// This is necessary to make the scheduler_run() in syscall_handler work.
task_struct *next = list_entry(runqueue.queue.next, task_struct, run_list);
task_struct *next = scheduler_pick_next_task(&runqueue);
assert((next != sleeping_task) && "The next selected process in the runqueue is the sleeping process");
scheduler_restore_context(next, f);
#endif
// Stops task from runqueue making it unrunnable
sleeping_task->state = TASK_UNINTERRUPTIBLE;
// Add sleeping process to sleep wait queue
// Allocate the wait_queue entry.
wait_queue_entry_t *wait_entry = kmalloc(sizeof(struct wait_queue_entry_t));
// Initialize the entry.
init_waitqueue_entry(wait_entry, sleeping_task);
// Add sleeping process to sleep wait queue.
add_wait_queue(wq, wait_entry);
return wait_entry;
}
@@ -523,7 +517,7 @@ void sys_exit(int exit_code)
if (runqueue.curr->parent) {
int ret = sys_kill(runqueue.curr->parent->pid, SIGCHLD);
if (ret == -1) {
printf("[%d] %5d failed sending signal %d : %s\n", ret, runqueue.curr->parent->pid,
pr_err("[%d] %5d failed sending signal %d : %s\n", ret, runqueue.curr->parent->pid,
SIGCHLD, strerror(errno));
}
}
+1 -1
View File
@@ -5,8 +5,8 @@
#include "system/printk.h"
#include "stdarg.h"
#include "stdio.h"
#include "io/video.h"
#include "stdio.h"
int sys_syslog(const char *format, ...)
{
+5 -5
View File
@@ -13,17 +13,17 @@
#include "mem/kheap.h"
#include "system/syscall.h"
#include "descriptor_tables/isr.h"
#include "sys/errno.h"
#include "kernel.h"
#include "process/process.h"
#include "process/scheduler.h"
#include "sys/utsname.h"
#include "fs/ioctl.h"
#include "hardware/timer.h"
#include "ipc/msg.h"
#include "ipc/sem.h"
#include "ipc/shm.h"
#include "sys/errno.h"
#include "sys/utsname.h"
#include "sys/msg.h"
#include "sys/sem.h"
#include "sys/shm.h"
/// The signature of a function call.
typedef int (*SystemCall)();
+79
View File
@@ -3,8 +3,87 @@
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#include <stdio.h>
#include <string.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
/*Checking for arguments*/
if (argc < 3){
printf("Missing arguments...\n");
return 0;
}
if (argc == 3){
if (!strcmp("-a", argv[1]) || !strcmp("--all", argv[1])){
printf("To be implemented...\n");
return 0;
}
if (!strcmp("-M", argv[1])){
printf("To be implemented...\n");
return 0;
}
if (!strcmp("-m", argv[1])){
printf("To be implemented...\n");
return 0;
}
if (!strcmp("-Q", argv[1])){
printf("To be implemented...\n");
return 0;
}
if (!strcmp("-q", argv[1])){
printf("To be implemented...\n");
return 0;
}
/* Remove the semaphore set with the given key. */
if (!strcmp("-S", argv[1])){
int semid;
if((semid = semget(atoi(argv[2]), 0, 0)) == -1){
printf("There is no semaphores set with this key...\n");
return -1;
}
if (semctl(semid, 0, IPC_RMID, NULL) == -1){
printf("There is no semaphore set with this sem_id...\n");
return -1;
}
printf("Done!\n");
return 0;
}
/* Remove the semaphore set with the given id. */
if (!strcmp("-s", argv[1])){
int semid = atoi(argv[2]);
if (semctl(semid, 0, IPC_RMID, NULL) == -1){
printf("There is no semaphore set with this sem_id...\n");
return -1;
}
printf("Done!\n");
return 0;
}
printf("Unknown argument...\n");
}
return 0;
#if 0
if (argc != 2) {
printf("Bad arguments: you have to specify only IPC id, see ipcs.\n");
+81 -42
View File
@@ -3,59 +3,98 @@
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#if 0
static inline void print_sem_stat()
{
printf("Semaphores: \n");
printf("%-10s %-10s %-10s %-10s %-10s %-10s \n", "T", "ID", "KEY", "MODE", "OWNER", "GROUP");
printf("%-20s %-10s %-20s \n\n", "", "Semaphores not implemented", "");
}
#include <sys/unistd.h>
#include <stdio.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
static inline void print_msg_stat()
static inline void __print_file_content(const char *path)
{
printf("Message Queues: \n");
printf("%-10s %-10s %-10s %-10s %-10s %-10s \n", "T", "ID", "KEY", "MODE", "OWNER", "GROUP");
printf("%-20s %-10s %-20s \n\n", "", "Message Queues not implemented", "");
// Prepare the buffer for reading.
char buffer[BUFSIZ];
// Clean the buffer.
memset(buffer, 0, BUFSIZ);
// Open the file.
int fd = open(path, O_RDONLY, 42);
if (fd >= 0) {
// Put on the standard output the characters.
while (read(fd, buffer, BUFSIZ) > 0)
puts(buffer);
// Close the file descriptor.
close(fd);
}
}
static inline void print_shm_stat()
{
printf("Shared Memory: \n");
printf("%-10s %-10s %-10s %-10s %-10s %-10s \n", "T", "ID", "KEY", "MODE", "OWNER", "GROUP");
printf("%-20s %-10s %-20s \n\n", "", "Shared Memory not implemented", "");
}
#endif
int main(int argc, char **argv)
{
#if 0
if (argc > 2) {
printf("Too much arguments.\n");
if (argc > 4)
return -1;
return;
// Default operation, prints all ipcs informations.
if (argc == 1) {
printf("------ Message Queues --------\n");
__print_file_content("/proc/ipc/msg");
printf("------ Semaphore Arrays --------\n");
__print_file_content("/proc/ipc/sem");
printf("------ Shared Memory Segments --------\n");
__print_file_content("/proc/ipc/shm");
return 0;
}
char datehour[100] = "";
strdatehour(datehour);
printf("IPC status from " OS_NAME " as of %s\n", datehour);
if (argc == 2) {
if (strcmp(argv[1], "-s") == 0) {
print_sem_stat();
} else if (strcmp(argv[1], "-m") == 0) {
print_shm_stat();
} else if (strcmp(argv[1], "-q") == 0) {
print_msg_stat();
if (!strcmp(argv[1], "-q")) { // Show message queues information.
printf("------ Message Queues --------\n");
__print_file_content("/proc/ipc/msg");
} else if (!strcmp(argv[1], "-s")) { // Show semaphores information.
printf("------ Semaphore Arrays --------\n");
__print_file_content("/proc/ipc/sem");
} else if (!strcmp(argv[1], "-m")) { // Show shared memories information.
printf("------ Shared Memory Segments --------\n");
__print_file_content("/proc/ipc/shm");
} else {
printf("Option not recognize.\n");
printf("%s: Command not found.", argv[0]);
return 1;
}
} else {
print_sem_stat();
print_shm_stat();
print_msg_stat();
return 0;
}
if (!strcmp(argv[1], "-i")) {
// Show details about a specific semaphore.
if (!strcmp(argv[3], "-s")) {
struct semid_ds sem;
union semun temp;
int semid;
long ret;
// Prepare the data structure.
temp.buf = &sem;
// Initialize the semid.
semid = atoi(argv[2]);
// Retrive the statistics.
ret = semctl(semid, 0, IPC_STAT, &temp);
// Check if we succeded.
if (!ret) {
printf("key semid owner perms nsems\n");
printf("%10d %10d %10d %10d %d\n", sem.sem_perm.key, semid, sem.sem_perm.uid, sem.sem_perm.mode, sem.sem_nsems);
return 0;
}
return 1;
}
return;
#endif
// Show details about a specific shared memory.
if (!strcmp(argv[3], "-m")) {
printf("Not Implemented!\n");
return 0;
}
// Show details about a specific message queue.
if (!strcmp(argv[3], "-q")) {
printf("Not Implemented!\n");
return 0;
}
printf("%s: Wrong combination, with `-i` you should provide either `-s`, `-m`, or `-q`.", argv[0]);
return 1;
}
printf("%s: Command not found.", argv[0]);
return 1;
}
-3
View File
@@ -53,9 +53,6 @@ static inline void __iterate_proc_dirs(int proc_fd)
strcat(absolute_path, "/stat");
// Open the `/proc/<pid>/stat` file.
if ((stat_fd = open(absolute_path, O_RDONLY, 0)) == -1) {
printf("Failed to open `%s`: ", absolute_path);
perror(NULL);
putchar('\n');
continue;
}
// Reset the stat buffer.
+2 -2
View File
@@ -24,7 +24,7 @@
#include <ctype.h>
/// Maximum length of commands.
#define CMD_LEN 32
#define CMD_LEN 64
/// Maximum lenght of the history.
#define HISTORY_MAX 10
@@ -155,7 +155,7 @@ static inline void __prompt_print()
} else {
HOSTNAME = buffer.nodename;
}
printf(FG_GREEN "%s" FG_WHITE "@" FG_CYAN "%s " FG_BLUE_BRIGHT "[%02d:%02d:%02d]" FG_WHITE " [%s] " FG_WHITE_BRIGHT "%% ",
printf(FG_GREEN "%s" FG_WHITE "@" FG_CYAN "%s " FG_BLUE_BRIGHT "[%02d:%02d:%02d]" FG_WHITE " [%s] " FG_WHITE_BRIGHT "\n-> %% ",
USER, HOSTNAME, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, CWD);
}
+4
View File
@@ -85,6 +85,10 @@ set(TESTS
t_kill.c
t_itimer.c
t_gid.c
# Test semaphores.
t_semget.c
t_semflg.c
t_semop.c
# Test scheduling feedback tests.
t_schedfb.c
)
+1 -1
View File
@@ -19,4 +19,4 @@ int main(int argc, char *argv[])
}
while (wait(NULL) != -1) continue;
return 0;
}
}
+119
View File
@@ -0,0 +1,119 @@
/// @file t_semflg.c
/// @brief Tests some of the IPC flags.
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#include "sys/unistd.h"
#include "sys/errno.h"
#include "sys/sem.h"
#include "sys/ipc.h"
#include "stdlib.h"
#include "fcntl.h"
#include "stdio.h"
int main(int argc, char *argv[])
{
struct sembuf op[1];
union semun arg;
long ret, semid;
op[0].sem_num = 0;
op[0].sem_op = -2;
op[0].sem_flg = IPC_NOWAIT;
// ========================================================================
// Create the first semaphore.
semid = semget(IPC_PRIVATE, 1, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if (semid < 0) {
perror("Failed to create semaphore set");
return 1;
}
printf("[father] Created semaphore set (semid : %d)\n", semid);
// ========================================================================
// Set the value of the semaphore in the structure.
arg.val = 1;
// Setting the semaphore value.
ret = semctl(semid, 0, SETVAL, &arg);
if (ret < 0) {
perror("Failed to set value of semaphore");
return 1;
}
printf("[father] Set semaphore value (id : %d, value : %d == 1)\n", semid, arg.val);
// ========================================================================
// Check if we successfully set the value of the semaphore.
ret = semctl(semid, 0, GETVAL, NULL);
if (ret < 0) {
perror("Failed to get the value of semaphore set");
return 1;
}
printf("[father] Get semaphore value (id : %d, value : %d == 1)\n", semid, ret);
// ========================================================================
// Create child process.
if (!fork()) {
struct sembuf op_child;
// Initialize the operation structure.
op_child.sem_num = 0; // Operate on semaphore 0.
op_child.sem_op = 1; // Increment value by 1.
op_child.sem_flg = 0; // No flags.
sleep(3);
// ====================================================================
// Increment semaphore value.
if (semop(semid, &op_child, 1) < 0) {
perror("Failed to perform first child operation");
return 1;
}
printf("[child] Succesfully performed opeation (id : %d)\n", semid);
// ====================================================================
// Check if we successfully set the value of the semaphore.
ret = semctl(semid, 0, GETVAL, NULL);
if (ret < 0) {
perror("Failed to get the value of semaphore set");
return 1;
}
printf("[child] Get semaphore value (id : %d, value : %d == 1)\n", semid, ret);
printf("[child] Exit, now.\n", semid, ret);
// ========================================================================
// Delete the semaphore set.
ret = semctl(semid, 0, IPC_RMID, 0);
if (ret < 0) {
perror("Failed to remove semaphore set");
}
printf("[child] Correctly removed semaphore set.\n");
return 0;
}
// ========================================================================
// Perform the operations.
if (semop(semid, op, 2) < 0) {
perror("Failed to perform operation");
return 1;
}
printf("[father] Performed semaphore operations (id : %d)\n", semid);
// ========================================================================
// Check if we successfully set the value of the semaphore.
ret = semctl(semid, 0, GETVAL, NULL);
if (ret < 0) {
perror("Failed to get the value of semaphore set");
return 1;
}
printf("[father] Get semaphore value (id : %d, value : %d == 1)\n", semid, ret);
// ========================================================================
// Delete the semaphore set.
ret = semctl(semid, 0, IPC_RMID, 0);
if (ret < 0) {
perror("Failed to remove semaphore set");
}
printf("[father] Correctly removed semaphore set.\n");
return 0;
}
+147
View File
@@ -0,0 +1,147 @@
/// @file t_semget.c
/// @brief 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.
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#include "sys/unistd.h"
#include "sys/errno.h"
#include "sys/sem.h"
#include "sys/ipc.h"
#include "stdlib.h"
#include "fcntl.h"
#include "stdio.h"
int main(int argc, char *argv[])
{
struct sembuf op_child;
struct sembuf op_father[3];
union semun arg;
long ret, semid;
key_t key;
// ========================================================================
// Generating a key using ftok
key = ftok("/home/user/test7.txt", 5);
if (key < 0) {
perror("Failed to generate key using ftok.");
return 1;
}
printf("Generated key using ftok (key = %d)\n", key);
// ========================================================================
// Create the first semaphore.
semid = semget(key, 1, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if (semid < 0) {
perror("Failed to create semaphore set.");
return 1;
}
printf("[father] Created semaphore set (id : %d)\n", semid);
// ========================================================================
// Set the value of the semaphore in the structure.
arg.val = 1;
// Setting the semaphore value.
ret = semctl(semid, 0, SETVAL, &arg);
if (ret < 0) {
perror("Failed to set value of semaphore.");
return 1;
}
printf("[father] Set semaphore value (id : %d, value : %d == 1)\n", semid, arg.val);
// ========================================================================
// Check if we successfully set the value of the semaphore.
ret = semctl(semid, 0, GETVAL, NULL);
if (ret < 0) {
perror("Failed to get the value of semaphore set.");
return 1;
}
printf("[father] Get semaphore value (id : %d, value : %d == 1)\n", semid, ret);
// ========================================================================
// Create child process.
if (!fork()) {
// Initialize the operation structure.
op_child.sem_num = 0; // Operate on semaphore 0.
op_child.sem_op = 1; // Increment value by 1.
op_child.sem_flg = 0; // No flags.
// Semaphore has value 1.
sleep(3);
if (semop(semid, &op_child, 1) < 0) {
perror("Failed to perform first child operation.");
return 1;
}
printf("[child] Succesfully performed opeation (id : %d)\n", semid);
// Check if we successfully set the value of the semaphore.
ret = semctl(semid, 0, GETVAL, NULL);
if (ret < 0) {
perror("Failed to get the value of semaphore set.");
return 1;
}
printf("[child] Get semaphore value (id : %d, value : %d == 0)\n", semid, ret);
// Semaphore has value 2, now the father can continue.
sleep(3);
if (semop(semid, &op_child, 1) < 0) {
perror("Failed to perform second child operation.");
return 1;
}
printf("[child] Succesfully performed opeation (id : %d)\n", semid);
// Check if we successfully set the value of the semaphore.
ret = semctl(semid, 0, GETVAL, NULL);
if (ret < 0) {
perror("Failed to get the value of semaphore set.");
return 1;
}
printf("[child] Get semaphore value (id : %d, value : %d == 0)\n", semid, ret);
printf("[child] Exit, now.\n", semid, ret);
// Exit with the child process.
return 0;
}
// ========================================================================
// Initialize the operation structure.
op_father[0].sem_num = 0; // Operate on semaphore 0.
op_father[0].sem_op = -1; // Decrement value by 1.
op_father[0].sem_flg = 0; // No flags.
op_father[1].sem_num = 0; // Operate on semaphore 0.
op_father[1].sem_op = -1; // Decrement value by 1.
op_father[1].sem_flg = 0; // No flags.
op_father[2].sem_num = 0; // Operate on semaphore 0.
op_father[2].sem_op = -1; // Decrement value by 1.
op_father[2].sem_flg = 0; // No flags.
// ========================================================================
// Perform the operations.
if (semop(semid, op_father, 3) < 0) {
perror("Failed to perform father operation.");
return 1;
}
sleep(2);
printf("[father] Performed semaphore operations (id : %d)\n", semid);
// Check if we successfully set the value of the semaphore.
ret = semctl(semid, 0, GETVAL, NULL);
if (ret < 0) {
perror("Failed to get the value of semaphore set.");
return 1;
}
printf("[father] Get semaphore value (id : %d, value : %d == 0)\n", semid, ret);
// Delete the semaphore set.
ret = semctl(semid, 0, IPC_RMID, 0);
if (ret < 0) {
perror("Failed to remove semaphore set.");
}
printf("[father] Correctly removed semaphore set.\n");
return 0;
}
+88
View File
@@ -0,0 +1,88 @@
/// @file t_semop.c
/// @brief Tests semop between processes.
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#include "sys/sem.h"
#include "stdio.h"
#include "sys/ipc.h"
#include "sys/errno.h"
#include "sys/wait.h"
#include "stdlib.h"
#include "sys/unistd.h"
#include "fcntl.h"
int main(int argc, char *argv[])
{
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(17, 4, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
//set the values of the semaphores
unsigned short values[] = { 0, 0, 0, 1 };
union semun arg;
arg.array = values;
if (semctl(semid, 0, SETALL, &arg) == -1) {
perror("Failed to set semaphores");
return 1;
}
if (!fork()) {
semop(semid, &sops[0], 1);
printf("cheers!\n");
exit(0);
}
if (!fork()) {
semop(semid, &sops[1], 1);
printf("course, ");
semop(semid, &sops[3], 1);
exit(0);
}
if (!fork()) {
semop(semid, &sops[2], 1);
printf("systems ");
semop(semid, &sops[4], 1);
exit(0);
}
if (!fork()) {
printf("From the operating ");
semop(semid, &sops[5], 1);
exit(0);
}
for (int n = 0; n < 4; n++) {
wait(&status);
}
if (semctl(semid, 0, IPC_RMID, 0) == -1) {
perror("Failed to remove IPC");
return 1;
}
return 0;
}