# Hazard pointers - in C++26 vs Julia - concurrency/atomics e.g. for UInt128

**URL:** <https://discourse.julialang.org/t/hazard-pointers-in-c-26-vs-julia-concurrency-atomics-e-g-for-uint128/108866>\
**Category:** Offtopic\
**Tags:** atomic, concurrency\
**Created:** [January 16, 2024, 12:48pm UTC](https://discourse.julialang.org/t/hazard-pointers-in-c-26-vs-julia-concurrency-atomics-e-g-for-uint128/108866 "2024-01-16T12:48:08Z")\
**Posts on this page:** 1\
**Showing post:** 4

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [January 16, 2024, 3:52pm UTC](https://discourse.julialang.org/t/hazard-pointers-in-c-26-vs-julia-concurrency-atomics-e-g-for-uint128/108866/4 "2024-01-16T15:52:28Z")

</div>

I usually trust you since you’re the expert, but I saw:

```julia
8

```

So it only seems to be the “minimum” guaranteed limit. Maybe 16 IS guaranteed on x86, however, but I want that guarantee always(?). Do you think I always have it despite that, or maybe that don’t need it?

It should be 16-byte aligned (by default), but I’m not sure it is/guaranteed on all platforms:

> <https://stackoverflow.com/questions/16703211/why-128bit-variables-should-be-aligned-to-16byte-boundary>

> One reasons is that most SSE2 instructions on X86 require the data to be 128 bit aligned. This design decision would have been made for performance reasons and to avoid overly complex (and hence slow and big) hardware.

FYI, existing on x86:  
[https://www.felixcloutier.com/x86/lddqu](https://www.felixcloutier.com/x86/lddqu)

> LDDQU — Load Unaligned Integer 128 Bits

I do see in Julia.h (implying it might not always be):

> // int128 is 16 bytes aligned on aarch64

In jl\_compute\_field\_offsets (MAX\_ALIGN is only 8):

> <https://github.com/JuliaLang/julia/blob/b058146cafec8405aa07f9647642fd485ea3b5d7/src/datatype.c#L694>

It seems to be fixed in Zig, but not in Rust (any why not for a long time? Seems like a simple fix):

> <https://github.com/rust-lang/rust/issues/54341>
>
> While fixing various bindgen bugs related to \`long double\`, \`int128\`, (https://g…ithub.com/rust-lang-nursery/rust-bindgen/issues/1370, etc).
> 
> I realized that the following Rust program, in my x86\_64 Linux machine:
> 
> \`\`\`rust
> \#\[repr(C)\]
> struct Foo {
> f: u128,
> }
> 
> fn main() {
> println!("Align: {}", ::std::mem::align\_of::\<Foo\>());
> }
> \`\`\`
> 
> Prints \`8\`.
> 
> While the following C program:
> 
> \`\`\`c
> \#include \<stdio.h\>
> 
> struct foo {
> unsigned \_\_int128 t;
> };
> 
> int main() {
> printf("Align: %ld\\n", \_Alignof(struct foo));
> }
> \`\`\`
> 
> Prints \`16\` on the same system. This is pretty unexpected, and means that i128 / u128 are not really usable for FFI / alignment purposes.

> `u128`/`i128` are not FFI-safe when they should be. That’s a bug. That’s why this issue exists and is still open. We also don’t _claim_ that they are FFI safe, so it’s not a soundness bug.

> <https://github.com/ziglang/zig/issues/2987>
>
> \`@cmpxchg\` on x86\_64 supports u128 integers. However \`@alignOf(u128)\` reports 8,… and without \`align(16)\` on the \`u128\`, the code segfaults at runtime. This alignment is reported by LLVM as the "ABI alignment". Is this alignment incorrect? Is the atomic alignment requirement higher? Investigation is needed.
> 
> Here's the test case:
> 
> \`\`\`zig
> test "128-bit cmpxchg" {
> if (builtin.arch != .x86\_64) {
> return error.SkipZigTest;
> }
> var x: u128 = 1234; // segfault at runtime can be fixed by adding align(16) here
> if (@cmpxchgWeak(u128, &x, 99, 5678, .SeqCst, .SeqCst)) |x1| {
> expect(x1 == 1234);
> } else {
> @panic("cmpxchg should have failed");
> }
> 
> while (@cmpxchgWeak(u128, &x, 1234, 5678, .SeqCst, .SeqCst)) |x1| {
> expect(x1 == 1234);
> }
> expect(x == 5678);
> 
> expect(@cmpxchgStrong(u128, &x, 5678, 42, .SeqCst, .SeqCst) == null);
> expect(x == 42);
> }
> \`\`\`

> `@cmpxchg` on x86\_64 supports u128 integers. However `@alignOf(u128)` reports 8, and without `align(16)` on the `u128`, the code segfaults at runtime.

[Now fixed, but if not in Julia, then would also segfault, if using that instruction, so since it’s not likely actually is 16-byte aligned. I suppose that instruction IS used.]

Would you say all structs should be 16 bytes (no larger), 8, 4 etc. for _concurrent programs_ (or use locking)?

Arrays are 64-byte aligned, if large, otherwise only 16-byte aligned, so larger 17, or 32byte has the possibility of straddling cache-line boundary.

> [@Julia alignas: is there a way to specify the alignment of Julia objects in memory?](https://discourse.julialang.org/t/julia-alignas-is-there-a-way-to-specify-the-alignment-of-julia-objects-in-memory/57501/2):
>
> (Julia defaults to 16-byte alignment). If the alignment is just an optimization, however, that may not be so terrible.
> 
> It doesn’t seem crazy to add an `alignment` keyword argument to the `Array` constructor, but the difficulty of supporting Windows is (as usual) a pain point. (You can have an aligned-memory allocator on Windows, but then you can’t use `free` to deallocate it, and so you’d need lower-level hacks for garbage-collection to work.)

---

_[View the full topic](https://discourse.julialang.org/t/hazard-pointers-in-c-26-vs-julia-concurrency-atomics-e-g-for-uint128/108866)._
