Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scheduler for grand central libdispatch queue #1258

Merged
merged 5 commits into from
Mar 11, 2024

Conversation

RishabhRD
Copy link
Contributor

In his talk "Better Code: Concurrency", @sean-parent said that a tasking system built upon libdispatch would be his 1.0 for the performance. So, just thought implement the same as I needed it for one of my project.

This can be helpful for people who want to use library and have high performance requirements.

I have profiled the libdispatch queue code over a ray tracing application against already existing static_thread_pool implementation. My usecase may not cover all the scenarios but can be good to look into some real applications.

My machine have 8 cores with 8 gigs ram.

libdispatch

  • cpu core usage graph
    libdispatchcpu
  • cpu core usage summary
    dispatchutilization

static_thread_pool

  • cpu core usage graph
    static_thread_pool_cores
  • cpu core usage summary
    static_thread_pool_usage

PS: I know the current bulk implementation of static_thread_pool is not the most optimal approach for my usecase.

Copy link

copy-pr-bot bot commented Feb 23, 2024

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@LeeHowes
Copy link
Contributor

This is a good contribution! In the short-term a free-standing scheduler may make sense but optimally we would hide this under the system scheduler as the default implementation on apple platforms (and configurable when libdispatch is installed elsewhere through the build system). That way nobody needs to think about the availability in the code.

Do you think it's worth merging separately anyway or should we wait and hide this and the static_thread_pool under the system scheduler?

@ericniebler
Copy link
Collaborator

/ok to test

@ericniebler
Copy link
Collaborator

We'll need to add some MacOS test runners.

@RishabhRD
Copy link
Contributor Author

@LeeHowes I just saw the system executor proposal and the PR here and I have to say its awesome. I guess its fine to wait for system executor PR to progress and let it merge with system executor PR. Its going to make things platform independent.

@ericniebler
Copy link
Collaborator

I don't think there's a reason to wait for the system scheduler. I would land this right now, except that without any MacOS test runners, it's not being tested in CI and that's not ok. I'm no GH Actions ninja. I'll see if I can find out how to get some MacOS runners.

@sean-parent
Copy link

sean-parent commented Feb 26, 2024 via email

@ericniebler
Copy link
Collaborator

@RishabhRD am i correct in assuming that you do MacOS development? i have a PR that adds a MacOS test runner, and it seems that a lot of stdexec's tests are SEGFAULT'ing there (see here). Could I trouble you to grab a stack trace and post it here?

@RishabhRD
Copy link
Contributor Author

@ericniebler I don't do mac os development (I do linux development). But luckily I had setup a mac yesterday itself for C++ 😅 .

Pasting a stacktrace generated using lldb

-------------------------------------------------------------------------------
transfer forwards set_stopped calls
-------------------------------------------------------------------------------
/Users/rishabh/git/stdexec/test/stdexec/algos/adaptors/test_transfer.cpp:164
...............................................................................

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:129: FAILED:
  CHECK( called_.load() )
with expansion:
  false

Process 12821 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x1001704c4)
    frame #0: 0x00000001001709c0 test.stdexec`(anonymous namespace)::tag_invoke((null)=set_value_t @ 0x000000016fdfd7df, self=expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> @ 0x000000016fdfd7c8, val=(val_ = 1876941456))::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env>, (anonymous namespace)::val_type3) at receivers.hpp:262:19
   259      }
   260
   261      friend void tag_invoke(ex::set_value_t, expect_value_receiver_ex self, T val) noexcept {
-> 262        *self.dest_ = val;
   263      }
   264
   265      template <typename... Ts>
Target 4: (test.stdexec) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x1001704c4)
  * frame #0: 0x00000001001709c0 test.stdexec`(anonymous namespace)::tag_invoke((null)=set_value_t @ 0x000000016fdfd7df, self=expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> @ 0x000000016fdfd7c8, val=(val_ = 1876941456))::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env>, (anonymous namespace)::val_type3) at receivers.hpp:262:19
    frame #1: 0x0000000100170998 test.stdexec`void void stdexec::__schedule_from::__receiver2<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >::set_value(this=0x000000016fdfd870, __tag=set_value_t @ 0x000000016fdfd7ff, __args=0x000000016fdfda38) &&::'lambda'<typename $T>($T&)::operator()<std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >($T&) const::'lambda'<typename ...$T0>(auto, $T0&...)::operator()<(anonymous namespace)::val_type3, stdexec::__receivers::set_value_t>(auto, $T0&...) const at execution.hpp:4161:19
    frame #2: 0x00000001001708c4 test.stdexec`void stdexec::__schedule_from::__receiver2<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >::set_value(this=0x000000016fdfda90, __tupl=size=2) &&::'lambda'<typename $T>($T&)::operator()<std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >($T&) const at execution.hpp:4159:15
    frame #3: 0x0000000100170804 test.stdexec`decltype(__f=0x000000016fdfda90, __args=size=2)(std::declval<std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3>&>())) std::__1::__invoke[abi:v15006]<stdexec::__schedule_from::__receiver2<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >::set_value() &&::'lambda'<typename $T>($T&), std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3>&>($T&&, std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3>&) at invoke.h:394:23
    frame #4: 0x00000001001707d4 test.stdexec`decltype(this=0x000000016fdfda38, __alts=0x000000016fdfda38) std::__1::__variant_detail::__visitation::__variant::__value_visitor<stdexec::__schedule_from::__receiver2<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >::set_value() &&::'lambda'<typename $T>($T&)>::operator()[abi:v15006]<std::__1::__variant_detail::__alt<1ul, std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >&>(std::__1::__variant_detail::__alt<1ul, std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >&) const at variant:668:14
    frame #5: 0x0000000100170774 test.stdexec`decltype(__f=0x000000016fdfda38, __args=0x000000016fdfda38)(std::declval<std::__1::__variant_detail::__alt<1ul, std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >&>())) std::__1::__invoke[abi:v15006]<std::__1::__variant_detail::__visitation::__variant::__value_visitor<stdexec::__schedule_from::__receiver2<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >::set_value() &&::'lambda'<typename $T>($T&)>, std::__1::__variant_detail::__alt<1ul, std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >&>($T&&, std::__1::__variant_detail::__alt<1ul, std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >&) at invoke.h:394:23
    frame #6: 0x000000010017061c test.stdexec`decltype(__f=0x000000016fdfda38, __vs=0x000000016fdfda38) std::__1::__variant_detail::__visitation::__base::__dispatcher<1ul>::__dispatch[abi:v15006]<std::__1::__variant_detail::__visitation::__variant::__value_visitor<stdexec::__schedule_from::__receiver2<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >::set_value() &&::'lambda'<typename $T>($T&)>&&, std::__1::__variant_detail::__base<(std::__1::__variant_detail::_Trait)0, std::__1::monostate, std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >&>($T, std::__1::__variant_detail::__base<(std::__1::__variant_detail::_Trait)0, std::__1::monostate, std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >&) at variant:548:16
    frame #7: 0x00000001001705a4 test.stdexec`decltype(__visitor=0x000000016fdfda38, __vs=0x000000016fdfda38) std::__1::__variant_detail::__visitation::__base::__visit_alt[abi:v15006]<std::__1::__variant_detail::__visitation::__variant::__value_visitor<stdexec::__schedule_from::__receiver2<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >::set_value() &&::'lambda'<typename $T>($T&)>, std::__1::__variant_detail::__impl<std::__1::monostate, std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >&>($T&&, std::__1::__variant_detail::__impl<std::__1::monostate, std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >&) at variant:511:12
    frame #8: 0x0000000100170514 test.stdexec`decltype(__visitor=0x000000016fdfda38, __vs= Active Type = std::tuple<stdexec::__receivers::set_value_t, val_type3> ) std::__1::__variant_detail::__visitation::__variant::__visit_alt[abi:v15006]<std::__1::__variant_detail::__visitation::__variant::__value_visitor<stdexec::__schedule_from::__receiver2<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >::set_value() &&::'lambda'<typename $T>($T&)>, std::__1::variant<std::__1::monostate, std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >&>($T&&, std::__1::variant<std::__1::monostate, std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >&) at variant:618:12
    frame #9: 0x00000001001704c4 test.stdexec`decltype(__visitor=0x000000016fdfda90, __vs= Active Type = std::tuple<stdexec::__receivers::set_value_t, val_type3> ) std::__1::__variant_detail::__visitation::__variant::__visit_value[abi:v15006]<stdexec::__schedule_from::__receiver2<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >::set_value() &&::'lambda'<typename $T>($T&), std::__1::variant<std::__1::monostate, std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >&>($T&&, std::__1::variant<std::__1::monostate, std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >&) at variant:637:12
    frame #10: 0x00000001001703c8 test.stdexec`decltype(__visitor=0x000000016fdfda90, __vs= Active Type = std::tuple<stdexec::__receivers::set_value_t, val_type3> ) std::__1::visit[abi:v15006]<stdexec::__schedule_from::__receiver2<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >::set_value() &&::'lambda'<typename $T>($T&), std::__1::variant<std::__1::monostate, std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >&, void>($T&&, std::__1::variant<std::__1::monostate, std::__1::tuple<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3> >&) at variant:1713:10
    frame #11: 0x0000000100170364 test.stdexec`stdexec::__schedule_from::__receiver2<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >::set_value(this=0x000000016fdfe0e0) && at execution.hpp:4154:9
    frame #12: 0x00000001001702dc test.stdexec`(anonymous namespace)::tag_invoke((null)=start_t @ 0x000000016fdfdabf, self=0x000000016fdfe0e0)::basic_inline_scheduler<void>::oper<stdexec::__schedule_from::__receiver2<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> > >&) at schedulers.hpp:194:9
    frame #13: 0x000000010016ffd0 test.stdexec`void stdexec::__schedule_from::__schedule_from_impl::$_6::operator(this=0x000000010099a91d, (null)=__ignore @ 0x000000016fdfdb2f, __state=0x000000016fdfe0d8, __rcvr=0x000000016fdfe0c8, (null)=set_value_t @ 0x000000016fdfdb2e, __args=0x000000016fdfe0f0)<stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3, stdexec::__schedule_from::__state<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >(stdexec::__ignore, stdexec::__schedule_from::__state<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >&, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env>&, stdexec::__receivers::set_value_t, (anonymous namespace)::val_type3&&) const at execution.hpp:4250:9
    frame #14: 0x000000010016ff60 test.stdexec`auto void stdexec::__just::__impl<stdexec::__just::just_t>::start::'lambda'<typename $T, typename $T0>(this=0x000000016fdfdc68, __ts=0x000000016fdfe0f0)::operator()<stdexec::__tup::__tuple<std::__1::integer_sequence<unsigned long, 0ul>*, (anonymous namespace)::val_type3>, stdexec::__detail::__receiver<stdexec::_Id<std::__1::integer_sequence<unsigned long, 0ul>*::expect_value_receiver_ex<(anonymous namespace), stdexec::__env::empty_env> >, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::__sexpr::__anon>, stdexec::__mconstant_<0ul>*>::__t>($T, $T0) const::'lambda'<typename ...$T1>($T1&...)::operator()<(anonymous namespace)>($T1&) const at execution.hpp:2040:13
    frame #15: 0x000000010016fe84 test.stdexec`decltype(this=0x000000016fdfdc8f, __fun=0x000000016fdfdc68, __tup=0x000000016fdfe0f0, (null)=0x000000016fdfe0f0)(__declval<decltype(__cpcvr<$T&>)::__f<(anonymous namespace)> >())) stdexec::__tup::__apply_::operator()<void stdexec::__just::__impl<stdexec::__just::just_t>::start::'lambda'<typename $T, typename $T0>($T&, $T0&)::operator()<stdexec::__tup::__tuple<std::__1::integer_sequence<unsigned long, 0ul>*, (anonymous namespace)::val_type3>, stdexec::__detail::__receiver<stdexec::_Id<std::__1::integer_sequence<unsigned long, 0ul>*::expect_value_receiver_ex<(anonymous namespace), stdexec::__env::empty_env> >, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::__sexpr::__anon>, stdexec::__mconstant_<0ul>*>::__t>($T, $T0) const::'lambda'<typename ...$T1>($T1&...), (anonymous namespace)::val_type3&, 0ul, (anonymous namespace)>(stdexec::__just::__impl<stdexec::__just::just_t>::start&&, $T&, stdexec::__just::__impl<stdexec::__just::just_t>::start::'lambda'<typename $T, typename $T0>($T&, $T0&)::operator()<std::__1<unsigned long, 0ul>*, decltype(__cpcvr<$T&>)::__f...> const*) at __tuple.hpp:85:16
    frame #16: 0x000000010016fe50 test.stdexec`void stdexec::__just::__impl<stdexec::__just::just_t>::start::'lambda'<typename $T, typename $T0>(this=0x0000000100999e68, __state=0x000000016fdfe0f0, __rcvr=0x000000016fdfe0e8)::operator()<stdexec::__tup::__tuple<std::__1::integer_sequence<unsigned long, 0ul>*, (anonymous namespace)::val_type3>, stdexec::__detail::__receiver<stdexec::_Id<std::__1::integer_sequence<unsigned long, 0ul>*::expect_value_receiver_ex<(anonymous namespace), stdexec::__env::empty_env> >, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::__sexpr::__anon>, stdexec::__mconstant_<0ul>*>::__t>($T, $T0) const at execution.hpp:2038:9
    frame #17: 0x000000010016fe00 test.stdexec`auto void stdexec::__detail::tag_invoke<stdexec::__start::start_t>(this=0x000000016fdfdd48)::'lambda39'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__detail::__receiver<stdexec::_Id<(anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__mconstant_<0ul>*>::__t>&)::'lambda'(auto&...)::operator()<>(auto&...) const at __basic_sender.hpp:380:13
    frame #18: 0x000000010016fdc8 test.stdexec`decltype(this=0x000000016fdfdd6f, __fun=0x000000016fdfdd48, __tup=0x000000016fdfe0f4, (null)=0x000000016fdfe0f4)()) stdexec::__tup::__apply_::operator()<void stdexec::__detail::tag_invoke<stdexec::__start::start_t>(stdexec::__start::start_t, stdexec::__detail::__op_state<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda39'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__detail::__receiver<stdexec::_Id<(anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__mconstant_<0ul>*>::__t>&)::'lambda'(auto&...), stdexec::__tup::__tuple<std::__1::integer_sequence<unsigned long>*>&>(stdexec::__start::start_t&&, stdexec::__tup::__tuple<std::__1::integer_sequence<unsigned long>*>&, stdexec::__tup::__tuple<std::__1::integer_sequence<unsigned long>*> const*) at __tuple.hpp:85:16
    frame #19: 0x000000010016fd84 test.stdexec`auto stdexec::__detail::__start::'lambda'<typename $T, typename ...$T0>(this=0x000000010099e0fe, (null)=__ignore @ 0x000000016fdfdd27, (null)=__ignore @ 0x000000016fdfdd26, __ops=0x000000016fdfe0e8)::operator()<stdexec::__start::start_t, stdexec::__detail::__op_state<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda39'(){}, stdexec::__sexpr::__anon>, stdexec::__detail::__receiver<stdexec::_Id<(anonymous namespace)::expect_value_receiver_ex<stdexec::_Id::val_type3, stdexec::__env::empty_env> >, stdexec::__detail::__op_state<stdexec::__sexpr::'lambda44'(){}, stdexec::(anonymous namespace)::'lambda39'()>, stdexec::__mconstant_<0ul>*>::__t> >(stdexec::__detail::__start, stdexec::__detail::__start, $T0&) const at __basic_sender.hpp:202:8
    frame #20: 0x000000010016fcf4 test.stdexec`auto void stdexec::__detail::tag_invoke<stdexec::__start::start_t>(this=0x000000016fdfe090, __ops=0x000000016fdfe0e8)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >&)::'lambda'(auto&...)::operator()<stdexec::__detail::__op_state<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda39'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__detail::__receiver<stdexec::_Id<(anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__mconstant_<0ul>*>::__t> >(auto&...) const at __basic_sender.hpp:380:13
    frame #21: 0x000000010016fc7c test.stdexec`decltype(this=0x000000016fdfe0b7, __fun=0x000000016fdfe090, __tup=0x000000016fdfe0e8, (null)=0x000000016fdfe0e8)(__declval<decltype(__cpcvr<stdexec::__tup::__tuple<std::__1::integer_sequence<unsigned long, 0ul>*, stdexec::__detail::__op_state<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda39'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__detail::__receiver<stdexec::_Id<(anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__mconstant_<0ul>*>::__t> >&>)::__f<stdexec::__detail::__op_state<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda39'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__detail::__receiver<stdexec::_Id<(anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__mconstant_<0ul>*>::__t> > >())) stdexec::__tup::__apply_::operator()<void stdexec::__detail::tag_invoke<stdexec::__start::start_t>(stdexec::__start::start_t, stdexec::__detail::__op_state<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, (anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >&)::'lambda'(auto&...), stdexec::__tup::__tuple<std::__1::integer_sequence<unsigned long, 0ul>*, stdexec::__detail::__op_state<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda39'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__detail::__receiver<stdexec::_Id<(anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__mconstant_<0ul>*>::__t> >&, 0ul, stdexec::__detail::__op_state<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda39'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__detail::__receiver<stdexec::_Id<(anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__mconstant_<0ul>*>::__t> >(stdexec::__start::start_t&&, stdexec::__tup::__tuple<std::__1::integer_sequence<unsigned long, 0ul>*, stdexec::__detail::__op_state<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda39'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__detail::__receiver<stdexec::_Id<(anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__mconstant_<0ul>*>::__t> >&, stdexec::__tup::__tuple<std::__1::integer_sequence<unsigned long, 0ul>*, stdexec::__detail::__op_state<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda39'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__detail::__receiver<stdexec::_Id<(anonymous namespace)::expect_value_receiver_ex<(anonymous namespace)::val_type3, stdexec::__env::empty_env> >, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda44'(){}, stdexec::(anonymous namespace)::__anon>, stdexec::__mconstant_<0ul>*>::__t> > const*) at __tuple.hpp:85:16
    frame #22: 0x0000000100151b7c test.stdexec`(anonymous namespace)::____C_A_T_C_H____T_E_S_T____38() at test_transfer.cpp:277:5
    frame #23: 0x000000010001df30 test.stdexec`Catch::TestInvokerAsFunction::invoke(this=0x0000600000004910) const at catch.hpp:14317:9
    frame #24: 0x0000000100016d0c test.stdexec`Catch::TestCase::invoke(this=0x000000010807d8c0) const at catch.hpp:14156:15
    frame #25: 0x0000000100016c44 test.stdexec`Catch::RunContext::invokeActiveTestCase(this=0x000000016fdfe870) at catch.hpp:13016:27
    frame #26: 0x0000000100015198 test.stdexec`Catch::RunContext::runCurrentTest(this=0x000000016fdfe870, redirectedCout="", redirectedCerr="") at catch.hpp:12989:17
    frame #27: 0x00000001000147e4 test.stdexec`Catch::RunContext::runTest(this=0x000000016fdfe870, testCase=0x000000010807d8c0) at catch.hpp:12750:13
    frame #28: 0x0000000100019570 test.stdexec`Catch::(anonymous namespace)::TestGroup::execute(this=0x000000016fdfe860) at catch.hpp:13343:45
    frame #29: 0x0000000100018ee8 test.stdexec`Catch::Session::runInternal(this=0x000000016fdfeb40) at catch.hpp:13549:39
    frame #30: 0x0000000100018d14 test.stdexec`Catch::Session::run(this=0x000000016fdfeb40) at catch.hpp:13505:24
    frame #31: 0x0000000100030ba8 test.stdexec`int Catch::Session::run<char>(this=0x000000016fdfeb40, argc=1, argv=0x000000016fdfef60) at catch.hpp:13227:30
    frame #32: 0x0000000100030af4 test.stdexec`main(argc=1, argv=0x000000016fdfef60) at catch.hpp:17504:29
    frame #33: 0x0000000180df7f28 dyld`start + 2236

@RishabhRD
Copy link
Contributor Author

Also pasting some tests that are not segfaulting but failing on my mac:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.stdexec is a Catch v2.13.6 host application.
Run with -? for options

-------------------------------------------------------------------------------
transfer_just simple example
-------------------------------------------------------------------------------
/Users/rishabh/git/stdexec/test/stdexec/algos/factories/test_transfer_just.cpp:38
...............................................................................

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:222: FAILED:
  CHECK( self.values_ == std::tie(vals...) )
with expansion:
  {?} == {?}

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:129: FAILED:
  CHECK( called_.load() )
with expansion:
  false

-------------------------------------------------------------------------------
transfer_just can be called with value type scheduler
-------------------------------------------------------------------------------
/Users/rishabh/git/stdexec/test/stdexec/algos/factories/test_transfer_just.cpp:62
...............................................................................

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:222: FAILED:
  CHECK( self.values_ == std::tie(vals...) )
with expansion:
  {?} == {?}

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:129: FAILED:
  CHECK( called_.load() )
with expansion:
  false

-------------------------------------------------------------------------------
transfer_just can be called with rvalue ref scheduler
-------------------------------------------------------------------------------
/Users/rishabh/git/stdexec/test/stdexec/algos/factories/test_transfer_just.cpp:69
...............................................................................

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:222: FAILED:
  CHECK( self.values_ == std::tie(vals...) )
with expansion:
  {?} == {?}

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:129: FAILED:
  CHECK( called_.load() )
with expansion:
  false

-------------------------------------------------------------------------------
transfer_just can be called with const ref scheduler
-------------------------------------------------------------------------------
/Users/rishabh/git/stdexec/test/stdexec/algos/factories/test_transfer_just.cpp:76
...............................................................................

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:222: FAILED:
  CHECK( self.values_ == std::tie(vals...) )
with expansion:
  {?} == {?}

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:129: FAILED:
  CHECK( called_.load() )
with expansion:
  false

-------------------------------------------------------------------------------
transfer_just can be called with ref scheduler
-------------------------------------------------------------------------------
/Users/rishabh/git/stdexec/test/stdexec/algos/factories/test_transfer_just.cpp:84
...............................................................................

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:222: FAILED:
  CHECK( self.values_ == std::tie(vals...) )
with expansion:
  {?} == {?}

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:129: FAILED:
  CHECK( called_.load() )
with expansion:
  false

-------------------------------------------------------------------------------
transfer_just forwards set_stopped calls
-------------------------------------------------------------------------------
/Users/rishabh/git/stdexec/test/stdexec/algos/factories/test_transfer_just.cpp:108
...............................................................................

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:129: FAILED:
  CHECK( called_.load() )
with expansion:
  false

-------------------------------------------------------------------------------
transfer simple example
-------------------------------------------------------------------------------
/Users/rishabh/git/stdexec/test/stdexec/algos/adaptors/test_transfer.cpp:44
...............................................................................

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:222: FAILED:
  CHECK( self.values_ == std::tie(vals...) )
with expansion:
  {?} == {?}

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:129: FAILED:
  CHECK( called_.load() )
with expansion:
  false

-------------------------------------------------------------------------------
transfer can be called with rvalue ref scheduler
-------------------------------------------------------------------------------
/Users/rishabh/git/stdexec/test/stdexec/algos/adaptors/test_transfer.cpp:125
...............................................................................

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:222: FAILED:
  CHECK( self.values_ == std::tie(vals...) )
with expansion:
  {?} == {?}

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:129: FAILED:
  CHECK( called_.load() )
with expansion:
  false

-------------------------------------------------------------------------------
transfer can be called with const ref scheduler
-------------------------------------------------------------------------------
/Users/rishabh/git/stdexec/test/stdexec/algos/adaptors/test_transfer.cpp:132
...............................................................................

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:222: FAILED:
  CHECK( self.values_ == std::tie(vals...) )
with expansion:
  {?} == {?}

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:129: FAILED:
  CHECK( called_.load() )
with expansion:
  false

-------------------------------------------------------------------------------
transfer can be called with ref scheduler
-------------------------------------------------------------------------------
/Users/rishabh/git/stdexec/test/stdexec/algos/adaptors/test_transfer.cpp:140
...............................................................................

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:222: FAILED:
  CHECK( self.values_ == std::tie(vals...) )
with expansion:
  {?} == {?}

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:129: FAILED:
  CHECK( called_.load() )
with expansion:
  false

It can be possible that it is due to the above issue only. But can be useful to have a look.

@RishabhRD
Copy link
Contributor Author

RishabhRD commented Feb 26, 2024

@ericniebler regarding the failing test cases without segfault, with a little effort I printed the values for {?} == {?} in output.

-------------------------------------------------------------------------------
transfer_just simple example
-------------------------------------------------------------------------------
/Users/rishabh/git/stdexec/test/stdexec/algos/factories/test_transfer_just.cpp:38
...............................................................................

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:260: FAILED:
  CHECK( lhs == rhs )
with expansion:
  "(1)" == "(1797266152)"

/Users/rishabh/git/stdexec/test/test_common/receivers.hpp:164: FAILED:
  CHECK( called_.load() )
with expansion:
  false

It seems like set_value is being called with some garbage value.
Edit: Also notice that LHS is also wrong for this case. Because from code I can see we were setting value 13 for receiver expectation. Seems like some lifetime issue.

@ericniebler
Copy link
Collaborator

ericniebler commented Feb 26, 2024

Hrm. Try with -fsanitize=address maybe? EDIT: if it's too much trouble, skip it.

Once we get the macos tests green in CI, I can merge this PR.

@RishabhRD
Copy link
Contributor Author

RishabhRD commented Feb 27, 2024

@ericniebler no its not a trouble. I am doing this because I find it fun. (Believe me, its way better than work at my day job 😅). It makes me feel I am doing something significant and interesting.

I think there is problem with connect call for schedule_from sender.

    auto snd = ex::schedule_from(inline_scheduler{}, ex::just(13));
    auto op = ex::connect(std::move(snd), expect_value_receiver{13});

This is leading to a crash when using address sanitizer. However, it was not producing any stacktrace as such to my surprise.
However, this produces a stacktrace with adrdress sanitizer.

    auto snd = ex::schedule_from(inline_scheduler{}, ex::just(13));
    ex::sync_wait(snd);

Stacktrace:

==34959==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x00016dbc0028 at pc 0x000102531b38 bp 0x00016dbbf950 sp 0x00016dbbf948
READ of size 8 at 0x00016dbc0028 thread T0
    #0 0x102531b34 in stdexec::__sync_wait::tag_invoke(stdexec::__env::get_env_t, stdexec::__sync_wait::__receiver<int>::__t const&) execution.hpp:5494
    #1 0x10253479c in decltype(__declval<decltype(__select_impl<(anonymous namespace)::basic_inline_scheduler<void>::my_sender, stdexec::__schedule_from::__receiver2<(anonymous namespace
)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&, stdexec::__sync_wait::__receiver<int>::__t>>())
>()()) stdexec::__connect::connect_t::operator()<(anonymous namespace)::basic_inline_scheduler<void>::my_sender, stdexec::__schedule_from::__receiver2<(anonymous namespace)::basic_inline
_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&, stdexec::__sync_wait::__receiver<int>::__t>>((anonymous namesp
ace)::basic_inline_scheduler<void>::my_sender&&, stdexec::__schedule_from::__receiver2<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace
)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&, stdexec::__sync_wait::__receiver<int>::__t>&&) const execution.hpp:1438
    #2 0x102534404 in stdexec::__schedule_from::__state<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(ano
nymous namespace)::__anon>&, stdexec::__sync_wait::__receiver<int>::__t>::__state((anonymous namespace)::basic_inline_scheduler<void>) execution.hpp:4182
    #3 0x10253354c in stdexec::__schedule_from::__state<(anonymous namespace)::basic_inline_scheduler<void>, stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(ano
nymous namespace)::__anon>&, stdexec::__sync_wait::__receiver<int>::__t>::__state((anonymous namespace)::basic_inline_scheduler<void>) execution.hpp:4182
    #4 0x10253340c in auto stdexec::__schedule_from::__schedule_from_impl::$_1::operator()<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace):
:__anon>&, stdexec::__sync_wait::__receiver<int>::__t>(stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&, stdexec::__sync_wait::__r
eceiver<int>::__t&) const execution.hpp:4224
    #5 0x102533130 in stdexec::__detail::__op_base<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&, stdexec::__sync_wait::__recei
ver<int>::__t>::__op_base(stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&, stdexec::__sync_wait::__receiver<int>::__t&&) __basic_
sender.hpp:274
    #6 0x102532e2c in stdexec::__detail::__op_state<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&, stdexec::__sync_wait::__rece
iver<int>::__t>::__op_state(stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&, stdexec::__sync_wait::__receiver<int>::__t) __basic_
sender.hpp:369
    #7 0x102532bc0 in stdexec::__detail::__op_state<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&, stdexec::__sync_wait::__rece
iver<int>::__t>::__op_state(stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&, stdexec::__sync_wait::__receiver<int>::__t) __basic_
sender.hpp:370
    #8 0x102532960 in stdexec::__detail::__op_state<stdexec::__detail::__connect, $T&&> stdexec::__detail::__connect::'lambda'<typename $T, typename $T0>($T&&, $T0)::operator()<stdexec::
__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::__sexpr::__anon>&, stdexec::__sync_wait::__receiver<int>::__t>($T, $T&&) const __basic_sender.hpp:194
    #9 0x1025311ec in decltype(__declval<decltype(__select_impl<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&, stdexec::__sync_
wait::__receiver<int>::__t>())>()()) stdexec::__connect::connect_t::operator()<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&, s
tdexec::__sync_wait::__receiver<int>::__t>(stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&, stdexec::__sync_wait::__receiver<int>
::__t&&) const execution.hpp:1446
    #10 0x10253085c in _ZNK7stdexec11__sync_wait11sync_wait_t12apply_senderIRNS_7__sexprIXtlNS_12_GLOBAL__N_1UlvE8_EEENS4_6__anonEEEEENSt3__18optionalINS_3__iIXL_ZNS_3_OkIJT_NS_3__qINS9_
5tupleEEEEEEEEE3__gINS_12__mtry_catchINS_12__mtry_eval_INS0_23__sync_wait_result_implEEENS_22_WITH_META_FUNCTION_T_ISL_EEE3__fESD_SG_EEEEOSD_ execution.hpp:5621
    #11 0x10252f6dc in std::__1::optional<stdexec::__sync_wait::__value_tuple_for<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&
>::__t> stdexec::__sync_wait::sync_wait_t::operator()<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&>(stdexec::__sexpr<stdexec::
(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&) const execution.hpp:5592
    #12 0x10252e5f0 in (anonymous namespace)::____C_A_T_C_H____T_E_S_T____0() test_transfer_just.cpp:28
    #13 0x10229b9c8 in Catch::TestInvokerAsFunction::invoke() const catch.hpp:14317
    #14 0x1022823d0 in Catch::TestCase::invoke() const catch.hpp:14156
    #15 0x102282188 in Catch::RunContext::invokeActiveTestCase() catch.hpp:13016
    #16 0x10227b4d8 in Catch::RunContext::runCurrentTest(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&, std::__1::basic_string<char, std::__1::cha
r_traits<char>, std::__1::allocator<char>>&) catch.hpp:12989
    #17 0x1022792f0 in Catch::RunContext::runTest(Catch::TestCase const&) catch.hpp:12750
    #18 0x10228a974 in Catch::(anonymous namespace)::TestGroup::execute() catch.hpp:13343
    #19 0x1022892c8 in Catch::Session::runInternal() catch.hpp:13549
    #20 0x102288d30 in Catch::Session::run() catch.hpp:13505
    #21 0x1022db1a8 in int Catch::Session::run<char>(int, char const* const*) catch.hpp:13227
    #22 0x1022daeac in main catch.hpp:17504
    #23 0x180df7f24  (<unknown module>)

Address 0x00016dbc0028 is located in stack of thread T0 at offset 40 in frame
    #0 0x102533198 in auto stdexec::__schedule_from::__schedule_from_impl::$_1::operator()<stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace):
:__anon>&, stdexec::__sync_wait::__receiver<int>::__t>(stdexec::__sexpr<stdexec::(anonymous namespace)::'lambda8'(){}, stdexec::(anonymous namespace)::__anon>&, stdexec::__sync_wait::__r
eceiver<int>::__t&) const execution.hpp:4220

  This frame has 3 object(s):
    [32, 33) 'ref.tmp.i' (line 4222)
    [48, 64) 'retval' <== Memory access at offset 40 underflows this variable
    [80, 81) 'ref.tmp' (line 4222)
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow execution.hpp:5494 in stdexec::__sync_wait::tag_invoke(stdexec::__env::get_env_t, stdexec::__sync_wait::__receiver<int>::__t const&)
Shadow bytes around the buggy address:
  0x00702db97fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x00702db97fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x00702db97fd0: f1 f1 f1 f1 01 f2 01 f2 00 f3 f3 f3 00 00 00 00
  0x00702db97fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x00702db97ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x00702db98000: f1 f1 f1 f1 f8[f2]00 00 f2 f2 f8 f3 00 00 00 00
  0x00702db98010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x00702db98020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x00702db98030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x00702db98040: 00 00 00 00 f1 f1 f1 f1 00 00 f2 f2 00 00 f2 f2
  0x00702db98050: 00 00 f2 f2 f8 f3 f3 f3 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==34959==ABORTING

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.stdexec is a Catch v2.13.6 host application.
Run with -? for options

-------------------------------------------------------------------------------
transfer_just simple example
-------------------------------------------------------------------------------
/Users/rishabh/git/stdexec/test/stdexec/algos/factories/test_transfer_just.cpp:26
...............................................................................

/Users/rishabh/git/stdexec/test/stdexec/algos/factories/test_transfer_just.cpp:26: FAILED:
due to a fatal error condition:
  SIGABRT - Abort (abnormal termination) signal

===============================================================================
test cases: 1 | 1 failed
assertions: 1 | 1 failed

[1]    34959 abort      build/test/test.stdexec

I have disabled other test cases to focus on this one only, that's why there is only one assertion. (I have modified this test case also to inspect the error).

Didn't get chance to look much into the stacktrace right now. Will look at it tomorrow.

@ericniebler
Copy link
Collaborator

ericniebler commented Feb 27, 2024

Thanks for this. I would bet money that this is a problem with the uniqueness of lambda identifiers across translation units. I bet there is a name collision in the __sexpr code due to its use of lambdas. The implementation of one __sexpr is accidentally linked with the implementation of an unrelated __sexpr from another TU, and chaos ensues.

The question is how to teach the LLVM toolchain on MacOS to avoid creating symbol collisions across TUs with lambdas defined at namespace scope.

EDIT:
Anybody interested in fixing the MacOS built would start by tweaking this code in __basic_sender.hpp to try to get clang to generate unique lambda symbols across TUs.

    template <
      class _Descriptor,
      auto _DescriptorFn =
        [] {
          return _Descriptor();
        }>
    inline constexpr auto __descriptor_fn_v = _DescriptorFn;

    template <class _Tag, class _Data, class... _Child>
    inline constexpr auto __descriptor_fn() {
      return __descriptor_fn_v<__detail::__desc<_Tag, _Data, _Child...>>;
    }

@ericniebler
Copy link
Collaborator

/ok to test

2 similar comments
@ericniebler
Copy link
Collaborator

/ok to test

@ericniebler
Copy link
Collaborator

/ok to test

@ericniebler
Copy link
Collaborator

/ok to test

@ericniebler
Copy link
Collaborator

/ok to test

@ericniebler ericniebler merged commit f5e2dd6 into NVIDIA:main Mar 11, 2024
16 checks passed
@ericniebler
Copy link
Collaborator

Hooray! stdexec has a GCD scheduler on MacOS. Thank you @RishabhRD.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants