Merge branch 'feature/Feature-Semaphores' into develop
This commit is contained in:
+4
-1
@@ -116,4 +116,7 @@ src/initscp/initfscp
|
||||
files/bin/**
|
||||
|
||||
# ISO creation files.
|
||||
iso/boot/*.bin
|
||||
iso/boot/*.bin
|
||||
|
||||
# ClangD stuff.
|
||||
.cache
|
||||
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"*.h": "c",
|
||||
"*.c": "c"
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
SYNOPSIS
|
||||
ipcs [options]
|
||||
|
||||
DESCRIPTION
|
||||
Ipcs shows information on System V inter-process communication facilities.
|
||||
+1
-1
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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
@@ -216,4 +216,6 @@ void perror(const char *s)
|
||||
putchar(' ');
|
||||
}
|
||||
puts(strerror(errno));
|
||||
}
|
||||
puts("\n");
|
||||
puts("\n");
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
@@ -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
@@ -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
@@ -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
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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...");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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, ...)
|
||||
{
|
||||
|
||||
@@ -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)();
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -19,4 +19,4 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
while (wait(NULL) != -1) continue;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user