2 * Copyright (C) 2017-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "SharedMemory.h"
15 #if defined(HAVE_LINUX_MEMFD)
16 #include <linux/memfd.h>
17 #include <sys/syscall.h>
22 #include <system_error>
24 #include "utils/log.h"
26 using namespace KODI::UTILS::POSIX
;
28 CSharedMemory::CSharedMemory(std::size_t size
)
29 : m_size
{size
}, m_fd
{Open()}, m_mmap(nullptr, m_size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, m_fd
, 0)
33 CFileHandle
CSharedMemory::Open()
40 catch (std::system_error
const& error
)
42 if (error
.code() == std::errc::function_not_supported
)
44 CLog::Log(LOGDEBUG
, "Kernel does not support memfd, falling back to plain shm");
53 if (ftruncate(fd
, m_size
) < 0)
55 throw std::system_error(errno
, std::generic_category(), "ftruncate");
61 CFileHandle
CSharedMemory::OpenMemfd()
63 #if defined(SYS_memfd_create) && defined(HAVE_LINUX_MEMFD)
64 // This is specific to Linux >= 3.17, but preferred over shm_create if available
65 // because it is race-free
66 int fd
= syscall(SYS_memfd_create
, "kodi", MFD_CLOEXEC
);
69 throw std::system_error(errno
, std::generic_category(), "memfd_create");
72 return CFileHandle(fd
);
74 throw std::system_error(std::make_error_code(std::errc::function_not_supported
), "memfd_create");
78 CFileHandle
CSharedMemory::OpenShm()
80 char* xdgRuntimeDir
= std::getenv("XDG_RUNTIME_DIR");
83 throw std::runtime_error("XDG_RUNTIME_DIR environment variable must be set");
86 std::string
tmpFilename(xdgRuntimeDir
);
87 tmpFilename
.append("/kodi-shared-XXXXXX");
90 #if defined(HAVE_MKOSTEMP)
91 // Opening the file with O_CLOEXEC is preferred since it avoids races where
92 // other threads might exec() before setting the CLOEXEC flag
93 rawFd
= mkostemp(&tmpFilename
[0], O_CLOEXEC
);
95 rawFd
= mkstemp(&tmpFilename
[0]);
100 throw std::system_error(errno
, std::generic_category(), "mkstemp");
102 CFileHandle
fd(rawFd
);
104 int flags
= fcntl(fd
, F_GETFD
);
107 throw std::system_error(errno
, std::generic_category(), "fcntl F_GETFD");
109 // Set FD_CLOEXEC if unset
110 if (!(flags
& FD_CLOEXEC
) && fcntl(fd
, F_SETFD
, flags
| FD_CLOEXEC
) == -1)
112 throw std::system_error(errno
, std::generic_category(), "fcntl F_SETFD FD_CLOEXEC");
115 unlink(tmpFilename
.c_str());