First rough implementation of shared memory.
This commit is contained in:
+9
-51
@@ -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.
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user