Hi,
Rusky wrote:Brendan wrote:Tagged unions are a separate issue. They simply don't work (they attempt to guarantee that unsafe usage will be detected, and then fail to detect unsafe usage).
In Rust, they guarantee that tagged unions are used safely to the same degree that you can guarantee a ranged integer is used safely, using a combination of pointer lifetimes and scoping. Inline assembly is unsafe anyway, so if it uses a union incorrectly then you know exactly where the problem is. In other cases, it forces all enum member access through a match (basically a glorified switch on the tag):
I don't want to force all enum member accesses through a glorified switch. For example, imagine if you've got some TaggedUnion structures floating around your code (where a switch is needed), plus a linked list of TaggedUnion structures where you know "TaggedUnion.Foo" is used and don't need to check, plus a linked list of TaggedUnion structures where you know "TaggedUnion.Bar" is used and don't need to check.
Rusky wrote:As for "foo and bar", that doesn't seem to come up much in my experience, but Combuster did show some ways to deal with it using tagged unions.
I've just been talking to the project manager. Apparently the QA team noticed some stability issues (on a 2-core test machine with 3 users) and traced it back to race conditions in "myTaggedUnion". The project manager was really worried because the production machine is expected to be a 32 core machine handling 500 or more users, and "myTaggedUnion" is going to get pounded from all directions. Basically; it has to be thread safe and it currently isn't. I also asked the project manager if "both foo and bar" will be needed or not, and they won't know until other parts of the project are done.
Here's my thread safe version. Acquiring and releasing a mutex isn't too fast, so I added some optimised versions for 80x86 (atomic reads/writes to avoid the mutex). For the optimised version the compiler should reduce the "myTaggedUnion" down to a single 64-bit integer (removing all other fields), while for the HLL version (for other CPUs) the compiler would remove the "asmdata" field.
Code: Select all
enum tagTypes = {
typeNone = 0
typeFoo
typeBar
}
structdef myTaggedUnion = {
mutex lock
type as tagTypes
foo as u32 ;Trivial structure member co-location!
bar as bool ;Trivial structure member co-location!
asmdata as u64 ;Only used by assembly
}
multitarget setFoo(union as @myTaggedUnion, value as u32) (void) {
functiondef setFoo(union as @myTaggedUnion, value as u32) (void) {
acquireMutex(@(union->lock))
union->type = typeFoo
union->foo = value
releaseMutex(@(union->lock))
}
asmfunction x86_64 setFoo(union as @myTaggedUnion in rdi, value as u32 in rbx) (void) {
mov rax,typeFoo << 32
or rax,rbx
mov [rdi+offset union.asmdata],rax
}
asmfunction x86_32 setFoo(union as @myTaggedUnion in edi, value as u32 in ebx) (void) {
mov ecx,typeFoo
mov eax,[edi+offset union.asmdata]
mov edx,[edi+offset union.asmdata+4]
retry:
lock cmpxchg8b [edi+offset union.asmdata] ;"cmpxchg8b" used as an atomic 64-bit write
jne retry
}
}
multitarget getFoo(union as @myTaggedUnion, badType as exit) (value as u32) {
functiondef getFoo(union as @myTaggedUnion, badType as exit) (value as u32) {
acquireMutex(@(union->lock))
if(union->type != typeFoo) {
releaseMutex(@(union->lock))
exit badType
}
value = union->foo
releaseMutex(@(union->lock))
}
asmfunction x86_64 getFoo(union as @myTaggedUnion in rsi, badType as exit in ebp) (value as u32 in rax) {
mov rax,[rdi+offset union.asmdata]
shld rbx,rax,32
cmp ebx,typeFoo
je OK
exit ebp
OK:
movzx rax,eax
}
asmfunction x86_32 getFoo(union as @myTaggedUnion in esi, badType as exit in ebp) (value as u32 in eax) {
clr eax
clr edx
clr ebx
clr ecx
lock cmpxchg8b [edi+offset union.asmdata] ;"cmpxchg8b" used as an atomic 64-bit read
cmp edx,typeFoo
je OK
exit ebp
OK:
movzx rax,eax
}
}
It'd still be easy to have a "both foo and bar" (even with thread safe code and the optimised assembly versions). Also note that no code in any caller had to be changed at all to do any of this.
Cheers,
Brendan