aboutsummaryrefslogblamecommitdiffstats
path: root/util/system/shmat.cpp
blob: f10a1268e7c2e3004e87318cd6764ec8fb5cb08e (plain) (tree)
1
2
3
                  
 
                              


































                                                                                                                                                      
      




















                                                            
 



                               






                                                                                 
                                               







                                                                         


          
                              
                             
                   

             
 
                                                    

                                                                  
                                                     
                          



                         

                                                                
                     
     
 
                                                                  
 
                    
                      

                                   



                     
 
                                      
                          




                         

                                                                                           
                      

                     
                                                                  
                    
                      

                                   



                     
 




                                 
     

                                                                                                 

                
                                                     
                                                                                     
 
                          

                         

                                                                                                      
                     
     
 
                                    
 
                          



                     
 
                                      
                          



                         

                                                          
                      

                     

                                     
                      

                                          



                     
 
                                 
                    



                                          
      
#include "shmat.h"

#include <util/generic/guid.h>

#if defined(_win_)
    #include <stdio.h>
    #include "winint.h"
#elif defined(_bionic_)
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/syscall.h>
#elif defined(_unix_)
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
#endif

#if defined(_cygwin_)
    #define WINAPI __stdcall
    #define FILE_MAP_ALL_ACCESS ((long)983071)
    #define PAGE_READWRITE 4
    #define FALSE 0

extern "C" {
    using HANDLE = OS_HANDLE;
    using BOOL = int;
    using DWORD = ui32;
    using LPCTSTR = const char*;
    using LPVOID = void*;
    using LPCVOID = void const*;
    using SIZE_T = size_t;

    BOOL WINAPI CloseHandle(HANDLE hObject);
    HANDLE WINAPI OpenFileMappingA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName);
    LPVOID WINAPI MapViewOfFile(HANDLE hFileMappingObject, DWORD DesiredAccess, DWORD FileOffsetHigh, DWORD FileOffsetLow, SIZE_T NumberOfBytesToMap);
    HANDLE WINAPI CreateFileMappingA(HANDLE hFile, LPVOID lpAttributes, DWORD flProtect, DWORD MaximumSizeHigh, DWORD MaximumSizeLow, LPCTSTR lpName);
    BOOL WINAPI UnmapViewOfFile(LPCVOID lpBaseAddress);
    DWORD WINAPI GetLastError(void);
}
#endif

#if defined(_bionic_)
namespace {
    #if !defined(__i386__)
    static int shmget(key_t key, size_t size, int flag) {
        if (size > PTRDIFF_MAX) {
            size = SIZE_MAX;
        }

        return syscall(__NR_shmget, key, size, flag);
    }

    static void* shmat(int id, const void* addr, int flag) {
        return (void*)syscall(__NR_shmat, id, addr, flag);
    }

    static int shmctl(int id, int cmd, void* buf) {
        return syscall(__NR_shmctl, id, cmd | IPC_64, buf);
    }

    static int shmdt(const void* addr) {
        return syscall(__NR_shmdt, addr);
    }

    #else
        #define IPCOP_shmat 21
        #define IPCOP_shmdt 22
        #define IPCOP_shmget 23
        #define IPCOP_shmctl 24

    static int shmget(key_t key, size_t size, int flag) {
        return syscall(__NR_ipc, IPCOP_shmget, key, size, flag, 0);
    }

    static void* shmat(int id, const void* addr, int flag) {
        void* retval;
        long res = syscall(__NR_ipc, IPCOP_shmat, id, flag, (long)&retval, addr);
        return (res >= 0) ? retval : (void*)-1;
    }

    static int shmctl(int id, int cmd, void* buf) {
        return syscall(__NR_ipc, IPCOP_shmctl, id, cmd | IPC_64, 0, buf);
    }

    static int shmdt(const void* addr) {
        return syscall(__NR_ipc, IPCOP_shmdt, 0, 0, 0, addr);
    }
    #endif
}
#endif

TSharedMemory::TSharedMemory()
    : Handle(INVALID_FHANDLE)
    , Data(nullptr)
    , Size(0)
{
}

#if defined(_win_)
static void FormatName(char* buf, const TGUID& id) {
    sprintf(buf, "Global\\shmat-%s", GetGuidAsString(id).c_str());
}

bool TSharedMemory::Open(const TGUID& id, int size) {
    //Y_ASSERT(Data == 0);
    Id = id;
    Size = size;

    char name[100];
    FormatName(name, Id);
    Handle = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, name);

    if (Handle == 0) {
        return false;
    }

    Data = MapViewOfFile(Handle, FILE_MAP_ALL_ACCESS, 0, 0, size);

    if (Data == 0) {
        //Y_ASSERT(0);
        CloseHandle(Handle);
        Handle = INVALID_OS_HANDLE;

        return false;
    }

    return true;
}

bool TSharedMemory::Create(int size) {
    //Y_ASSERT(Data == 0);
    Size = size;

    CreateGuid(&Id);

    char name[100];
    FormatName(name, Id);
    Handle = CreateFileMappingA(INVALID_OS_HANDLE, nullptr, PAGE_READWRITE, 0, size, name);

    if (Handle == 0) {
        //Y_ASSERT(0);
        return false;
    }

    Data = MapViewOfFile(Handle, FILE_MAP_ALL_ACCESS, 0, 0, size);

    if (Data == 0) {
        //Y_ASSERT(0);
        CloseHandle(Handle);
        Handle = INVALID_OS_HANDLE;

        return false;
    }

    return true;
}

TSharedMemory::~TSharedMemory() {
    if (Data) {
        UnmapViewOfFile(Handle);
    }

    CloseHandle(Handle);
}
#else
static key_t GetKey(const TGUID& id) {
    i64 id64 = (ui64)(((ui64)id.dw[0] + (ui64)id.dw[2]) << 32) + (ui64)id.dw[1] + (ui64)id.dw[3];

    return id64;
}

bool TSharedMemory::Open(const TGUID& id, int size) {
    Y_ABORT_UNLESS(id, "invalid shared memory guid: %s", GetGuidAsString(id).data());

    //Y_ASSERT(Data == 0);
    Size = size;

    key_t k = GetKey(id);
    int shmId = shmget(k, Size, 0777); // do not fill Handle, since IPC_RMID should be called by owner

    if (shmId < 0) {
        return false;
    }

    Data = shmat(shmId, nullptr, 0);

    if (Data == nullptr) {
        //Y_ASSERT(0);
        return false;
    }

    return true;
}

bool TSharedMemory::Create(int size) {
    //Y_ASSERT(Data == 0);
    Size = size;

    CreateGuid(&Id);

    key_t k = GetKey(Id);
    Handle = shmget(k, Size, IPC_CREAT | IPC_EXCL | 0777);

    if (Handle < 0) {
        //Y_ASSERT(0);
        return false;
    }

    Data = shmat(Handle, nullptr, 0);

    if (Data == (void*)-1) {
        //Y_ASSERT(0);
        shmctl(Handle, IPC_RMID, nullptr);
        Handle = -1;

        return false;
    }

    return true;
}

TSharedMemory::~TSharedMemory() {
    if (Data) {
        shmdt(Data);
    }

    if (Handle >= 0) {
        shmctl(Handle, IPC_RMID, nullptr);
    }
}
#endif