asyncio is a c++20 library to write concurrent code using the async/await syntax.(developing in progress)

Overview

asyncio

Asyncio is a C++20 coroutine library to write concurrent code using the await syntax, and imitate python asyncio library.

Hello world

Task<> hello_world() {
    fmt::print("hello\n");
    co_await asyncio::sleep(1s);
    fmt::print("world\n");
}

int main() {
    asyncio::run(hello_world());
}

output:

hello
world

Dump callstack

Task<int> factorial(int n) {
    if (n <= 1) {
        co_await dump_callstack();
        co_return 1;
    }
    co_return (co_await factorial(n - 1)) * n;
}

int main() {
    fmt::print("run result: {}\n", asyncio::run(factorial(10)));
    return 0;
}

output:

[0] void factorial(factorial(int)::_Z9factoriali.Frame*) at asyncio/test/st/hello_world.cpp:17
[1] void factorial(factorial(int)::_Z9factoriali.Frame*) at asyncio/test/st/hello_world.cpp:20
[2] void factorial(factorial(int)::_Z9factoriali.Frame*) at asyncio/test/st/hello_world.cpp:20
[3] void factorial(factorial(int)::_Z9factoriali.Frame*) at asyncio/test/st/hello_world.cpp:20
[4] void factorial(factorial(int)::_Z9factoriali.Frame*) at asyncio/test/st/hello_world.cpp:20
[5] void factorial(factorial(int)::_Z9factoriali.Frame*) at asyncio/test/st/hello_world.cpp:20
[6] void factorial(factorial(int)::_Z9factoriali.Frame*) at asyncio/test/st/hello_world.cpp:20
[7] void factorial(factorial(int)::_Z9factoriali.Frame*) at asyncio/test/st/hello_world.cpp:20
[8] void factorial(factorial(int)::_Z9factoriali.Frame*) at asyncio/test/st/hello_world.cpp:20
[9] void factorial(factorial(int)::_Z9factoriali.Frame*) at asyncio/test/st/hello_world.cpp:20

run result: 3628800

Gather

auto factorial(std::string_view name, int number) -> Task<int> {
    int r = 1;
    for (int i = 2; i <= number; ++i) {
        fmt::print("Task {}: Compute factorial({}), currently i={}...\n", name, number, i);
        co_await asyncio::sleep(500ms);
        r *= i;
    }
    fmt::print("Task {}: factorial({}) = {}\n", name, number, r);
    co_return r;
};

auto test_void_func() -> Task<> {
    fmt::print("this is a void value\n");
    co_return;
};

int main() {
    asyncio::run([&]() -> Task<> {
        auto&& [a, b, c, _void] = co_await asyncio::gather(
            factorial("A", 2),
            factorial("B", 3),
            factorial("C", 4),
            test_void_func());
        assert(a == 2);
        assert(b == 6);
        assert(c == 24);
    }());
}

output:

Task A: Compute factorial(2), currently i=2...
Task B: Compute factorial(3), currently i=2...
Task C: Compute factorial(4), currently i=2...
this is a void value
Task C: Compute factorial(4), currently i=3...
Task A: factorial(2) = 2
Task B: Compute factorial(3), currently i=3...
Task B: factorial(3) = 6
Task C: Compute factorial(4), currently i=4...
Task C: factorial(4) = 24

Tested Compiler

  • gcc-12

TODO

  • implement result type for code reuse, variant<monostate, value, exception>
  • implement coroutine backtrace(dump continuation chain)
  • implement some io coroutine(socket/read/write/close)

Reference

Comments
  • wait_for控制超时导致coredump

    wait_for控制超时导致coredump

    在测试echo_client时,使用wait_for为read增加超时机制。在很快收到echo_server响应后,打印data.data()数据时,程序coredump了。请帮忙看看是什么问题,谢谢!

    运行环境: Ubuntu 18.04.4 LTS gcc version 11.1.0

    测试代码如下:

    #include <iostream>
    #include <asyncio/open_connection.h>
    #include <asyncio/runner.h>
    #include <asyncio/sleep.h>
    #include <asyncio/schedule_task.h>
    #include <asyncio/wait_for.h>
    using asyncio::Stream;
    using asyncio::Task;
    
    using namespace std::chrono;
    
    Task<> tcp_echo_client(std::string_view message) {
            auto stream = co_await asyncio::open_connection("127.0.0.1", 8888);
    
            fmt::print("Send: '{}'\n", message);
            co_await stream.write(Stream::Buffer(message.begin(), message.end()));
    
            fmt::print("Send: ok\n");
    
            auto data = co_await asyncio::wait_for(stream.read(100), 300ms);
    
            fmt::print("wait_for: ok data len {}\n", data.size());
            fmt::print("Received: '{}'\n", data.data());
    
            fmt::print("Close the connection\n");
            stream.close();
    }
    
    int main(int argc, char** argv) {
        asyncio::run(tcp_echo_client("hello world!"));
        return 0;
    }
    

    输出和报错信息如下:

    Send: 'hello world!'
    Send: ok
    wait_for: ok data len 12
    =================================================================
    ==16717==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000019c at pc 0x55555557d747 bp 0x7fffffffcfa0 sp 0x7fffffffc748
    READ of size 13 at 0x60200000019c thread T0
        #0 0x55555557d746 in __interceptor_strlen.part.0 (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0x29746)
        #1 0x5555556906bd in fmt::v8::basic_string_view<char>::basic_string_view(char const*) /home/ubuntu/c++/asyncio/third_party/fmt/include/fmt/core.h:440
        #2 0x5555556906bd in fmt::v8::appender fmt::v8::detail::write<char, fmt::v8::appender>(fmt::v8::appender, char const*) /home/ubuntu/c++/asyncio/third_party/fmt/include/fmt/format.h:2122
        #3 0x55555568a2f5 in fmt::v8::appender fmt::v8::detail::default_arg_formatter<char>::operator()<char const*>(char const*) /home/ubuntu/c++/asyncio/third_party/fmt/include/fmt/format.h:2162
        #4 0x55555569254b in decltype ({parm#1}(0)) fmt::v8::visit_format_arg<fmt::v8::detail::default_arg_formatter<char>, fmt::v8::basic_format_context<fmt::v8::appender, char> >(fmt::v8::detail::default_arg_formatter<char>&&, fmt::v8::basic_format_arg<fmt::v8::basic_format_context<fmt::v8::appender, char> > const&) /home/ubuntu/c++/asyncio/third_party/fmt/include/fmt/core.h:1560
        #5 0x55555569254b in fmt::v8::detail::vformat_to<char>(fmt::v8::detail::buffer<char>&, fmt::v8::basic_string_view<char>, fmt::v8::basic_format_args<fmt::v8::basic_format_context<std::conditional<std::is_same<fmt::v8::type_identity<char>::type, char>::value, fmt::v8::appender, std::back_insert_iterator<fmt::v8::detail::buffer<fmt::v8::type_identity<char>::type> > >::type, fmt::v8::type_identity<char>::type> >, fmt::v8::detail::locale_ref)::format_handler::on_replacement_field(int, char const*) /home/ubuntu/c++/asyncio/third_party/fmt/include/fmt/format.h:2919
        #6 0x55555569254b in char const* fmt::v8::detail::parse_replacement_field<char, fmt::v8::detail::vformat_to<char>(fmt::v8::detail::buffer<char>&, fmt::v8::basic_string_view<char>, fmt::v8::basic_format_args<fmt::v8::basic_format_context<std::conditional<std::is_same<fmt::v8::type_identity<char>::type, char>::value, fmt::v8::appender, std::back_insert_iterator<fmt::v8::detail::buffer<fmt::v8::type_identity<char>::type> > >::type, fmt::v8::type_identity<char>::type> >, fmt::v8::detail::locale_ref)::format_handler&>(char const*, char const*, fmt::v8::detail::vformat_to<char>(fmt::v8::detail::buffer<char>&, fmt::v8::basic_string_view<char>, fmt::v8::basic_format_args<fmt::v8::basic_format_context<std::conditional<std::is_same<fmt::v8::type_identity<char>::type, char>::value, fmt::v8::appender, std::back_insert_iterator<fmt::v8::detail::buffer<fmt::v8::type_identity<char>::type> > >::type, fmt::v8::type_identity<char>::type> >, fmt::v8::detail::locale_ref)::format_handler&) /home/ubuntu/c++/asyncio/third_party/fmt/include/fmt/core.h:2536
        #7 0x55555567b74c in void fmt::v8::detail::parse_format_string<false, char, fmt::v8::detail::vformat_to<char>(fmt::v8::detail::buffer<char>&, fmt::v8::basic_string_view<char>, fmt::v8::basic_format_args<fmt::v8::basic_format_context<std::conditional<std::is_same<fmt::v8::type_identity<char>::type, char>::value, fmt::v8::appender, std::back_insert_iterator<fmt::v8::detail::buffer<fmt::v8::type_identity<char>::type> > >::type, fmt::v8::type_identity<char>::type> >, fmt::v8::detail::locale_ref)::format_handler>(fmt::v8::basic_string_view<char>, fmt::v8::detail::vformat_to<char>(fmt::v8::detail::buffer<char>&, fmt::v8::basic_string_view<char>, fmt::v8::basic_format_args<fmt::v8::basic_format_context<std::conditional<std::is_same<fmt::v8::type_identity<char>::type, char>::value, fmt::v8::appender, std::back_insert_iterator<fmt::v8::detail::buffer<fmt::v8::type_identity<char>::type> > >::type, fmt::v8::type_identity<char>::type> >, fmt::v8::detail::locale_ref)::format_handler&&) /home/ubuntu/c++/asyncio/third_party/fmt/include/fmt/core.h:2571
        #8 0x55555567b74c in void fmt::v8::detail::vformat_to<char>(fmt::v8::detail::buffer<char>&, fmt::v8::basic_string_view<char>, fmt::v8::basic_format_args<fmt::v8::basic_format_context<std::conditional<std::is_same<fmt::v8::type_identity<char>::type, char>::value, fmt::v8::appender, std::back_insert_iterator<fmt::v8::detail::buffer<fmt::v8::type_identity<char>::type> > >::type, fmt::v8::type_identity<char>::type> >, fmt::v8::detail::locale_ref) /home/ubuntu/c++/asyncio/third_party/fmt/include/fmt/format.h:2945
        #9 0x55555566dc10 in fmt::v8::vprint(_IO_FILE*, fmt::v8::basic_string_view<char>, fmt::v8::basic_format_args<fmt::v8::basic_format_context<fmt::v8::appender, char> >) /home/ubuntu/c++/asyncio/third_party/fmt/include/fmt/format-inl.h:2611
        #10 0x55555566de4a in fmt::v8::vprint(fmt::v8::basic_string_view<char>, fmt::v8::basic_format_args<fmt::v8::basic_format_context<fmt::v8::appender, char> >) /home/ubuntu/c++/asyncio/third_party/fmt/include/fmt/format-inl.h:2627
        #11 0x555555640102 in void fmt::v8::print<char*>(fmt::v8::basic_format_string<char, fmt::v8::type_identity<char*>::type>, char*&&) /home/ubuntu/c++/asyncio/third_party/fmt/include/fmt/core.h:3150
        #12 0x555555640102 in tcp_echo_client(std::basic_string_view<char, std::char_traits<char> >) [clone .actor] /home/ubuntu/c++/asyncio/test/st/echo_client.cpp:26
        #13 0x555555662401 in std::__n4861::coroutine_handle<asyncio::Task<void>::promise_type>::resume() const (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0x10e401)
        #14 0x555555661671 in asyncio::Task<void>::promise_type::run() (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0x10d671)
        #15 0x5555556634c3 in asyncio::EventLoop::run_once() /home/ubuntu/c++/asyncio/src/event_loop.cpp:63
        #16 0x555555662805 in asyncio::EventLoop::run_until_complete() /home/ubuntu/c++/asyncio/src/event_loop.cpp:17
        #17 0x555555647d14 in decltype(auto) asyncio::run<asyncio::Task<void> >(asyncio::Task<void>&&) (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xf3d14)
        #18 0x55555564099b in main /home/ubuntu/c++/asyncio/test/st/echo_client.cpp:33
        #19 0x7ffff6a15bf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
        #20 0x555555564bb9 in _start (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0x10bb9)
    
    0x60200000019c is located 0 bytes to the right of 12-byte region [0x602000000190,0x60200000019c)
    allocated by thread T0 here:
        #0 0x5555555f5297 in operator new(unsigned long) (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xa1297)
        #1 0x555555659af1 in __gnu_cxx::new_allocator<char>::allocate(unsigned long, void const*) /usr/include/c++/11/ext/new_allocator.h:121
        #2 0x5555556552dd in std::allocator<char>::allocate(unsigned long) /usr/include/c++/11/bits/allocator.h:173
        #3 0x5555556552dd in std::allocator_traits<std::allocator<char> >::allocate(std::allocator<char>&, unsigned long) /usr/include/c++/11/bits/alloc_traits.h:460
        #4 0x555555653ae9 in std::_Vector_base<char, std::allocator<char> >::_M_allocate(unsigned long) (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xffae9)
        #5 0x55555565374c in std::_Vector_base<char, std::allocator<char> >::_M_create_storage(unsigned long) (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xff74c)
        #6 0x55555564ee7c in std::_Vector_base<char, std::allocator<char> >::_Vector_base(unsigned long, std::allocator<char> const&) (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xfae7c)
        #7 0x555555657ccd in std::vector<char, std::allocator<char> >::vector(std::vector<char, std::allocator<char> > const&) (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0x103ccd)
        #8 0x555555654b6e in asyncio::Result<std::vector<char, std::allocator<char> > >::result() & (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0x100b6e)
        #9 0x555555651d35 in asyncio::detail::WaitForAwaiter<std::vector<char, std::allocator<char> >, std::chrono::duration<long, std::ratio<1l, 1000l> > >::await_resume() (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xfdd35)
        #10 0x555555641124 in asyncio::Task<decltype ((((declval<asyncio::detail::GetAwaiter<asyncio::Task<std::vector<char, std::allocator<char> > > >::type>)()).await_resume)())> asyncio::detail::wait_for<asyncio::Task<std::vector<char, std::allocator<char> > >, long, std::ratio<1l, 1000l> >(asyncio::NoWaitAtInitialSuspend, asyncio::Task<std::vector<char, std::allocator<char> > >&&, std::chrono::duration<long, std::ratio<1l, 1000l> >) [clone .actor] /home/ubuntu/c++/asyncio/include/asyncio/wait_for.h:100
        #11 0x5555556623a1 in std::__n4861::coroutine_handle<asyncio::Task<std::vector<char, std::allocator<char> > >::promise_type>::resume() const (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0x10e3a1)
        #12 0x555555660f19 in asyncio::Task<std::vector<char, std::allocator<char> > >::promise_type::run() (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0x10cf19)
        #13 0x5555556634c3 in asyncio::EventLoop::run_once() /home/ubuntu/c++/asyncio/src/event_loop.cpp:63
        #14 0x555555662805 in asyncio::EventLoop::run_until_complete() /home/ubuntu/c++/asyncio/src/event_loop.cpp:17
        #15 0x555555647d14 in decltype(auto) asyncio::run<asyncio::Task<void> >(asyncio::Task<void>&&) (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xf3d14)
        #16 0x55555564099b in main /home/ubuntu/c++/asyncio/test/st/echo_client.cpp:33
        #17 0x7ffff6a15bf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
    
    SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0x29746) in __interceptor_strlen.part.0
    Shadow bytes around the buggy address:
      0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0c047fff8000: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
      0x0c047fff8010: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
      0x0c047fff8020: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
    =>0x0c047fff8030: fa fa 00[04]fa fa fd fd fa fa fa fa fa fa fa fa
      0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c047fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c047fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c047fff8080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    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
      Shadow gap:              cc
    ==16717==ABORTING
    [1] + Done                       "/usr/bin/gdb" --interpreter=mi --tty=${DbgTerm} 0<"/tmp/Microsoft-MIEngine-In-qj4itxmc.b1y" 1>"/tmp/Microsoft-MIEngine-Out-gs1cjxb4.rcj"
    
    opened by awen162 7
  • heap-use-after-free

    heap-use-after-free

    环境

    Ubuntu 18.04.4 LTS gcc 11.1.0

    测试内容

    在echo_server中,在write之前加300ms的sleep时间。 在echo_client中,创建多个连接(测试了17个)同时发送给echo_server,并且使用wait_for进行超时控制,超时是300ms。 客户端和服务端的时间300ms,是特意设置的。

    测试结果

    偶尔会有成功,偶尔会有超时,偶尔会产生heap-use-after-free的coredump。重复测试多次,是会复现问题的。

    请帮忙看看是哪里导致了内存释放了,还在被使用。

    测试代码

    server

    #include <asyncio/runner.h>
    #include <asyncio/start_server.h>
    #include <asyncio/sleep.h>
    #include <asyncio/wait_for.h>
    #include <arpa/inet.h>
    
    using namespace std::chrono;
    using asyncio::Task;
    using asyncio::Stream;
    using asyncio::get_in_addr;
    using asyncio::get_in_port;
    
    Task<> handle_echo(Stream stream) {
        auto& sockinfo = stream.get_sock_info();
        auto sa = reinterpret_cast<const sockaddr*>(&sockinfo);
        char addr[INET6_ADDRSTRLEN] {};
    
        auto data = co_await stream.read(100);
        fmt::print("Received: '{}' from '{}:{}'\n", data.data(),
                   inet_ntop(sockinfo.ss_family, get_in_addr(sa), addr, sizeof addr),
                   get_in_port(sa));
    
        co_await asyncio::sleep(300ms);
        fmt::print("Send: '{}'\n", data.data());
        co_await stream.write(data);
    
        fmt::print("Close the connection\n");
        stream.close();
    }
    
    Task<void> amain() {
        auto server = co_await asyncio::start_server(
                handle_echo, "127.0.0.1", 8888);
    
        fmt::print("Serving on 127.0.0.1:8888\n");
    
        co_await server.serve_forever();
    }
    
    int main() {
        asyncio::run(amain());
        return 0;
    }
    

    client

    #include <iostream>
    #include <asyncio/open_connection.h>
    #include <asyncio/runner.h>
    #include <asyncio/sleep.h>
    #include <asyncio/schedule_task.h>
    #include <asyncio/wait_for.h>
    
    using namespace asyncio;
    using namespace std::chrono;
    
    Task<> tcp_echo_client(std::string_view message) {
            auto stream = co_await asyncio::open_connection("127.0.0.1", 8888);
    
            fmt::print("Send: '{}'\n", message);
            co_await stream.write(Stream::Buffer(message.begin(), message.end() + 1));
    
            fmt::print("Send: ok\n");
    
            auto data = co_await asyncio::wait_for(stream.read(100), 300ms);
    
            fmt::print("Received: '{}'\n", data.data());
    
            fmt::print("Close the connection\n");
            stream.close();
    }
    
    int main(int argc, char** argv) {
    
        std::vector<ScheduledTask<Task<>>> tasks;
        for (size_t i = 0; i < 16; ++i)
        {
            tasks.emplace_back(tcp_echo_client("hello world! 1"));
        }
        
        try
        {
            asyncio::run(tcp_echo_client("hello world!"));
        }
        catch(const std::exception& e)
        {
            std::cerr << e.what() << '\n';
        }
        printf("end ....\n");
    
        return 0;
    }
    

    coredump的输出

    ./echo_client 
    Send: 'hello world! 1'
    Send: 'hello world! 1'
    Send: 'hello world! 1'
    Send: 'hello world! 1'
    Send: 'hello world! 1'
    Send: 'hello world! 1'
    Send: 'hello world! 1'
    Send: 'hello world! 1'
    Send: 'hello world! 1'
    Send: 'hello world! 1'
    Send: 'hello world! 1'
    Send: 'hello world! 1'
    Send: 'hello world! 1'
    Send: 'hello world! 1'
    Send: 'hello world! 1'
    Send: 'hello world! 1'
    Send: 'hello world!'
    Send: ok
    Send: ok
    Send: ok
    Send: ok
    Send: ok
    Send: ok
    Send: ok
    Send: ok
    Send: ok
    Send: ok
    Send: ok
    Send: ok
    Send: ok
    Send: ok
    Send: ok
    Send: ok
    Send: ok
    =================================================================
    ==26685==ERROR: AddressSanitizer: heap-use-after-free on address 0x612000002a60 at pc 0x5580ce2d05a6 bp 0x7ffc3359c220 sp 0x7ffc3359c210
    WRITE of size 1 at 0x612000002a60 thread T0
        #0 0x5580ce2d05a5 in asyncio::Handle::set_state(asyncio::Handle::State) /home/ubuntu/c++/asyncio/include/asyncio/handle.h:25
        #1 0x5580ce2f1e3d in asyncio::EventLoop::run_once() /home/ubuntu/c++/asyncio/src/event_loop.cpp:62
        #2 0x5580ce2f11f7 in asyncio::EventLoop::run_until_complete() /home/ubuntu/c++/asyncio/src/event_loop.cpp:17
        #3 0x5580ce2d4fbe in decltype(auto) asyncio::run<asyncio::Task<void> >(asyncio::Task<void>&&) (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xf3fbe)
        #4 0x5580ce2cda06 in main /home/ubuntu/c++/asyncio/test/st/echo_client.cpp:40
        #5 0x7fe6a576abf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
        #6 0x5580ce1f1d49 in _start (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0x10d49)
    
    0x612000002a60 is located 32 bytes inside of 312-byte region [0x612000002a40,0x612000002b78)
    freed by thread T0 here:
        #0 0x5580ce282f47 in operator delete(void*) (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xa1f47)
        #1 0x5580ce2c68a1 in asyncio::Stream::read(long) [clone .actor] /home/ubuntu/c++/asyncio/include/asyncio/stream.h:46
        #2 0x5580ce2c6b29 in asyncio::Stream::read(long) [clone .destroy] /home/ubuntu/c++/asyncio/include/asyncio/stream.h:34
        #3 0x5580ce2e0ee3 in std::__n4861::coroutine_handle<asyncio::Task<std::vector<char, std::allocator<char> > >::promise_type>::destroy() const (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xffee3)
        #4 0x5580ce2dbd41 in asyncio::Task<std::vector<char, std::allocator<char> > >::destroy() (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xfad41)
        #5 0x5580ce2d5f81 in asyncio::Task<std::vector<char, std::allocator<char> > >::~Task() (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xf4f81)
        #6 0x5580ce2dee4f in asyncio::detail::WaitForAwaiterRegistry<asyncio::Task<std::vector<char, std::allocator<char> > >, std::chrono::duration<long, std::ratio<1l, 1000l> > >::~WaitForAwaiterRegistry() (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xfde4f)
        #7 0x5580ce2ce5c8 in asyncio::Task<decltype ((((declval<asyncio::detail::GetAwaiter<asyncio::Task<std::vector<char, std::allocator<char> > > >::type>)()).await_resume)())> asyncio::detail::wait_for<asyncio::Task<std::vector<char, std::allocator<char> > >, long, std::ratio<1l, 1000l> >(asyncio::NoWaitAtInitialSuspend, asyncio::Task<std::vector<char, std::allocator<char> > >&&, std::chrono::duration<long, std::ratio<1l, 1000l> >) [clone .actor] /home/ubuntu/c++/asyncio/include/asyncio/wait_for.h:101
        #8 0x5580ce2f0d93 in std::__n4861::coroutine_handle<asyncio::Task<std::vector<char, std::allocator<char> > >::promise_type>::resume() const (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0x10fd93)
        #9 0x5580ce2ef90b in asyncio::Task<std::vector<char, std::allocator<char> > >::promise_type::run() (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0x10e90b)
        #10 0x5580ce2f1eb5 in asyncio::EventLoop::run_once() /home/ubuntu/c++/asyncio/src/event_loop.cpp:63
        #11 0x5580ce2f11f7 in asyncio::EventLoop::run_until_complete() /home/ubuntu/c++/asyncio/src/event_loop.cpp:17
        #12 0x5580ce2d4fbe in decltype(auto) asyncio::run<asyncio::Task<void> >(asyncio::Task<void>&&) (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xf3fbe)
        #13 0x5580ce2cda06 in main /home/ubuntu/c++/asyncio/test/st/echo_client.cpp:40
        #14 0x7fe6a576abf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
    
    previously allocated by thread T0 here:
        #0 0x5580ce282427 in operator new(unsigned long) (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xa1427)
        #1 0x5580ce2d3590 in asyncio::Stream::read(long) (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xf2590)
        #2 0x5580ce2ccb2e in tcp_echo_client(std::basic_string_view<char, std::char_traits<char> >) [clone .actor] /home/ubuntu/c++/asyncio/test/st/echo_client.cpp:28
        #3 0x5580ce2f0df3 in std::__n4861::coroutine_handle<asyncio::Task<void>::promise_type>::resume() const (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0x10fdf3)
        #4 0x5580ce2f0063 in asyncio::Task<void>::promise_type::run() (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0x10f063)
        #5 0x5580ce2f1eb5 in asyncio::EventLoop::run_once() /home/ubuntu/c++/asyncio/src/event_loop.cpp:63
        #6 0x5580ce2f11f7 in asyncio::EventLoop::run_until_complete() /home/ubuntu/c++/asyncio/src/event_loop.cpp:17
        #7 0x5580ce2d4fbe in decltype(auto) asyncio::run<asyncio::Task<void> >(asyncio::Task<void>&&) (/home/ubuntu/c++/asyncio/build/test/st/echo_client+0xf3fbe)
        #8 0x5580ce2cda06 in main /home/ubuntu/c++/asyncio/test/st/echo_client.cpp:40
        #9 0x7fe6a576abf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
    
    SUMMARY: AddressSanitizer: heap-use-after-free /home/ubuntu/c++/asyncio/include/asyncio/handle.h:25 in asyncio::Handle::set_state(asyncio::Handle::State)
    Shadow bytes around the buggy address:
      0x0c247fff84f0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
      0x0c247fff8500: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa
      0x0c247fff8510: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
      0x0c247fff8520: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0c247fff8530: 00 00 00 00 00 00 00 00 00 00 00 00 00 fa fa fa
    =>0x0c247fff8540: fa fa fa fa fa fa fa fa fd fd fd fd[fd]fd fd fd
      0x0c247fff8550: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
      0x0c247fff8560: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa
      0x0c247fff8570: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
      0x0c247fff8580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0c247fff8590: 00 00 00 00 00 00 00 00 00 00 00 00 00 fa fa fa
    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
      Shadow gap:              cc
    ==26685==ABORTING
    
    
    opened by awen162 4
  • Just a comparison

    Just a comparison

    https://github.com/alibaba/PhotonLibOS

    First of all, Go and Rust should be faster than you thought. Wondering how you get such results.

    Did you test it with two real machines?

    opened by beef9999 3
  • 关于task.h中的await_transform和co_await如何执行

    关于task.h中的await_transform和co_await如何执行

    co_await expr会被转化为

    auto&& awaitable = **get_awaitable**(promise, static_cast<decltype(value)>(value));
    auto&& awaiter = get_awaiter(static_cast<decltype(awaitable)>(awaitable));
    

    而get_awaitable由下面伪代码构成

    decltype(auto) **get_awaitable**(P& promise, T&& expr)
    {
      if constexpr (has_any_await_transform_member_v<P>)
        return promise.await_transform(static_cast<T&&>(expr));
      else
        return static_cast<T&&>(expr);
    }
    

    参考task_test.cpp例子,struct Task不应该是一个awaitable对象,想问一下task.h中的await_transform是如何工作的。 调试代码,先运行await_transform再运行co_await,没弄明白参数是怎么传递的,能否做个简单提示 不胜感激

    opened by BestUO 2
  • Can't compile it with gcc 11

    Can't compile it with gcc 11

    At the beginning, I compile it with gcc 9 and get the following error:

    asyncio/include/asyncio/handle.h:9:10: fatal error: source_location: No such file or directory
        9 | #include <source_location>
           |          ^~~~~~~~~~~~~~~~~
    

    Then, I update the gcc to version 11.1 and still get this error.

    Could author paste the successful building environment in the README?

    Thanks.

    opened by xzhangxian1008 2
  • 单元测试报错

    单元测试报错

    环境: Ubuntu 18.04.1 LTS gcc版本: gcc version 11.1.0 (Ubuntu 11.1.0-1ubuntu1~18.04.1)

    单元测试报错信息如下,请帮忙分析下是什么原因,谢谢! `[email protected]:~/c++/asyncio/build/test/ut$ ./asyncio_ut this is a void value Task C: Compute factorial(4), currently i=2... Task B: Compute factorial(3), currently i=2... Task A: Compute factorial(2), currently i=2... Task C: Compute factorial(4), currently i=3... Task B: Compute factorial(3), currently i=3... Task A: factorial(2) = 2 Task C: Compute factorial(4), currently i=4... Task B: factorial(3) = 6 Task C: factorial(4) = 24 Task B: Compute factorial(3), currently i=2... Task A: Compute factorial(2), currently i=2... this is a void value Task C: Compute factorial(4), currently i=2... Task B: Compute factorial(3), currently i=3... Task A: factorial(2) = 2 Task C: Compute factorial(4), currently i=3... Task B: factorial(3) = 6 Task C: Compute factorial(4), currently i=4... Task C: factorial(4) = 24 Task B: Compute factorial(3), currently i=2... Task A: Compute factorial(2), currently i=2... Task B: Compute factorial(3), currently i=3... Task A: factorial(2) = 2 Task B: factorial(3) = 6 Task B: Compute factorial(3), currently i=2... wait_duration finished

    asyncio_ut is a Catch v3.0.0-preview.3 host application.
    Run with -? for options
    
    Randomness seeded to: 1868188266
    
    -------------------------------------------------------------------------------
    Scenario: test timeout
      wait_for with gather
    -------------------------------------------------------------------------------
    /home/ubuntu/c++/asyncio/test/ut/task_test.cpp:275
    ...............................................................................
    
    /home/ubuntu/c++/asyncio/test/ut/task_test.cpp:278: FAILED:
      REQUIRE_NOTHROW( co_await wait_for(gather(sleep(10ms), sleep(20ms), sleep(30ms)), 50ms) )
    due to unexpected exception with message:
      TimeoutError
    
    ===============================================================================
    test cases: 11 | 10 passed | 1 failed
    assertions: 96 | 95 passed | 1 failed`
    opened by awen162 2
  • Release test pass in GCC 11.2 :-)

    Release test pass in GCC 11.2 :-)

    Hi

    My test don't show any release bug in GCC 11.2. I use in arch Linux.

    Then: " Debian Linux gcc-11/12, gcc-11 crash at Release mode"

    Seems wrong Now !

    opened by Maziar123 0
  • [Feature Request] TLS Support?

    [Feature Request] TLS Support?

    Greetings and also AWESOME WORK @netcan I have been wondering why C++ doesn't have a library like this - been struggling with ASIO. Turns out, it DOES have a library like this I just hadn't heard of it.

    One thing that Python Asyncio has going for it that seems to be missing, though, is TLS support. I know adding that isn't easy, but figure it should be on the TODO list of any project like this.

    Or, is it more common these days to use tools like stunnel ? I've found TLS outside of Python to be very finnicky to setup.

    opened by volundmush 2
Owner
Netcan
C++ Programmer
Netcan
Mongoose Embedded Web Server Library - a multi-protocol embedded networking library with TCP/UDP, HTTP, WebSocket, MQTT built-in protocols, async DNS resolver, and non-blocking API.

Mongoose - Embedded Web Server / Embedded Networking Library Mongoose is a networking library for C/C++. It implements event-driven non-blocking APIs

Cesanta Software 9k Jan 1, 2023
A C++ async HTTP client library to use in asynchronous applications while communicating with REST services.

libashttp An asynchronous HTTP library using Boost.ASIO as the backend. This project is licensed under: Usage Here is a example usage which is taken f

Tolga Hoşgör 53 Dec 17, 2022
Simple embeddable C++11 async tcp,http and websocket serving.

net11 Simple embeddable C++11 async tcp,http and websocket serving. What is it? An easily embeddable C++11 networking library designed to make buildin

Jonas Lund 9 Mar 28, 2020
A modern C++ network library for developing high performance network services in TCP/UDP/HTTP protocols.

evpp Introduction 中文说明 evpp is a modern C++ network library for developing high performance network services using TCP/UDP/HTTP protocols. evpp provid

Qihoo 360 3.2k Jan 5, 2023
BingBing 60 Dec 15, 2022
The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design. This project aims to help C++ developers connect to and interact with services.

Welcome! The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design

Microsoft 7.2k Dec 30, 2022
Growtopia Server Using Code Blocks IDE

Growtopia Server First Growtopia Private Server made with ENet by GrowtopiaNoobs. This project has been compiled with Codeblocks This project has been

GuckTube YT 9 Dec 25, 2022
A library with common code used by libraries and tools around the libimobiledevice project

libimobiledevice-glue Library with common code used by the libraries and tools around the libimobiledevice project. Features The main functionality pr

libimobiledevice 41 Dec 23, 2022
single header C(99) library to implement client-server network code for games

single header C(99) library to implement client-server network code for games

Nathan 227 Jan 5, 2023
Single C file TLS 1.2/1.3 implementation, using tomcrypt as crypto library

TLSe Single C file TLS 1.3, 1.2, 1.1 and 1.0(without the weak ciphers) implementation, using libtomcrypt as crypto library. It also supports DTLS 1.2

Eduard Suica 481 Dec 31, 2022
Inter-process communication library to enable allocation between processes/threads and send/receive of allocated regions between producers/consumer processes or threads using this ipc buffer.

This is a relatively simple IPC buffer that allows multiple processes and threads to share a dynamic heap allocator, designate "channels" between processes, and share that memory between producer/consumer pairs on those channels.

RaftLib 8 Aug 20, 2022
Brynet - Header Only Cross platform high performance TCP network library using C++ 11.

Brynet Header Only Cross platform high performance TCP network library using C++ 11. Build status Windows : Linux/MacOS : Features Header only Cross p

IronsDu 895 Jan 8, 2023
requests-like networking library using boost for C++

cq == C++ Requests cq == C++ Requests is a "Python Requests"-like C++ header-only library for sending HTTP requests. The library is inspired a lot by

null 11 Dec 15, 2021
Ole Christian Eidheim 741 Dec 27, 2022
Asynchronous TCP Library for STM32H7-based Portenta_H7 using mbed_portenta core.

Asynchronous TCP Library for STM32H7-based Portenta_H7 using mbed_portenta core. This library is the base for future and more advanced Async libraries, such as AsyncWebServer, AsyncHTTPRequest, AsyncHTTPSRequest

Khoi Hoang 3 Dec 29, 2022
Socket and Networking Library using msgpack.org[C++11]

netLink C++ 11 KISS principle networking library. Features: C++ 11 IPv4, IPv6 Protocols: TCP, UDP Enable/Disable blocking mode Join/Leave UDP-Multicas

Alexander Meißner 210 Oct 18, 2022
A very simple, fast, multithreaded, platform independent HTTP and HTTPS server and client library implemented using C++11 and Boost.Asio.

A very simple, fast, multithreaded, platform independent HTTP and HTTPS server and client library implemented using C++11 and Boost.Asio. Created to be an easy way to make REST resources available from C++ applications.

Ole Christian Eidheim 2.4k Dec 23, 2022
http server code by c

Lamphttp HTTP服务 Lamphttp是使用c语言实现的http服务,目前市面上有非常多的http服务,比如大名鼎鼎的Nginx 那么对于Lamphttp存在的意义是什么呢?对于Lamphttp主要是为了理解了tcp/ip到http的中间 这一层的实现,说白了就是当作学习用的. 虽然Lam

D-灯先生 47 Dec 19, 2022
An MQTT-based Virtual Wall for ESP8266 Devices and Gerber files to make the IR hat; this code and board can easily be adapted to be ANY infrared controller/remote!

Roomba-Virtual-Wall-ESP8266-MQTT An MQTT-based Virtual Wall for ESP8266 Devices I made this based off of the IRSend, IRremoteESP8266, and EspMQTTClien

null 8 Sep 20, 2021