-
Notifications
You must be signed in to change notification settings - Fork 652
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
Add support for compiling and running NIO on Raspberry Pi 32-bit #383
Conversation
Motivation: Pointers are unsigned on the supported platforms. This makes NIO compile on 32 bit platforms, like AppleWatch. The compilation error is actually not because of UInt, but because of 0xDEADBEEF, which requires full 32 bit width. Modifications: Changed `AtomicBox` storage from `Int` to `UInt`. Result: NIO compiles on 32 bit platforms.
Motivation: When building a datacenter out of Apple Watches w/ shattered glasses, you'll need the ability to build on 32 bit platforms. This fixes building NIOHTTP1 on such platforms. Modifications: This was resetting the parser context pointer using a very long deadly beef. Had to shorted this for 32bit cows. Result: NIOHTTP1 compiles on 32 bit ARM platforms.
Motivation: On 32-bit platforms the ByteBuffer is too big indeed. This is not a real fix for that, but at least it makes it work on 32-bit ARM, even if it will be very slow ... Modifications: Disabled assert on 32-bit ARM. Result: NIO programs do not crash right away on Apple Watch compute clustes.
Motivation: To run k8s NIO clusters on Apple Watches, we need to make the software 32-bit safe. NIO uses a lot of timestamps directly (w/o a dedicated type). And it uses `Int` for those, which is insufficient for the desired ns granularity on 32-bit platforms. I think the proper fix would be to use a proper custom time type, but until then, lets use `Int64` when time values are involved. Modifications: Replace Int w/ Int64 for time calculations. Result: Echo daemon runs on Apple Watch. If you just shout Hello at it, it doesn't answer yet though.
Motivation: Make sourcecode look consistent. Die \t die. Modifications: Fix indent Result: Sources look consistent regardless of tab width.
Can one of the admins verify this patch? |
1 similar comment
Can one of the admins verify this patch? |
Sources/NIOHTTP1/HTTPDecoder.swift
Outdated
parser.data = UnsafeMutableRawPointer(bitPattern: veryDeadBeef) | ||
#else | ||
parser.data = UnsafeMutableRawPointer(bitPattern: 0x0000deadbeef0000) | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jw Do we need this change? I think we only wanted this pointer value to be easy to spot in debuggers and core dumps: does it need to have the deadbeef
portion shifted left 4 bits on 64-bit operating systems or is it ok to leave it in the least significant 32 bits?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can just use a 32 bit value 0xdeadbeef
is totally fine by me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That still needs the UInt32 cast though, because parser.data seems to be Int32.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@helje5 isn’t parser.data a pointer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right it is. I guess the problem is the Swift type overloading again. It will treat 0xdeadbeef as an Int
. At least that's the error w/o the explicit UInt (cannot represent Integer literal as Int or something like that).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but can't we just compress this into one line? parser.data = UnsafeMutableRawPointer(bitPattern: UInt(0xdeadbeef)
? That'll work correctly on all platforms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@helje5 I'm happy with this except for this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should, but you have to remember that we are talking Swift here! ;->
/src/Sources/NIOHTTP1/HTTPDecoder.swift:382:64: error: integer literal '3735928559' overflows when stored into 'Int'
parser.data = UnsafeMutableRawPointer(bitPattern: UInt(0xdeadbeef))
Same issue: UInt essentially has a UInt.init(Int)
, hence Swift will treat the literal as such ...
I have...mixed feelings about this. For NIO's major server-side use-cases 32-bit architectures are not compelling to target. While the convenience of running on a Raspberry Pi is nice, it's certainly not a feature I feel compelled to support. Supporting it would be easier if it we had CI for 32-bit environments, but currently we don't, so the risk of regression here is high. I think we probably need to decide as a team whether we care about supporting 32-bit environments at all: if we do, then we can merge this for 2.0, and if we don't, we can skip it. |
I think you should treat this similar to Swift itself - no official support at all, but accept community PRs which make it work. |
BTW: Why do you think this needs a major version bump? |
I think supporting Raspberry Pi is worthwhile. Swift is attractive to embedded/IoT devices, and there are many things which could be built on top of NIO that would be valuable on Raspberry Pi and similar devices. For example, https://mosquitto.org/ is a widely deployed MQTT broker that runs on Raspberry Pi and it would be really nice if there was a NIO-based MQTT broker. |
assert(MemoryLayout<ByteBuffer>.size <= 3 * MemoryLayout<Int>.size, | ||
"ByteBuffer has size \(MemoryLayout<ByteBuffer>.size) which is larger than the built-in storage of the existential containers.") | ||
#if !arch(arm) // only complain on 64-bit, this is unfortunate reality on 32-bit | ||
assert(MemoryLayout<ByteBuffer>.size <= 3 * MemoryLayout<Int>.size, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can just kill this assertion. We now have much better tests (allocation counters) which will blow up if this assertion would fail
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume there is no chance to make this work better on 32-bit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@helje5 the existential buffer size is 3 words. On 32 bit that means 12 bytes. Given that byte buffer needs one pointer, we’re left with 8 bytes for reader index, writer index, slice begin and end. I don’t think it’s feasible. So unfortunately for 32bit we’ll need to be larger than the builtin storage of an existential. But we still have the byte buffer special case in NIOAny so not all too bad...
@helje5 The changes on |
@weissi Any reason not to just make it an Int64 but provide deprecated compat shims to the old type, so that it can still be accessed and set via Int? |
TBH this kind of code doesn't feel quite right in the first place when you have your own TimeAmount abstraction:
This code probably belongs into a new |
Mqtt broker on top of this |
As Swift is supporting 32-bit environments I think it is important that swift-nio also supports 32-bit. We now have CI for Armv7 32-bit environments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think after changing this PR not to change the public API on 64bit platforms we should take this. Ping @normanmaurer
@swift-nio-bot test this please |
@weissi Agree as long as public API stays the same on 64bit I am happy with the PR |
I will do the #if fix for the 1.x line. Neat shims are a little harder due to the nanoseconds property. In a different PR we should pull out the time calculations out of the main code base into TimeAmount, but let’s just go with the #if arm for this PR |
Motivation: `Int64` is the right choice here, but it breaks SemVer and needs to wait for NIO 2.x. So instead we just use `Int64` on ARM 32-bit, and stick w/ `Int` on the other platforms. Modifications: Added a typealias `TimeAmount.Value` which aliases to `Int` on 64-bit platforms and `Int64` on arch(arm). Result: Result should be SemVer minor.
@weissi @Lukasa PTAL, I added a typealias which should make it SemVer minor. OK with that? BTW: Small hint: You don't need an actual Raspi to test a Raspi build! If you have Docker4Mac, it has QEmu included and can run simple Raspi images (it can't run NIO servers, unfortunately). To build NIO from within a NIO checkout:
Takes about 2.5 mins on my MacPro. |
Motivation: Make code nicer. Modifications: Use 0xdeadbeef on both, 64-bit and 32-bit. Cast using `as`. Result: The source code will be pure beauty. (not, 4-space indent!!)
@swift-nio-bot test this please |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great work, thanks @helje5
Port SwiftNIO to 32-bit platforms
Motivation:
Pretty much every developer in the world want to run MicroExpress applications on Raspberry Pi K8s clusters. The unfortunate precondition to that is getting NIO compiled for RaspberryPi. This PR makes it work.
Modifications:
Two main changes:
Result:
NIO compiles on Raspi 3, 32-bit Ubuntu. I tried the Echo Server, which seems to work, and also the HTTP sample Server, which also seems to work.
P.S.: This should also allow you to run NIO on AppleWatch, which is 32-bit too.