#Is there any reason why atomic.Value is an extern struct?

1 messages · Page 1 of 1 (latest)

limber stump
polar fox
#

what is the type of your worker._state?
std.atomic.Value is only for basic types such as integers, bools, pointers, int backed enums, floats.

Not sure why exactly it's marked as extern, but probably to ensure that the atomic field indeed is C ABI compatible since atomic operations are resolved when generating machine code (self-hosted or LLVM backend). This is also why atomic operations rely on builtins instead of being part of zig std lib

upbeat viper
#

its extern to have a defined layout when placed explictly in FFI stuff, or to guarantee data layout to avoid false sharing without overalignment

extern struct {
  x: Atomic(u32),
  _pad: [atomic.cache_line]u8,
  data: T,
};
warped shell
#

you can actually _: void align(atomic.cache_line) = {} to get the same thing

#

for http.zig, just make the state enum enum(u8)

upbeat viper
warped shell
#

perhaps

limber stump
polar fox
#

Oh i see, yeah for compatability better off turn it int u8. You could also intCast back to the original backing int so that rest of zig code can use u2

limber stump
limber stump
polar fox
#

i mean intCast is fine if you control the API such that you can guarantee that only u2 range will be stored in the u8

#

That's the point of it - you assert that transition from u8 to u2 in this context is safe

#

But it is more of a hassle, so might as well just use u8 as backing int - it's the smallest unit of storage anyway on most systems

limber stump
#

still seems kinda odd, to have to pay the penalty of ffi without relying on it :/

polar fox
#

I mean it sort of is - CPU has specific constraints on values that can be operated on atomically, so it's modeled around them

limber stump
#

why would passing an extern struct to anything C-land with an atomic even be desired? all the methodes become inaccesible and the type wont even show up in headers as anything special, right?

limber stump
polar fox
#

Does it work with u2 backed enum, have you tried? The type that is pointed to is still limited, though zig docs are bit vague on that:

T must be a pointer, a bool, a float, an integer or an enum.

limber stump
#

as far as im aware byte is the smallest addressable unit of memory (idk really at which point in the zig pipeline this is presumed), so addres of u2 will point to the whole byte and just act as another hint to llvm to dissregard all other illegal states

polar fox
#

Wtf, here the state doesn't even have backing int. Which zig version is that?

limber stump
upbeat viper
polar fox
#

Then yeah, seems arbitrary to have extern on that atomic.Value struct, especially since it's single value. Perhaps designed to access foreign atomics directly

limber stump
# upbeat viper no, they mean different things. You can however store `x: [@sizeOf(T)]u8 align(@...

would you mind clarifying what extern means, in my mind it is a restriction on the layout and allowed types (to be somewhat C compatible), and thus if we think of it as a constraint, it can be passed down the hierarchy (this is a horribly bad idea, i figured out why now, you could have multiple variants of T or backward propagate extern constraint, creating problems in both cases);
but

const T = struct {...};
const TExportable = @extern(T);
const M = extern struct {...};
comptime {
assert(TExportable == M);
}

should be sane, where @extern(T:type) T would compile error on unrepresentable types and otherwise convert struct to extr struct?

limber stump
polar fox
#

i mean this as it is wouldn't be exported in a way accessible from C. But one can use this as an interface to say atomic in a shared memory or to some struct returned from C

limber stump
#

all fair points, i think that for now u8 as the backing int is the best solution and later on nag in the #bikeshed channel about creating 2 versions in stdlib or adding support for comptime struct to extern struct & packed struct translation

upbeat viper
limber stump
# upbeat viper extern means "C layout" normal structs means "compiler defined / undefined" layo...

i mean, id write my own externify function, but zig doesn't allow building arbitrary types in comptime, meaning, (not sure which one) decls or fields would be missing from an externified struct; thus the builtin proposal, to get around the restrictions, otherwise it would be just like defining a new struct with extern at the begining; maybe this is too rare of a usecace and crossing over into creating a bikeshed parkinglot

#

closing question for now, thank you all for great answers

polar fox
#

uhh actually in this case i think comptime would allow generating extern struct. You can't generate functions, but you can construct types at comptime

#

create new struct type, mark it extern, copy the decls as is from original struct, have some methods that allow filling out that extern struct from existing regular struct. Of course would imply copying the values, since layouts wouldn't match for bitcast

upbeat viper
polar fox
#

Right, child types would be biggest hassle at which point it would be simpler to design the extern version of such struct manually

limber stump
#

The basic demo works !!

#

:O