sync: use `mfence` on windows-tcc (#6079)

pull/6080/head
Uwe Krüger 2020-08-06 17:31:05 +02:00 committed by GitHub
parent ea76a33b43
commit d63daa0798
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 17 additions and 11 deletions

View File

@ -123,7 +123,7 @@ __CRT_INLINE SHORT _InterlockedExchangeAdd16(SHORT volatile *Addend, SHORT Value
#define InterlockedIncrement64 _InterlockedExchangeAdd64 #define InterlockedIncrement64 _InterlockedExchangeAdd64
__CRT_INLINE VOID __faststorefence() { __CRT_INLINE VOID __faststorefence() {
__asm__ __volatile__ ("sfence"); __asm__ __volatile__ ("mfence");
} }
#endif #endif

View File

@ -40,7 +40,7 @@ fn test_select() {
go do_send_byte(mut chb) go do_send_byte(mut chb)
go do_send_i64(mut chl) go do_send_i64(mut chl)
mut channels := [chi, recch, chl, chb] mut channels := [chi, recch, chl, chb]
directions := [false, true, false, false] directions := [sync.Direction.pop, .push, .pop, .pop]
mut sum := i64(0) mut sum := i64(0)
mut rl := i64(0) mut rl := i64(0)
mut ri := int(0) mut ri := int(0)

View File

@ -71,6 +71,11 @@ mut:
nxt &Subscription nxt &Subscription
} }
enum Direction {
pop
push
}
struct Channel { struct Channel {
writesem Semaphore // to wake thread that wanted to write, but buffer was full writesem Semaphore // to wake thread that wanted to write, but buffer was full
readsem Semaphore // to wake thread that wanted to read, but buffer was empty readsem Semaphore // to wake thread that wanted to read, but buffer was empty
@ -97,17 +102,18 @@ mut: // atomic
} }
pub fn new_channel<T>(n u32) &Channel { pub fn new_channel<T>(n u32) &Channel {
st := sizeof(T)
return &Channel{ return &Channel{
writesem: new_semaphore_init(if n > 0 { n + 1 } else { 1 }) writesem: new_semaphore_init(if n > 0 { n + 1 } else { 1 })
readsem: new_semaphore_init(if n > 0 { u32(0) } else { 1 }) readsem: new_semaphore_init(if n > 0 { u32(0) } else { 1 })
writesem_im: new_semaphore() writesem_im: new_semaphore()
readsem_im: new_semaphore() readsem_im: new_semaphore()
objsize: sizeof(T) objsize: st
queue_length: n queue_length: n
write_free: n write_free: n
read_avail: 0 read_avail: 0
ringbuf: if n > 0 { malloc(int(n * sizeof(T))) } else { byteptr(0) } ringbuf: if n > 0 { malloc(int(n * st)) } else { byteptr(0) }
statusbuf: if n > 0 { vcalloc(int(n * sizeof(u16))) } else { byteptr(0) } statusbuf: if n > 0 { vcalloc(int(n * 2)) } else { byteptr(0) }
write_subscriber: 0 write_subscriber: 0
read_subscriber: 0 read_subscriber: 0
} }
@ -412,13 +418,13 @@ fn (mut ch Channel) try_pop(dest voidptr, no_block bool) bool {
// Wait `timeout` on any of `channels[i]` until one of them can push (`is_push[i] = true`) or pop (`is_push[i] = false`) // Wait `timeout` on any of `channels[i]` until one of them can push (`is_push[i] = true`) or pop (`is_push[i] = false`)
// object referenced by `objrefs[i]`. `timeout = 0` means wait unlimited time // object referenced by `objrefs[i]`. `timeout = 0` means wait unlimited time
pub fn channel_select(mut channels []&Channel, is_push []bool, mut objrefs []voidptr, timeout time.Duration) int { pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []voidptr, timeout time.Duration) int {
assert channels.len == is_push.len assert channels.len == dir.len
assert is_push.len == objrefs.len assert dir.len == objrefs.len
mut subscr := []Subscription{len: channels.len} mut subscr := []Subscription{len: channels.len}
sem := new_semaphore() sem := new_semaphore()
for i, ch in channels { for i, ch in channels {
if is_push[i] { if dir[i] == .push {
mut null16 := u16(0) mut null16 := u16(0)
for !C.atomic_compare_exchange_weak_u16(&ch.write_sub_mtx, &null16, u16(1)) { for !C.atomic_compare_exchange_weak_u16(&ch.write_sub_mtx, &null16, u16(1)) {
null16 = u16(0) null16 = u16(0)
@ -453,7 +459,7 @@ pub fn channel_select(mut channels []&Channel, is_push []bool, mut objrefs []voi
if i >= channels.len { if i >= channels.len {
i -= channels.len i -= channels.len
} }
if is_push[i] { if dir[i] == .push {
if channels[i].try_push(objrefs[i], true) { if channels[i].try_push(objrefs[i], true) {
event_idx = i event_idx = i
goto restore goto restore
@ -477,7 +483,7 @@ pub fn channel_select(mut channels []&Channel, is_push []bool, mut objrefs []voi
restore: restore:
// reset subscribers // reset subscribers
for i, ch in channels { for i, ch in channels {
if is_push[i] { if dir[i] == .push {
mut null16 := u16(0) mut null16 := u16(0)
for !C.atomic_compare_exchange_weak_u16(&ch.write_sub_mtx, &null16, u16(1)) { for !C.atomic_compare_exchange_weak_u16(&ch.write_sub_mtx, &null16, u16(1)) {
null16 = u16(0) null16 = u16(0)