Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iox #33 implement ipc mutex semaphore #834

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
260ed1b
iox-#33 implemented unique system id as basis for named mutex and sem…
elfenpiff Jun 3, 2021
83bcc59
iox-#33 implemented posix style ipc semaphores in windows
elfenpiff Jun 4, 2021
5af74e1
iox-#33 create ipc handle manager abstraction
elfenpiff Jun 4, 2021
850a621
iox-#33 interprocess capable mutex implemented
elfenpiff Jun 4, 2021
9b8cc39
iox-#33 added windows handle to unix file handle translator
elfenpiff Jun 4, 2021
daaac59
iox-#33 implemented filelock for windows
elfenpiff Jun 4, 2021
2d7c186
iox-#33 activating filelock tests
elfenpiff Jun 4, 2021
82ceea6
iox-#33 file lock file must be a valid file path
elfenpiff Jun 4, 2021
6929a37
iox-#33 reduce the test so that it verifies that only at least the ti…
elfenpiff Jun 4, 2021
ad1dd82
iox-#33 shm unlink impossible/unnessary in windows
elfenpiff Jun 7, 2021
160791b
iox-#33 removed implicit shm removal from posix wrapper and packed it…
elfenpiff Jun 7, 2021
0cee171
iox-#33 added shared memory tests
elfenpiff Jun 7, 2021
f9d9b3e
iox-#33 ipc channel works with windows and named pipes
elfenpiff Jun 7, 2021
9808911
iox-#33 adjusted platform settings variable namespace
elfenpiff Jun 9, 2021
01cf307
iox-#33 handle translator const correctness, adjusted ipc mutex name
elfenpiff Jun 9, 2021
c2b395e
iox-#33 Fix Windows handle_t Issue In HandleTranslator
elfenpiff Jun 9, 2021
890c043
iox-#33 Fix review findings
elfenpiff Jun 10, 2021
a72b44d
iox-#33 Use new policy instead of ownership enum
elfenpiff Jun 10, 2021
8271dfa
iox-#33 Adjust ownership handling
elfenpiff Jun 11, 2021
bcc51d9
iox-#33 Fix review findings
elfenpiff Jun 14, 2021
dad28d5
iox-#33 Fix unused warning for gcc
elfenpiff Jun 14, 2021
c72bb80
iox-#33 Fix shared memory moduletest
elfenpiff Jun 14, 2021
cf67c17
iox-#33 Add platform setting for max shm name length
elfenpiff Jun 14, 2021
6b1d6aa
iox-#33 Try to select right header for mac os SHM_NAME_MAX
elfenpiff Jun 14, 2021
a4588d9
iox-#33 Use MAX_SHM_NAME_LENGTH value from windows in mac
elfenpiff Jun 14, 2021
49f9a0e
iox-#33 Increase SIGBUS_ERROR_MESSAGE_LENGTH
elfenpiff Jun 14, 2021
2c4647a
iox-#33 Introduce iox_shm_unlink
elfenpiff Jun 14, 2021
8de03e1
iox-#33 Add missing mac os errno header
elfenpiff Jun 14, 2021
46d651f
iox-#33 Address review findings
elfenpiff Jun 15, 2021
f2940dd
iox-#33 Fix Timer timing test
elfenpiff Jun 15, 2021
2c301e0
iox-#33 Cleanup shared memory test
elfenpiff Jun 15, 2021
22f6dd4
iox-#33 Add copyright header, consistent variable naming
elfenpiff Jun 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class SharedMemoryObject : public DesignPattern::Creation<SharedMemoryObject, Sh
SharedMemoryObject(const SharedMemory::Name_t& name,
const uint64_t memorySizeInBytes,
const AccessMode accessMode,
const Policy policy,
const OpenMode openMode,
const void* baseAddressHint,
const mode_t permissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ enum class AccessMode : uint64_t
static constexpr const char* ACCESS_MODE_STRING[] = {"AccessMode::READ_ONLY", "AccessMode::READ_WRITE"};

/// @brief describes how the shared memory is opened or created
enum class Policy : uint64_t
enum class OpenMode : uint64_t
{
/// @brief creates the shared memory, if it exists already the construction will fail
EXCLUSIVE_CREATE = 0U,
Expand All @@ -46,10 +46,10 @@ enum class Policy : uint64_t
/// @brief creates the shared memory, if it does not exist otherwise it opens it
OPEN_OR_CREATE = 2U,
/// @brief opens the shared memory, if it does not exist it will fail
OPEN = 3U
OPEN_EXISTING = 3U
};
static constexpr const char* POLICY_STRING[] = {
"Policy::EXCLUSIVE_CREATE", "Policy::PURGE_AND_CREATE", "Policy::CREATE_OR_OPEN", "Policy::OPEN"};
static constexpr const char* OPEN_MODE_STRING[] = {
"OpenMode::EXCLUSIVE_CREATE", "OpenMode::PURGE_AND_CREATE", "OpenMode::CREATE_OR_OPEN", "OpenMode::OPEN_EXISTING"};
elfenpiff marked this conversation as resolved.
Show resolved Hide resolved

enum class SharedMemoryError
{
Expand Down Expand Up @@ -87,25 +87,26 @@ class SharedMemory : public DesignPattern::Creation<SharedMemory, SharedMemoryEr
int32_t getHandle() const noexcept;
bool hasOwnership() const noexcept;

static bool unlinkIfExist(const Name_t& name) noexcept;
static cxx::expected<bool, SharedMemoryError> unlinkIfExist(const Name_t& name) noexcept;

friend class DesignPattern::Creation<SharedMemory, SharedMemoryError>;

private:
SharedMemory(const Name_t& name,
const AccessMode accessMode,
const Policy policy,
const OpenMode openMode,
const mode_t permissions,
const uint64_t size) noexcept;

bool open(const AccessMode accessMode, const Policy policy, const mode_t permissions, const uint64_t size) noexcept;
bool
open(const AccessMode accessMode, const OpenMode openMode, const mode_t permissions, const uint64_t size) noexcept;
bool unlink() noexcept;
bool close() noexcept;
void destroy() noexcept;
void reset() noexcept;
static int getOflagsFor(const AccessMode accessMode, const Policy policy) noexcept;
static int getOflagsFor(const AccessMode accessMode, const OpenMode openMode) noexcept;

SharedMemoryError errnoToEnum(const int32_t errnum) const noexcept;
static SharedMemoryError errnoToEnum(const int32_t errnum) noexcept;

Name_t m_name;
int m_handle{INVALID_HANDLE};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@
#undef interface
#undef CreateSemaphore
#undef NO_ERROR
#undef OPEN_EXISTING
2 changes: 1 addition & 1 deletion iceoryx_hoofs/source/posix_wrapper/named_pipe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ NamedPipe::NamedPipe(const IpcChannelName_t& name,
// m_messages. when we add the alignment it is guaranteed that enough memory should be available.
sizeof(MessageQueue_t) + alignof(MessageQueue_t),
AccessMode::READ_WRITE,
(channelSide == IpcChannelSide::SERVER) ? Policy::OPEN_OR_CREATE : Policy::OPEN,
(channelSide == IpcChannelSide::SERVER) ? OpenMode::OPEN_OR_CREATE : OpenMode::OPEN_EXISTING,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why OPEN_OR_CREATE? It's different from our current IpcChannel implementations

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is correct but it is absolutely no problem to support multiple readers and writes for named pipes and therefore I wanted to use this advantage right from the beginning. I felt that restricting this to single server multiple clients would gain nothing.

The restriction would require more code (for the error handling when a named pipe already exists and you would like to create a server) and would have less flexibility and this seemed just weird.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does the shm behave i unlink is called even if there are other applications which have it still mapped into address space? Can they sill use the shm or do they crash?

Oh, and with this approach it is also possible to "steal" messages from the server without him even noticing it. The message queue has the same problem though, not sure about the unix domain socket.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can they sill use the shm or do they crash?

They will crash and burn. Yeah this is maybe dangerous to use but when we restrict this I would restrict this on a higher level - for instance in a real IpcChannel abstraction. The posix wrappers do not restrict functionality they provide the developer with what is possible (with a safe API) so that they can decide howto handle it with logic or restrictions.

"steal" messages?

Actually we can solve this problem easily with ACLs. Then only the trustworthy applications have read/write access. Also every client can steal messages from a named pipe since the server and the client requires write access.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. It might be quite difficult to prevent stealing with the NamedPipe. I guess it should not be used in environments where this is a problem.

iox::posix::SharedMemoryObject::NO_ADDRESS_HINT);

if (sharedMemory.has_error())
Expand Down
14 changes: 7 additions & 7 deletions iceoryx_hoofs/source/posix_wrapper/shared_memory_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@ static void memsetSigbusHandler(int)
SharedMemoryObject::SharedMemoryObject(const SharedMemory::Name_t& name,
const uint64_t memorySizeInBytes,
const AccessMode accessMode,
const Policy policy,
const OpenMode openMode,
const void* baseAddressHint,
const mode_t permissions)
: m_memorySizeInBytes(cxx::align(memorySizeInBytes, Allocator::MEMORY_ALIGNMENT))
{
m_isInitialized = true;

SharedMemory::create(name, accessMode, policy, permissions, m_memorySizeInBytes)
SharedMemory::create(name, accessMode, openMode, permissions, m_memorySizeInBytes)
.and_then([this](auto& sharedMemory) { m_sharedMemory.emplace(std::move(sharedMemory)); })
.or_else([this](auto&) {
std::cerr << "Unable to create SharedMemoryObject since we could not acquire a SharedMemory resource"
Expand All @@ -79,9 +79,9 @@ SharedMemoryObject::SharedMemoryObject(const SharedMemory::Name_t& name,
std::cerr << "Unable to create a shared memory object with the following properties [ name = " << name
<< ", sizeInBytes = " << memorySizeInBytes
<< ", access mode = " << ACCESS_MODE_STRING[static_cast<uint64_t>(accessMode)]
<< ", policy = " << POLICY_STRING[static_cast<uint64_t>(policy)] << ", baseAddressHint = " << std::hex
<< baseAddressHint << ", permissions = " << std::bitset<sizeof(mode_t)>(permissions) << " ]"
<< std::endl;
<< ", open mode = " << OPEN_MODE_STRING[static_cast<uint64_t>(openMode)]
<< ", baseAddressHint = " << std::hex << baseAddressHint
<< ", permissions = " << std::bitset<sizeof(mode_t)>(permissions) << " ]" << std::endl;
return;
}

Expand All @@ -102,12 +102,12 @@ SharedMemoryObject::SharedMemoryObject(const SharedMemory::Name_t& name,
SIGBUS_ERROR_MESSAGE_LENGTH,
"While setting the acquired shared memory to zero a fatal SIGBUS signal appeared caused by memset. The "
"shared memory object with the following properties [ name = %s, sizeInBytes = %llu, access mode = %s, "
"policy = %s, baseAddressHint = %p, permissions = %lu ] maybe requires more memory than it is "
"open mode = %s, baseAddressHint = %p, permissions = %lu ] maybe requires more memory than it is "
"currently available in the system.\n",
name.c_str(),
static_cast<unsigned long long>(memorySizeInBytes),
ACCESS_MODE_STRING[static_cast<uint64_t>(accessMode)],
POLICY_STRING[static_cast<uint64_t>(policy)],
OPEN_MODE_STRING[static_cast<uint64_t>(openMode)],
baseAddressHint,
std::bitset<sizeof(mode_t)>(permissions).to_ulong());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ namespace posix
{
SharedMemory::SharedMemory(const Name_t& name,
const AccessMode accessMode,
const Policy policy,
const OpenMode openMode,
const mode_t permissions,
const uint64_t size) noexcept
{
Expand All @@ -57,14 +57,14 @@ SharedMemory::SharedMemory(const Name_t& name,
if (m_isInitialized)
{
m_name = name;
m_isInitialized = open(accessMode, policy, permissions, size);
m_isInitialized = open(accessMode, openMode, permissions, size);
}

if (!m_isInitialized)
{
std::cerr << "Unable to create shared memory with the following properties [ name = " << name
<< ", access mode = " << ACCESS_MODE_STRING[static_cast<uint64_t>(accessMode)]
<< ", policy = " << POLICY_STRING[static_cast<uint64_t>(policy)]
<< ", open mode = " << OPEN_MODE_STRING[static_cast<uint64_t>(openMode)]
<< ", mode = " << std::bitset<sizeof(mode_t)>(permissions) << ", sizeInBytes = " << size << " ]"
<< std::endl;
return;
Expand All @@ -76,11 +76,11 @@ SharedMemory::~SharedMemory() noexcept
destroy();
}

int SharedMemory::getOflagsFor(const AccessMode accessMode, const Policy policy) noexcept
int SharedMemory::getOflagsFor(const AccessMode accessMode, const OpenMode openMode) noexcept
{
int oflags = 0;
oflags |= (accessMode == AccessMode::READ_ONLY) ? O_RDONLY : O_RDWR;
oflags |= (policy != Policy::OPEN) ? O_CREAT | O_EXCL : 0;
oflags |= (openMode != OpenMode::OPEN_EXISTING) ? O_CREAT | O_EXCL : 0;
elBoberido marked this conversation as resolved.
Show resolved Hide resolved
return oflags;
}

Expand Down Expand Up @@ -134,40 +134,41 @@ bool SharedMemory::hasOwnership() const noexcept
}

bool SharedMemory::open(const AccessMode accessMode,
const Policy policy,
const OpenMode openMode,
const mode_t permissions,
const uint64_t size) noexcept
{
cxx::Expects(size <= static_cast<uint64_t>(std::numeric_limits<int64_t>::max()));

m_hasOwnership =
(policy == Policy::EXCLUSIVE_CREATE || policy == Policy::PURGE_AND_CREATE || policy == Policy::OPEN_OR_CREATE);
m_hasOwnership = (openMode == OpenMode::EXCLUSIVE_CREATE || openMode == OpenMode::PURGE_AND_CREATE
|| openMode == OpenMode::OPEN_OR_CREATE);

// the mask will be applied to the permissions, therefore we need to set it to 0
mode_t umaskSaved = umask(0U);
{
cxx::GenericRAII umaskGuard([&] { umask(umaskSaved); });

if (policy == Policy::PURGE_AND_CREATE)
if (openMode == OpenMode::PURGE_AND_CREATE)
{
IOX_DISCARD_RESULT(posixCall(shm_unlink)(m_name.c_str())
.failureReturnValue(INVALID_HANDLE)
.ignoreErrnos(ENOENT)
.evaluate());
}

auto result = posixCall(iox_shm_open)(m_name.c_str(), getOflagsFor(accessMode, policy), permissions)
auto result = posixCall(iox_shm_open)(m_name.c_str(), getOflagsFor(accessMode, openMode), permissions)
elfenpiff marked this conversation as resolved.
Show resolved Hide resolved
.failureReturnValue(INVALID_HANDLE)
.suppressErrorMessagesForErrnos((policy == Policy::OPEN_OR_CREATE) ? EEXIST : 0)
.suppressErrorMessagesForErrnos((openMode == OpenMode::OPEN_OR_CREATE) ? EEXIST : 0)
.evaluate();
if (result.has_error())
{
// if it was not possible to create the shm exclusively someone else has the
// ownership and we just try to open it
if (policy == Policy::OPEN_OR_CREATE && result.get_error().errnum == EEXIST)
if (openMode == OpenMode::OPEN_OR_CREATE && result.get_error().errnum == EEXIST)
{
m_hasOwnership = false;
result = posixCall(iox_shm_open)(m_name.c_str(), getOflagsFor(accessMode, Policy::OPEN), permissions)
result = posixCall(iox_shm_open)(
m_name.c_str(), getOflagsFor(accessMode, OpenMode::OPEN_EXISTING), permissions)
.failureReturnValue(INVALID_HANDLE)
.evaluate();
elfenpiff marked this conversation as resolved.
Show resolved Hide resolved
if (!result.has_error())
Expand All @@ -177,7 +178,7 @@ bool SharedMemory::open(const AccessMode accessMode,
}
}

m_errorValue = this->errnoToEnum(result.get_error().errnum);
m_errorValue = errnoToEnum(result.get_error().errnum);
return false;
}
m_handle = result->value;
Expand All @@ -188,7 +189,7 @@ bool SharedMemory::open(const AccessMode accessMode,
if (posixCall(ftruncate)(m_handle, static_cast<int64_t>(size))
.failureReturnValue(INVALID_HANDLE)
.evaluate()
.or_else([this](auto& r) { m_errorValue = this->errnoToEnum(r.errnum); })
.or_else([this](auto& r) { m_errorValue = errnoToEnum(r.errnum); })
.has_error())
{
return false;
Expand All @@ -198,13 +199,25 @@ bool SharedMemory::open(const AccessMode accessMode,
return true;
}

bool SharedMemory::unlinkIfExist(const Name_t& name) noexcept
cxx::expected<bool, SharedMemoryError> SharedMemory::unlinkIfExist(const Name_t& name) noexcept
{
return !posixCall(shm_unlink)(name.c_str())
.failureReturnValue(INVALID_HANDLE)
.suppressErrorMessagesForErrnos(ENOENT)
.evaluate()
.has_error();
auto result = posixCall(shm_unlink)(name.c_str())
.failureReturnValue(INVALID_HANDLE)
.suppressErrorMessagesForErrnos(ENOENT)
.evaluate();

if (result.has_error())
{
auto& error = result.get_error();
if (error.errnum == ENOENT)
{
return cxx::success<bool>(false);
}

return cxx::error<SharedMemoryError>(errnoToEnum(error.errnum));
}

return cxx::success<bool>(true);
}

bool SharedMemory::unlink() noexcept
Expand Down Expand Up @@ -235,12 +248,12 @@ bool SharedMemory::close() noexcept
return true;
}

SharedMemoryError SharedMemory::errnoToEnum(const int32_t errnum) const noexcept
SharedMemoryError SharedMemory::errnoToEnum(const int32_t errnum) noexcept
{
switch (errnum)
{
case EACCES:
std::cerr << "No permission to modify, truncate or to access the shared memory!" << std::endl;
std::cerr << "No permission to modify, truncate or access the shared memory!" << std::endl;
return SharedMemoryError::INSUFFICIENT_PERMISSIONS;
case EPERM:
std::cerr << "Resizing a file beyond its current size is not supported by the filesystem!" << std::endl;
Expand Down
Loading