about summary refs log blame commit diff stats
path: root/kernel.soso/sharedmemory.c
blob: 8a4e635a0b0b8e17ddd0d8b5fcf4bd6937b06c7f (plain) (tree)



























































































































































































































































                                                                                         
#include "fs.h"
#include "common.h"
#include "list.h"
#include "alloc.h"
#include "spinlock.h"
#include "vmm.h"
#include "sharedmemory.h"

static List* gShmList = NULL;
static Spinlock gShmListLock;

static FileSystemNode* gShmRoot = NULL;

static FileSystemDirent gDirent;

static BOOL sharedmemorydir_open(File *file, uint32 flags);
static FileSystemDirent *sharedmemorydir_readdir(FileSystemNode *node, uint32 index);
static FileSystemNode *sharedmemorydir_finddir(FileSystemNode *node, char *name);

typedef struct SharedMemory
{
    FileSystemNode* node;
    List* physicalAddressList;
    Spinlock physicalAddressListLock;
    //TODO: permissions
} SharedMemory;

void initializeSharedMemory()
{
    Spinlock_Init(&gShmListLock);

    gShmList = List_Create();

    gShmRoot = getFileSystemNode("/system/shm");

    if (NULL == gShmRoot)
    {
        WARNING("/system/shm not found!!");
    }
    else
    {
        gShmRoot->open = sharedmemorydir_open;
        gShmRoot->finddir = sharedmemorydir_finddir;
        gShmRoot->readdir = sharedmemorydir_readdir;
    }
}

static BOOL sharedmemorydir_open(File *file, uint32 flags)
{
    return TRUE;
}

static FileSystemDirent *sharedmemorydir_readdir(FileSystemNode *node, uint32 index)
{
    FileSystemDirent* result = NULL;

    int counter = 0;

    Spinlock_Lock(&gShmListLock);

    List_Foreach (n, gShmList)
    {
        SharedMemory* p = (SharedMemory*)n->data;

        if (counter == index)
        {
            strcpy(gDirent.name, p->node->name);
            gDirent.fileType = p->node->nodeType;

            result = &gDirent;

            break;
        }
        ++counter;
    }

    Spinlock_Unlock(&gShmListLock);

    return result;
}

static FileSystemNode *sharedmemorydir_finddir(FileSystemNode *node, char *name)
{
    FileSystemNode* result = NULL;

    Spinlock_Lock(&gShmListLock);

    List_Foreach (n, gShmList)
    {
        SharedMemory* p = (SharedMemory*)n->data;

        if (strcmp(name, p->node->name) == 0)
        {
            result = p->node;
            break;
        }
    }

    Spinlock_Unlock(&gShmListLock);

    return result;
}

static BOOL sharedmemory_open(File *file, uint32 flags)
{
    return TRUE;
}

static void sharedmemory_unlink(File *file)
{
    destroySharedMemory(file->node->name);
}

static int32 sharedmemory_ftruncate(File *file, int32 length)
{
    if (length <= 0)
    {
        return -1;
    }

    SharedMemory* sharedMem = (SharedMemory*)file->node->privateNodeData;

    if (0 != file->node->length)
    {
        //already set
        return -1;
    }

    int pageCount = (length / PAGESIZE_4M) + 1;

    Spinlock_Lock(&sharedMem->physicalAddressListLock);

    for (int i = 0; i < pageCount; ++i)
    {
        char* pAddress = getPageFrame4M();

        List_Append(sharedMem->physicalAddressList, pAddress);
    }

    file->node->length = length;

    Spinlock_Unlock(&sharedMem->physicalAddressListLock);

    return 0;
}

static void* sharedmemory_mmap(File* file, uint32 size, uint32 offset, uint32 flags)
{
    void* result = NULL;

    SharedMemory* sharedMem = (SharedMemory*)file->node->privateNodeData;

    Spinlock_Lock(&sharedMem->physicalAddressListLock);

    if (List_GetCount(sharedMem->physicalAddressList) > 0)
    {
        result = mapMemory(file->thread->owner, size, 0, sharedMem->physicalAddressList);
    }

    Spinlock_Unlock(&sharedMem->physicalAddressListLock);

    return result;
}

FileSystemNode* getSharedMemoryNode(const char* name)
{
    FileSystemNode* result = NULL;

    Spinlock_Lock(&gShmListLock);

    List_Foreach (n, gShmList)
    {
        SharedMemory* p = (SharedMemory*)n->data;

        if (strcmp(name, p->node->name) == 0)
        {
            result = p->node;
            break;
        }
    }

    Spinlock_Unlock(&gShmListLock);

    return result;
}

FileSystemNode* createSharedMemory(const char* name)
{
    if (getSharedMemoryNode(name) != NULL)
    {
        return NULL;
    }

    SharedMemory* sharedMem = (SharedMemory*)kmalloc(sizeof(SharedMemory));
    memset((uint8*)sharedMem, 0, sizeof(SharedMemory));

    FileSystemNode* node = (FileSystemNode*)kmalloc(sizeof(FileSystemNode));
    memset((uint8*)node, 0, sizeof(FileSystemNode));

    strcpy(node->name, name);
    node->nodeType = FT_CharacterDevice;
    node->open = sharedmemory_open;
    //TODO: node->shm_unlink = sharedmemory_unlink;
    node->ftruncate = sharedmemory_ftruncate;
    node->mmap = sharedmemory_mmap;
    node->privateNodeData = sharedMem;

    sharedMem->node = node;
    sharedMem->physicalAddressList = List_Create();
    Spinlock_Init(&sharedMem->physicalAddressListLock);

    Spinlock_Lock(&gShmListLock);
    List_Append(gShmList, sharedMem);
    Spinlock_Unlock(&gShmListLock);

    return node;
}

void destroySharedMemory(const char* name)
{
    SharedMemory* sharedMem = NULL;

    Spinlock_Lock(&gShmListLock);

    List_Foreach (n, gShmList)
    {
        SharedMemory* p = (SharedMemory*)n->data;

        if (strcmp(name, p->node->name) == 0)
        {
            sharedMem = (SharedMemory*)p;
            break;
        }
    }

    if (sharedMem)
    {
        Spinlock_Lock(&sharedMem->physicalAddressListLock);

        kfree(sharedMem->node);

        List_Destroy(sharedMem->physicalAddressList);

        List_RemoveFirstOccurrence(gShmList, sharedMem);

        Spinlock_Unlock(&sharedMem->physicalAddressListLock);

        kfree(sharedMem);
    }

    Spinlock_Unlock(&gShmListLock);
}