Unfortunately, that fails to compile (the C code) with: In file included from .atspkg/c/test/stack.c:14: .atspkg/c/test/stack.c: In function ‘_057_home_057_vanessa_057_programming_057_ats_057_stack_057_SATS_057_stack_056_sats__push__1__1’: .atspkg/c/test/stack.c:2884:21: error: variable or field ‘__atomic_compare_exchange_tmp’ declared void 2884 | ATSINSmove(tmp5__1, atomic_compare_exchange_strong(ATSPMVrefarg1(arg0), tmpref3__1, tmpref4__1)) ; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from .atspkg/c/test/stack.c:14: .atspkg/c/test/stack.c:6958:21: error: argument 1 of ‘__atomic_compare_exchange’ must be a non-void pointer type 6958 | ATSINSmove(tmp5__2, atomic_compare_exchange_strong(ATSPMVrefarg1(arg0), tmpref3__2, tmpref4__2)) ; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/vanessa/.atspkg/0.3.13/lib/ats2-postiats-0.3.13/ccomp/runtime/pats_ccomp_instrset.h:276:37: note: in definition of macro ‘ATSINSmove’ 276 | #define ATSINSmove(tmp, val) (tmp = val) | ^~~
Since I guess C doesn't allow atomic void pointers for some reason? Cheers, Vanessa On Friday, March 1, 2019 at 11:23:20 PM UTC-6, gmhwxi wrote: > > > If we ignore malloc/free, then lock-free stack implementation > should look more or less like the following code: > > > fun > pop(theStack) = let > var xs0 = theStack > in > case+ xs0 of > | nil() => None_vt() > | cons(x0, xs1) => > if atomic_compare_exchange(theStack, xs0, xs1) > then Some_vt(x0) else pop(theStack) > end > > fun > push(theStack, x0) = let > var xs0 = theStack > val xs1 = cons(x0, xs0) > in > if atomic_compare_exchange(theStack, xs0, xs1) then () else > push(theStack, x0) > end > > On Friday, March 1, 2019 at 11:05:44 PM UTC-5, gmhwxi wrote: >> >> I took a quick look. >> >> The paper gives an algorithm for implementing a queue, and your code >> implements >> a stack. The stack implementation contains a few race conditions. For >> example, say that thread A pops >> and thread B pops as well; after thread A frees a node, thread B could >> try to free it again, resulting in a very >> common crash caused by "double-free". >> >> >> On Thu, Feb 28, 2019 at 12:10 PM Vanessa McHale <vanessa...> wrote: >> >>> Hi all, >>> >>> I've been trying to implement a lock-free stack here: >>> https://github.com/vmchale/stack. Unfortunately, this is not something >>> I'm particularly familiar with, and it segfaults around 70% of the time I >>> try to actually do anything with it. >>> >>> Here is the static bit: >>> >>> %{# >>> #include <stdatomic.h> >>> %} >>> >>> typedef aptr(l: addr) = $extype "_Atomic void**" >>> >>> datavtype pointer_t(a: vt@ype) = >>> | pointer_t of node_t(a) >>> | none_t >>> and node_t(a: vt@ype) = >>> | node_t of @{ value = [ l : addr | l > null ] (a @ l | aptr(l)) >>> , next = pointer_t(a) >>> } >>> >>> vtypedef stack_t(a: vt@ype) = @{ stack_head = pointer_t(a) } >>> >>> castfn release_stack {a:vt@ype} (stack_t(a)) : void >>> >>> fun new {a:vt@ype} (&stack_t(a)? >> stack_t(a)) : void >>> >>> fun {a:vt@ype} push (&stack_t(a) >> stack_t(a), a) : void >>> >>> fun {a:vt@ype} pop (&stack_t(a) >> _) : Option_vt(a) >>> >>> fun newm {a:vt@ype} () : stack_t(a) >>> >>> fn atomic_store {a:vt@ype}{ l : addr | l > null }(a? @ l | aptr(l), a) : >>> (a @ l | void) = >>> "mac#" >>> >>> fn atomic_load {a:vt@ype}{ l : addr | l > null }(a @ l | aptr(l)) : a = >>> "mac#" >>> >>> fn leaky_malloc {a:vt@ype}{ sz : int | sz == sizeof(a) }(sz : >>> size_t(sz)) : >>> [ l : addr | l > null ] (a? @ l | aptr(l)) = >>> "mac#malloc" >>> >>> And here is the implementation: >>> >>> staload "SATS/stack.sats" >>> >>> implement new (st) = >>> st.stack_head := none_t >>> >>> implement {a} push (st, x) = >>> let >>> val (pf_pre | ptr) = leaky_malloc(sizeof<a>) >>> val (pf | ()) = atomic_store(pf_pre | ptr, x) >>> val next_node = node_t(@{ value = (pf | ptr), next = st.stack_head }) >>> val () = st.stack_head := pointer_t(next_node) >>> in end >>> >>> implement {a} pop (st) = >>> case+ st.stack_head of >>> | ~pointer_t (~node_t (nd)) => >>> begin >>> let >>> val (pf | aptr) = nd.value >>> val x = atomic_load(pf | aptr) >>> val () = st.stack_head := nd.next >>> in >>> Some_vt(x) >>> end >>> end >>> | none_t() => None_vt() >>> >>> It's based on the Michael-Scott paper >>> http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf, but I >>> worry about the frees in the pattern match (of ~node_t and ~pointer_t), >>> and in fact this does segfault when I try to use it for parallel directory >>> traversal. >>> >>> Cheers, >>> Vanessa McHale >>> >>> -- >>> You received this message because you are subscribed to the Google >>> Groups "ats-lang-users" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to ats-lan...@googlegroups.com <javascript:>. >>> To post to this group, send email to ats-lan...@googlegroups.com >>> <javascript:>. >>> Visit this group at https://groups.google.com/group/ats-lang-users. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/ats-lang-users/e1a19c62-5759-c930-4684-ffae2dec0813%40iohk.io >>> >>> <https://groups.google.com/d/msgid/ats-lang-users/e1a19c62-5759-c930-4684-ffae2dec0813%40iohk.io?utm_medium=email&utm_source=footer> >>> . >>> >> -- You received this message because you are subscribed to the Google Groups "ats-lang-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-users+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/ats-lang-users/361eb92b-ccfd-469e-9000-609ee524924b%40googlegroups.com.