-
Notifications
You must be signed in to change notification settings - Fork 397
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2348 from elBoberido/iox-2301-mixed-mode-32-and-6…
…4-bit iox-#2301 Mixed mode 32 and 64 bit
- Loading branch information
Showing
33 changed files
with
1,246 additions
and
302 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
build/ | ||
build-*/ | ||
build_out_of_tree/ | ||
build_package/ | ||
install/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
# Status | ||
|
||
iceoryx works on 32-bit hardware, but only as technology preview and is not meant for production. | ||
|
||
See also https://github.com/eclipse-iceoryx/iceoryx/issues/2301 for more details and the limitations sections in this document. | ||
|
||
# Dependencies | ||
|
||
For 32-bit support, the following packages need to be installed on ubuntu | ||
|
||
```bash | ||
sudo dpkg --add-architecture i386 | ||
sudo apt install libacl1-dev:i386 libc6-dev-i386 libc6-dev-i386-cross libstdc++6-i386-cross gcc-multilib g++-multilib | ||
``` | ||
|
||
# iceoryx as 32-bit library | ||
|
||
## Build steps | ||
|
||
The simplest way to build iceoryx is via the `iceoryx_build_test.sh` script | ||
|
||
```bash | ||
tools/iceoryx_build_test.sh release 32-bit-x86 | ||
``` | ||
|
||
If the script cannot be used, this are the steps with `cmake` on x86 | ||
|
||
```bash | ||
cmake -S iceoryx_meta -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-m32 -malign-double" -DCMAKE_CXX_FLAGS="-m32 -malign-double" | ||
cmake --build build | ||
``` | ||
|
||
The `-m32` flag tells GCC to build iceoryx as 32-bit library on a 64-bit system. | ||
The `-malign-double` flag is required to have 64-bit atomics on an 8 byte boundary. | ||
Furthermore, it is required for the 32-64 bit mix-mode to enforce the same data layout when 32-bit application communicate with 64-bit applications. | ||
|
||
## Limitations | ||
|
||
An internal data structure, the `UsedChunkList`, might be left in a corrupt state when an application terminates abnormally when writing to this data structure. | ||
In order to detect torn-writes on 32-bit, the data structure needs to be refactored. | ||
|
||
# iceoryx for communication between 32-bit and 64-bit applications aka 32-64 bit mix-mode | ||
|
||
## Attention | ||
|
||
Mixing 32-bit and 64-bit applications in a shared-memory environment is a non-trivial endeavor. | ||
Since the data structures are shared between applications with varying bitness, one has to take special care of the layout of the data structures shared between the applications. | ||
|
||
For example, the following struct has a size of 16 bytes and is aligned to 8 byte on common 64-bit architectures like x86-64. | ||
But on common 32-bit architectures like x86, it has a size of 12 bytes and is aligned to 4 bytes. | ||
|
||
```cpp | ||
struct Foo { | ||
bool bar {false}; | ||
uint64_t baz {0}; | ||
}; | ||
``` | ||
As long as the applications share the same bitness, there is no need for special consideration. | ||
However, when connecting 32-bit and 64-bit applications via shared memory, both must adhere to a common memory layout. | ||
If the layout differs, it can lead to unpredictable behavior and errors in the applications. | ||
The simplest way to fix this specific alignment issue, is to use the `-malign-double` flag, which enforces an 8 byte alignment boundary for 64-bit data types on 32-bit architectures. | ||
## Build steps | ||
Similar to the 32-bit build, the simplest way to build for the 32-64 bit mix-mode is the `iceoryx_build_test.sh` script | ||
```bash | ||
tools/iceoryx_build_test.sh release examples 32-bit-x86 experimental-32-64-bit-mix-mode --build-dir build-32 | ||
tools/iceoryx_build_test.sh release examples experimental-32-64-bit-mix-mode --build-dir build-64 | ||
``` | ||
|
||
If the script cannot be used, this are the steps with `cmake` on x86 | ||
|
||
```bash | ||
cmake -S iceoryx_meta -B build-32 -DCMAKE_BUILD_TYPE=Release -DEXAMPLES=ON -DCMAKE_C_FLAGS="-m32 -malign-double" -DCMAKE_CXX_FLAGS="-m32 -malign-double" -DIOX_EXPERIMENTAL_32_64_BIT_MIX_MODE=ON | ||
cmake --build build-32 | ||
|
||
cmake -S iceoryx_meta -B build-64 -DCMAKE_BUILD_TYPE=Release -DEXAMPLES=ON -DIOX_EXPERIMENTAL_32_64_BIT_MIX_MODE=ON | ||
cmake --build build-64 | ||
``` | ||
|
||
## Running the examples | ||
|
||
You can now mix and match 32-bit and 64-bit applications | ||
|
||
```bash | ||
# terminal 1 | ||
build-32/iox-roudi | ||
|
||
# terminal 2 | ||
build-64/iceoryx_examples/request_response/iox-cpp-request-response-listener-server | ||
|
||
# terminal 3 | ||
build-32/iceoryx_examples/request_response/iox-cpp-request-response-waitset-client | ||
``` | ||
|
||
## Limitations | ||
|
||
In addition to the limitations of the 32-bit iceoryx, the mix-mode needs to ensure that all the data structures in shared memory have the same layout. | ||
While the `-malign-double` flag can be used for the iceoryx data types, it does not work for POSIX data structures like `sem_t`. | ||
These data types also have a different size for 32-bit and 64-bit architecture and are used in iceoryx in the shared-memory, e.g. for the `WaitSet`. | ||
In order to make the iceoryx applications interoperable between 32-bit and 64-bit, a spin lock and a spin semaphore is used for their POSIX counterparts. | ||
This can increase the CPU load and also the latency. | ||
|
||
For a production environment, the spin semaphore and spin lock needs to be replaced by a `futex` on Linux and a `WaitOnAddress` call on Windows. | ||
For other OSes, a proper solution is yet to be found. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// Copyright (c) 2024 by ekxide IO GmbH. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
#ifndef IOX_HOOFS_CONCURRENT_SYNC_SPIN_LOCK_HPP | ||
#define IOX_HOOFS_CONCURRENT_SYNC_SPIN_LOCK_HPP | ||
|
||
#include "iceoryx_platform/unistd.hpp" | ||
#include "iox/atomic.hpp" | ||
#include "iox/lock_interface.hpp" | ||
|
||
#include <thread> | ||
|
||
namespace iox | ||
{ | ||
namespace concurrent | ||
{ | ||
class SpinLockBuilder; | ||
|
||
/// @brief A spin lock implementation as drop-in replacement for a mutex | ||
class SpinLock : public LockInterface<SpinLock> | ||
{ | ||
public: | ||
using Builder = SpinLockBuilder; | ||
|
||
SpinLock(const SpinLock&) = delete; | ||
SpinLock(SpinLock&&) = delete; | ||
SpinLock& operator=(const SpinLock&) = delete; | ||
SpinLock& operator=(SpinLock&&) = delete; | ||
|
||
~SpinLock() noexcept = default; | ||
|
||
private: | ||
friend class optional<SpinLock>; | ||
friend class LockInterface<SpinLock>; | ||
|
||
explicit SpinLock(const LockBehavior lock_behavior) noexcept; | ||
|
||
expected<void, LockError> lock_impl() noexcept; | ||
|
||
expected<void, UnlockError> unlock_impl() noexcept; | ||
|
||
expected<TryLock, TryLockError> try_lock_impl() noexcept; | ||
|
||
struct LockInfo | ||
{ | ||
pid_t tid; | ||
uint32_t recursive_count; | ||
}; | ||
|
||
private: | ||
concurrent::AtomicFlag m_lock_flag = | ||
ATOMIC_FLAG_INIT; // NOTE: only initialization via assignment is guaranteed to work | ||
const concurrent::Atomic<bool> m_recursive{false}; | ||
concurrent::Atomic<pid_t> m_pid{0}; | ||
concurrent::Atomic<uint64_t> m_recursive_count{0}; | ||
concurrent::Atomic<std::thread::id> m_tid{}; | ||
}; | ||
|
||
class SpinLockBuilder | ||
{ | ||
public: | ||
enum class Error : uint8_t | ||
{ | ||
LOCK_ALREADY_INITIALIZED, | ||
INTER_PROCESS_LOCK_UNSUPPORTED_BY_PLATFORM, | ||
UNKNOWN_ERROR | ||
}; | ||
|
||
/// @brief Defines if the SpinLock should be usable in an inter process context. Default: true | ||
IOX_BUILDER_PARAMETER(bool, is_inter_process_capable, true) | ||
|
||
/// @brief Sets the LockBehavior, default: LockBehavior::RECURSIVE | ||
IOX_BUILDER_PARAMETER(LockBehavior, lock_behavior, LockBehavior::RECURSIVE) | ||
|
||
public: | ||
/// @brief Initializes a provided uninitialized SpinLock | ||
/// @param[in] uninitializedLock the uninitialized SpinLock which should be initialized | ||
/// @return On failure LockCreationError which explains the error | ||
expected<void, Error> create(optional<SpinLock>& uninitializedLock) noexcept; | ||
}; | ||
|
||
} // namespace concurrent | ||
} // namespace iox | ||
|
||
#endif // IOX_HOOFS_CONCURRENT_SYNC_SPIN_LOCK_HPP |
86 changes: 86 additions & 0 deletions
86
iceoryx_hoofs/concurrent/sync/include/iox/spin_semaphore.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
|
||
// Copyright (c) 2024 by ekxide IO GmbH. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
#ifndef IOX_HOOFS_CONCURRENT_SYNC_SPIN_SEMAPHORE_HPP | ||
#define IOX_HOOFS_CONCURRENT_SYNC_SPIN_SEMAPHORE_HPP | ||
|
||
#include "iox/atomic.hpp" | ||
#include "iox/deadline_timer.hpp" | ||
#include "iox/detail/adaptive_wait.hpp" | ||
#include "iox/optional.hpp" | ||
#include "iox/semaphore_interface.hpp" | ||
#include "iox/spin_lock.hpp" | ||
|
||
namespace iox | ||
{ | ||
namespace concurrent | ||
{ | ||
class SpinSemaphoreBuilder; | ||
|
||
class SpinSemaphore : public detail::SemaphoreInterface<SpinSemaphore> | ||
{ | ||
public: | ||
using Builder = SpinSemaphoreBuilder; | ||
|
||
SpinSemaphore(const SpinSemaphore&) = delete; | ||
SpinSemaphore(SpinSemaphore&&) = delete; | ||
SpinSemaphore& operator=(const SpinSemaphore&) = delete; | ||
SpinSemaphore& operator=(SpinSemaphore&&) = delete; | ||
|
||
~SpinSemaphore() noexcept; | ||
|
||
private: | ||
friend class optional<SpinSemaphore>; | ||
friend class detail::SemaphoreInterface<SpinSemaphore>; | ||
|
||
explicit SpinSemaphore(int32_t initial_value) noexcept; | ||
|
||
expected<void, SemaphoreError> post_impl() noexcept; | ||
|
||
expected<void, SemaphoreError> wait_impl() noexcept; | ||
|
||
expected<bool, SemaphoreError> try_wait_impl() noexcept; | ||
|
||
expected<SemaphoreWaitState, SemaphoreError> timed_wait_impl(const units::Duration& timeout) noexcept; | ||
|
||
private: | ||
concurrent::Atomic<int32_t> m_count{0}; | ||
concurrent::Atomic<bool> m_to_be_destroyed{false}; | ||
optional<concurrent::SpinLock> m_spinlock; | ||
}; | ||
|
||
class SpinSemaphoreBuilder | ||
{ | ||
/// @brief Set the initial value of the spin semaphore | ||
IOX_BUILDER_PARAMETER(uint32_t, initialValue, 0U) | ||
|
||
/// @brief Set if the spin semaphore can be stored in the shared memory | ||
/// for inter process usage | ||
IOX_BUILDER_PARAMETER(bool, isInterProcessCapable, true) | ||
|
||
public: | ||
/// @brief Create a spin semaphore | ||
/// @param[in] uninitializedSemaphore since the semaphore is not movable the user has to provide | ||
/// memory to store the semaphore into - packed in an optional | ||
/// @return an error describing the failure or success | ||
expected<void, SemaphoreError> create(optional<SpinSemaphore>& uninitializedSemaphore) const noexcept; | ||
}; | ||
|
||
} // namespace concurrent | ||
} // namespace iox | ||
|
||
#endif // IOX_HOOFS_CONCURRENT_SYNC_SPIN_LOCK_HPP |
Oops, something went wrong.