#include "shmat.h" #include #if defined(_win_) #include #include "winint.h" #elif defined(_bionic_) #include #include #include #elif defined(_unix_) #include #include #include #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 } // namespace #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