14.10.2013 17:42, robert пишет:
Damn it, you are right I did not think this through, somehow thought the
use in addrOf is enough, which is of course crap. Thank's a lot for your
time, I'll fix this ASAP.

So, here are your revised version:
https://github.com/phobos-x/phobosx/blob/1f0016c84c2043da0b9d2dafe65f54fcf6b6b8fa/source/phobosx/signal.d

Sorry, but you are making the same mistake again.

Lets start from the hardware. Just like a compiler CPU is free to do whatever it wants with passed instructions but guarantee result state will be the same as if it is executed sequentially. And it doesn't assume access from other threads by default (see e.g. "out-of-order execution"). So memory barriers (memory fences) are needed to ensure loads/stores before the barrier are performed and no loads/stores after the barrier are executing. This is what `core.atomic.atomicFence` does and it can be used in e.g. in mutex implementations. As your operations with `_obj` are already atomic no `atomicFence` call is needed.

Now let's assume without loss of generality `InvisibleAddress.address` returns `cast(void*) ~_addr`, inline the `address` call, and remove redundant `atomicFence` call:
```
auto tmp = atomicLoad(_obj);
auto o = cast(void*) ~tmp._addr;
if(o is null) return null;
GC.addrOf(o);

auto tmp1 = atomicLoad(_obj);
if(o is cast(void*) ~tmp1._addr)
    return cast(Object) o;
assert(cast(void*) ~tmp1._addr is null);
return null;
```

As I mentioned above you are making the same incorrect assumption that you know what machine instructions a compiler will generate. Never make such assumptions. Here is an example of how your code can be rewritten by a compiler:
```
auto tmp = atomicLoad(_obj);
if(tmp._addr == -1) return null;
GC.addrOf(cast(void*) ~tmp._addr);

auto tmp1 = atomicLoad(_obj);
if(tmp._addr == tmp1._addr)
    return cast(Object) cast(void*) ~tmp._addr;
assert(tmp1._addr == -1);
return null;
```


--
Денис В. Шеломовский
Denis V. Shelomovskij

Reply via email to