2 // Copyright Oliver Kowalke 2017.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
7 #ifndef BOOST_FIBERS_CUDA_WAITFOR_H
8 #define BOOST_FIBERS_CUDA_WAITFOR_H
10 #include <initializer_list>
17 #include <boost/assert.hpp>
18 #include <boost/config.hpp>
20 #include <hip/hip_runtime.h>
22 #include <boost/fiber/detail/config.hpp>
23 #include <boost/fiber/detail/is_all_same.hpp>
24 #include <boost/fiber/condition_variable.hpp>
25 #include <boost/fiber/mutex.hpp>
27 #ifdef BOOST_HAS_ABI_HEADERS
28 # include BOOST_ABI_PREFIX
36 template< typename Rendezvous >
37 static void trampoline( hipStream_t st, hipError_t status, void * vp) {
38 Rendezvous * data = static_cast< Rendezvous * >( vp);
39 data->notify( st, status);
42 class single_stream_rendezvous {
44 single_stream_rendezvous( hipStream_t st) {
45 unsigned int flags = 0;
46 hipError_t status = ::hipStreamAddCallback( st, trampoline< single_stream_rendezvous >, this, flags);
47 if ( hipSuccess != status) {
54 void notify( hipStream_t st, hipError_t status) noexcept {
55 std::unique_lock< mutex > lk{ mtx_ };
63 std::tuple< hipStream_t, hipError_t > wait() {
64 std::unique_lock< mutex > lk{ mtx_ };
65 cv_.wait( lk, [this]{ return done_; });
66 return std::make_tuple( st_, status_);
71 condition_variable cv_{};
73 hipError_t status_{ hipErrorUnknown };
77 class many_streams_rendezvous {
79 many_streams_rendezvous( std::initializer_list< hipStream_t > l) :
81 results_.reserve( stx_.size() );
82 for ( hipStream_t st : stx_) {
83 unsigned int flags = 0;
84 hipError_t status = ::hipStreamAddCallback( st, trampoline< many_streams_rendezvous >, this, flags);
85 if ( hipSuccess != status) {
86 std::unique_lock< mutex > lk{ mtx_ };
88 results_.push_back( std::make_tuple( st, status) );
93 void notify( hipStream_t st, hipError_t status) noexcept {
94 std::unique_lock< mutex > lk{ mtx_ };
96 results_.push_back( std::make_tuple( st, status) );
103 std::vector< std::tuple< hipStream_t, hipError_t > > wait() {
104 std::unique_lock< mutex > lk{ mtx_ };
105 cv_.wait( lk, [this]{ return stx_.empty(); });
111 condition_variable cv_{};
112 std::set< hipStream_t > stx_;
113 std::vector< std::tuple< hipStream_t, hipError_t > > results_;
121 std::tuple< hipStream_t, hipError_t > waitfor_all( hipStream_t st) {
122 detail::single_stream_rendezvous rendezvous( st);
123 return rendezvous.wait();
126 template< typename ... STP >
127 std::vector< std::tuple< hipStream_t, hipError_t > > waitfor_all( hipStream_t st0, STP ... stx) {
128 static_assert( boost::fibers::detail::is_all_same< hipStream_t, STP ...>::value, "all arguments must be of type `CUstream*`.");
129 detail::many_streams_rendezvous rendezvous{ st0, stx ... };
130 return rendezvous.wait();
135 #ifdef BOOST_HAS_ABI_HEADERS
136 # include BOOST_ABI_SUFFIX
139 #endif // BOOST_FIBERS_CUDA_WAITFOR_H