First rough implementation of shared memory.

This commit is contained in:
Enrico Fraccaroli (Galfurian)
2023-08-16 11:49:52 -04:00
parent 07d603f47a
commit dde6e6bc9e
7 changed files with 225 additions and 59 deletions
+9 -51
View File
@@ -51,20 +51,6 @@ struct shmid_ds {
#define SHM_W 0200
//==============================================================================
//======== Flags for shmat =====================================================
// Attach read-only else read-write.
#define SHM_RDONLY 010000
// Round attach address to SHMLBA.
#define SHM_RND 020000
// Take-over region on attach.
#define SHM_REMAP 040000
// Execution access.
#define SHM_EXEC 0100000
//==============================================================================
//======== Commands for shmctl =================================================
// Lock segment (root only).
#define SHM_LOCK 11
@@ -93,41 +79,13 @@ struct shmid_ds {
// Don't check for reservations.
#define SHM_NORESERVE 010000
/// @@brief Syscall Service Routine: Shared memory control operation.
int syscall_shmctl(int *args);
/// @@brief Syscall Service Routine: Get shared memory segment.
int syscall_shmget(int *args);
/// @@brief Syscall Service Routine: Attach shared memory segment.
void *syscall_shmat(int *args);
/// @@brief Syscall Service Routine: Detach shared memory segment.
int syscall_shmdt(int *args);
/// @@brief User Wrapper: Shared memory control operation.
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
/// @@brief User Wrapper: Get shared memory segment.
int shmget(key_t key, size_t size, int flags);
/// @@brief User Wrapper: Attach shared memory segment.
void *shmat(int shmid, void *shmaddr, int flag);
/// @@brief User Wrapper: Detach shared memory segment.
int shmdt(void *shmaddr);
/// @@brief Find shmid_ds on list.
struct shmid_ds *find_shm_fromid(int shmid);
/// @@brief Find shmid_ds on list.
struct shmid_ds *find_shm_fromkey(key_t key);
/// @@brief shmid_ds on list.
struct shmid_ds *find_shm_fromvaddr(void *shmvaddr);
#endif
#define SHM_RDONLY 010000 ///< Attach read-only else read-write.
#define SHM_RND 020000 ///< Round attach address to SHMLBA.
#define SHM_REMAP 040000 ///< Take-over region on attach.
#define SHM_EXEC 0100000 ///< Execution access.
#ifdef __KERNEL__
/// @brief Initializes the shared memory.
@@ -138,10 +96,10 @@ int shm_init();
/// @param key can be used either to obtain the identifier of a previously
/// created shared memory, or to create a new one.
/// @param size of the shared memory, rounded up to a multiple of PAGE_SIZE.
/// @param flag controls the behaviour of the function.
/// @param shmflg controls the behaviour of the function.
/// @return the shared memory identifier, -1 on failure, and errno is set to
/// indicate the error.
long sys_shmget(key_t key, size_t size, int flag);
long sys_shmget(key_t key, size_t size, int shmflg);
/// @brief Attaches the shared memory segment identified by shmid to the address
/// space of the calling process.
@@ -173,10 +131,10 @@ long sys_shmctl(int shmid, int cmd, struct shmid_ds *buf);
/// @param key can be used either to obtain the identifier of a previously
/// created shared memory, or to create a new one.
/// @param size of the shared memory, rounded up to a multiple of PAGE_SIZE.
/// @param flag controls the behaviour of the function.
/// @param shmflg controls the behaviour of the function.
/// @return the shared memory identifier, -1 on failure, and errno is set to
/// indicate the error.
long shmget(key_t key, size_t size, int flag);
long shmget(key_t key, size_t size, int shmflg);
/// @brief Attaches the shared memory segment identified by shmid to the address
/// space of the calling process.
+7
View File
@@ -236,6 +236,13 @@ vm_area_struct_t *create_vm_area(mm_struct_t *mm,
uint32_t pgflags,
uint32_t gfpflags);
vm_area_struct_t *create_vm_area_with_phy(mm_struct_t *mm,
uint32_t virt_start,
size_t size,
uint32_t pgflags,
uint32_t gfpflags,
uint32_t phy_vm_start);
/// @brief Clone a virtual memory area, using copy on write if specified
/// @param mm the memory descriptor which will contain the new segment.
/// @param area the area to clone
+144 -6
View File
@@ -16,8 +16,10 @@
#include "sys/shm.h"
#include "assert.h"
#include "fcntl.h"
#include "mem/kheap.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "sys/errno.h"
#include "sys/list_head.h"
@@ -34,7 +36,7 @@ typedef struct {
/// @brief The shared memory data strcutre.
struct shmid_ds shmid;
/// Where shm created is memorized.
void *shm_location;
page_t *shm_location;
/// Reference inside the list of shared memory management structures.
list_head list;
} shm_info_t;
@@ -68,6 +70,9 @@ static inline shm_info_t *__shm_info_alloc(key_t key, size_t size, int shmflg)
shm_info->shmid.shm_cpid = 0;
shm_info->shmid.shm_lpid = 0;
shm_info->shmid.shm_nattch = 0;
// Allocate the memory.
uint32_t order = find_nearest_order_greater(0, size);
shm_info->shm_location = _alloc_pages(GFP_KERNEL, order);
// Return the shared memory structure.
return shm_info;
}
@@ -77,6 +82,8 @@ static inline shm_info_t *__shm_info_alloc(key_t key, size_t size, int shmflg)
static inline void __shm_info_dealloc(shm_info_t *shm_info)
{
assert(shm_info && "Received a NULL pointer.");
// Free the shared memory.
__free_pages(shm_info->shm_location);
// Deallocate the shmid memory.
kfree(shm_info);
}
@@ -147,14 +154,119 @@ int shm_init()
return 0;
}
void *sys_shmat(int shmid, const void *shmaddr, int shmflg)
long sys_shmget(key_t key, size_t size, int shmflg)
{
return 0;
shm_info_t *shm_info = NULL;
// Need to find a unique key.
if (key == IPC_PRIVATE) {
// Exit when i find a unique key.
do {
key = (int)-rand();
} while (__list_find_shm_info_by_key(key));
// We have a unique key, create the shared memory.
shm_info = __shm_info_alloc(key, size, shmflg);
// Add the shared memory to the list.
__list_add_shm_info(shm_info);
} else {
// Get the shared memory if it exists.
shm_info = __list_find_shm_info_by_key(key);
// Check if no shared memory exists for the given key and the flags did not specify IPC_CREAT.
if (!shm_info && !(shmflg & IPC_CREAT)) {
pr_err("No shared memory exists for the given key and the flags did not specify IPC_CREAT.\n");
return -ENOENT;
}
// Check if IPC_CREAT and IPC_EXCL were specified, but a shared memory already exists for key.
if (shm_info && (shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) {
pr_err("IPC_CREAT and IPC_EXCL were specified, but a shared memory already exists for key.\n");
return -EEXIST;
}
// Check if the shared memory exists for the given key, but the calling
// process does not have permission to access the set.
if (shm_info && !ipc_valid_permissions(shmflg, &shm_info->shmid.shm_perm)) {
pr_err("The shared memory exists for the given key, but the calling process does not have permission to access the set.\n");
return -EACCES;
}
// If the shared memory does not exist we need to create a new one.
if (shm_info == NULL) {
// Create the shared memory.
shm_info = __shm_info_alloc(key, size, shmflg);
// Add the shared memory to the list.
__list_add_shm_info(shm_info);
}
}
// Return the id of the shared memory.
return shm_info->id;
}
long sys_shmget(key_t key, size_t size, int flag)
static inline int __find_vm_free_area(mm_struct_t *mm, size_t length, uintptr_t *vm_start)
{
return 0;
// Get the stack.
vm_area_struct_t *area, *prev_area;
list_for_each_prev_decl(it, &mm->mmap_list)
{
area = list_entry(it, vm_area_struct_t, vm_list);
assert(area && "There is a NULL area in the list.");
// Check the previous segment.
if (area->vm_list.prev != &mm->mmap_list) {
prev_area = list_entry(area->vm_list.prev, vm_area_struct_t, vm_list);
assert(prev_area && "There is a NULL area in the list.");
// Compute the available space.
unsigned available_space = area->vm_start - prev_area->vm_end;
// If the space is enough, return the address.
if (available_space >= length) {
*vm_start = area->vm_start - length;
return 0;
}
}
}
return 1;
}
void *sys_shmat(int shmid, const void *shmaddr, int shmflg)
{
shm_info_t *shm_info = NULL;
task_struct *task = NULL;
// The id is less than zero.
if (shmid < 0) {
pr_err("The id is less than zero.\n");
return (void *)-EINVAL;
}
// Get the shared memory if it exists.
shm_info = __list_find_shm_info_by_id(shmid);
// Check if no shared memory exists for the given key and the flags did not specify IPC_CREAT.
if (!shm_info) {
pr_err("No shared memory exists for the given id and the flags did not specify IPC_CREAT.\n");
return (void *)-ENOENT;
}
// Check if the shared memory exists for the given key, but the calling
// process does not have permission to access the set.
if ((shmflg & SHM_RDONLY) && !ipc_valid_permissions(O_RDONLY, &shm_info->shmid.shm_perm)) {
pr_err("The shared memory exists for the given key, but the calling process does not have permission to access the set.\n");
return (void *)-EACCES;
}
if (!ipc_valid_permissions(O_RDWR, &shm_info->shmid.shm_perm)) {
pr_err("The shared memory exists for the given key, but the calling process does not have permission to access the set.\n");
return (void *)-EACCES;
}
// Get the calling task.
task = scheduler_get_current_process();
assert(task && "Failed to get the current running process.");
uint32_t phy_start = get_physical_address_from_page(shm_info->shm_location);
uint32_t vm_start;
__find_vm_free_area(
task->mm,
shm_info->shmid.shm_segsz,
&vm_start);
mem_upd_vm_area(
task->mm->pgd,
vm_start,
phy_start,
shm_info->shmid.shm_segsz,
MM_RW | MM_PRESENT | MM_USER | MM_UPDADDR);
return (void *)vm_start;
}
long sys_shmdt(const void *shmaddr)
@@ -164,6 +276,32 @@ long sys_shmdt(const void *shmaddr)
long sys_shmctl(int shmid, int cmd, struct shmid_ds *buf)
{
shm_info_t *shm_info = NULL;
task_struct *task = NULL;
// Search for the shared memory.
shm_info = __list_find_shm_info_by_id(shmid);
// The shared memory doesn't exist.
if (!shm_info) {
pr_err("The shared memory 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 shared memory; any processes blocked is awakened (errno set to EIDRM); no argument required.
if ((shm_info->shmid.shm_perm.uid != task->uid) && (shm_info->shmid.shm_perm.cuid != task->uid)) {
pr_err("The calling process is not the creator or the owner of the shared memory.\n");
return -EPERM;
}
// Remove the set from the list.
__list_remove_shm_info(shm_info);
// Delete the set.
__shm_info_dealloc(shm_info);
}
return 0;
}
@@ -187,7 +325,7 @@ ssize_t procipc_shm_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte
// Prepare the header.
ret = sprintf(buffer, "key shmid perms segsz uid gid cuid cgid atime dtime ctime cpid lpid nattch\n");
// Iterate through the list of shmaphore set.
// Iterate through the list of shared memory.
list_for_each_decl(it, &shm_list)
{
// Get the current entry.
+1 -1
View File
@@ -447,7 +447,7 @@ void *sys_shmat(int shmid, const void *shmaddr, int shmflg)
return 0;
}
long sys_shmget(key_t key, size_t size, int flag)
int sys_shmget(key_t key, size_t size, int flag)
{
return 0;
}
+2 -1
View File
@@ -13,7 +13,8 @@ int main(int argc, char *argv[], char *envp[])
char *_argv[] = { "login", NULL };
if (fork() == 0) {
execv("/bin/login", _argv);
// execv("/bin/login", _argv);
execv("/bin/tests/t_shmget", _argv);
printf("This is bad, I should not be here! EXEC NOT WORKING\n");
}
int status;
+2
View File
@@ -90,6 +90,8 @@ set(TESTS
t_semop.c
# Test message queues.
t_msgget.c
# Test shared memory.
t_shmget.c
# Test scheduling feedback tests.
t_schedfb.c
)
+60
View File
@@ -0,0 +1,60 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/unistd.h>
#include <sys/wait.h>
#define MEM_SIZE sizeof(int) * 2
int main(void)
{
int semid, shmid;
pid_t cpid;
int *array;
// Create shared memory.
shmid = shmget(IPC_PRIVATE, MEM_SIZE, IPC_CREAT | 0600);
if (shmid == -1) {
perror("shmget");
return EXIT_FAILURE;
}
// Create a semaphore set containing one semaphore.
semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
if (semid == -1) {
perror("semget");
return EXIT_FAILURE;
}
cpid = fork();
if (cpid == 0) {
array = (int *)shmat(shmid, NULL, 0);
printf("C: %p\n", array);
array[0] = 1;
return 0;
} else {
array = (int *)shmat(shmid, NULL, 0);
printf("F: %p\n", array);
array[1] = 2;
}
while (wait(NULL) != -1) continue;
printf("array[%d] : %d\n", 0, array[0]);
printf("array[%d] : %d\n", 1, array[1]);
// Remove the shared memory.
if (shmctl(shmid, IPC_RMID, NULL) == -1) {
perror("shmctl");
return EXIT_FAILURE;
}
// Remove the semaphore set.
if (semctl(semid, 0, IPC_RMID, NULL) == -1) {
perror("semctl");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}