Skip to content

Commit

Permalink
Merge pull request #154 from kirkshoop/runloop
Browse files Browse the repository at this point in the history
add run loop scheduler
  • Loading branch information
Kirk Shoop committed Jun 24, 2015
2 parents d58f68b + 0efa842 commit 0ff6d6a
Show file tree
Hide file tree
Showing 10 changed files with 314 additions and 60 deletions.
82 changes: 52 additions & 30 deletions Rx/v2/src/rxcpp/operators/rx-observe_on.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,65 +68,79 @@ struct observe_on
, destination(std::move(d))
{
}

void finish(std::unique_lock<std::mutex>& guard, typename mode::type end) const {
if (!guard.owns_lock()) {
abort();
}
if (current == mode::Errored || current == mode::Disposed) {return;}
current = end;
queue_type fill_expired;
swap(fill_expired, fill_queue);
queue_type drain_expired;
swap(drain_expired, drain_queue);
RXCPP_UNWIND_AUTO([&](){guard.lock();});
guard.unlock();
lifetime.unsubscribe();
destination.unsubscribe();
}

void ensure_processing(std::unique_lock<std::mutex>& guard) const {
if (!guard.owns_lock()) {
abort();
}
if (current == mode::Empty) {
current = mode::Processing;

if (!lifetime.is_subscribed() && fill_queue.empty() && drain_queue.empty()) {
finish(guard, mode::Disposed);
}

auto keepAlive = this->shared_from_this();

auto drain = [keepAlive, this](const rxsc::schedulable& self){
using std::swap;
try {
if (drain_queue.empty() || !destination.is_subscribed()) {
std::unique_lock<std::mutex> guard(lock);
if (!destination.is_subscribed() ||
(!lifetime.is_subscribed() && fill_queue.empty() && drain_queue.empty())) {
current = mode::Disposed;
queue_type expired;
swap(expired, fill_queue);
guard.unlock();
lifetime.unsubscribe();
destination.unsubscribe();
return;
}
if (drain_queue.empty()) {
if (fill_queue.empty()) {
current = mode::Empty;
for (;;) {
if (drain_queue.empty() || !destination.is_subscribed()) {
std::unique_lock<std::mutex> guard(lock);
if (!destination.is_subscribed() ||
(!lifetime.is_subscribed() && fill_queue.empty() && drain_queue.empty())) {
finish(guard, mode::Disposed);
return;
}
swap(fill_queue, drain_queue);
if (drain_queue.empty()) {
if (fill_queue.empty()) {
current = mode::Empty;
return;
}
swap(fill_queue, drain_queue);
}
}
auto notification = std::move(drain_queue.front());
drain_queue.pop_front();
notification->accept(destination);
std::unique_lock<std::mutex> guard(lock);
self();
if (lifetime.is_subscribed()) break;
}
auto notification = std::move(drain_queue.front());
drain_queue.pop_front();
notification->accept(destination);
self();
} catch(...) {
destination.on_error(std::current_exception());
std::unique_lock<std::mutex> guard(lock);
current = mode::Errored;
queue_type expired;
swap(expired, fill_queue);
finish(guard, mode::Errored);
}
};

auto selectedDrain = on_exception(
[&](){return coordinator.act(drain);},
destination);
if (selectedDrain.empty()) {
current = mode::Errored;
using std::swap;
queue_type expired;
swap(expired, fill_queue);
finish(guard, mode::Errored);
return;
}

auto processor = coordinator.get_worker();

RXCPP_UNWIND_AUTO([&](){guard.lock();});
guard.unlock();

Expand All @@ -143,16 +157,19 @@ struct observe_on

void on_next(source_value_type v) const {
std::unique_lock<std::mutex> guard(state->lock);
if (state->current == mode::Errored || state->current == mode::Disposed) { return; }
state->fill_queue.push_back(notification_type::on_next(std::move(v)));
state->ensure_processing(guard);
}
void on_error(std::exception_ptr e) const {
std::unique_lock<std::mutex> guard(state->lock);
if (state->current == mode::Errored || state->current == mode::Disposed) { return; }
state->fill_queue.push_back(notification_type::on_error(e));
state->ensure_processing(guard);
}
void on_completed() const {
std::unique_lock<std::mutex> guard(state->lock);
if (state->current == mode::Errored || state->current == mode::Disposed) { return; }
state->fill_queue.push_back(notification_type::on_completed());
state->ensure_processing(guard);
}
Expand All @@ -163,7 +180,7 @@ struct observe_on

this_type o(d, std::move(coor), cs);
auto keepAlive = o.state;
cs.add([keepAlive](){
cs.add([=](){
std::unique_lock<std::mutex> guard(keepAlive->lock);
keepAlive->ensure_processing(guard);
});
Expand Down Expand Up @@ -262,6 +279,11 @@ class observe_on_one_worker : public coordination_base
}
};

inline observe_on_one_worker observe_on_run_loop(const rxsc::run_loop& rl) {
static observe_on_one_worker r(rxsc::make_run_loop(rl));
return r;
}

inline observe_on_one_worker observe_on_event_loop() {
static observe_on_one_worker r(rxsc::make_event_loop());
return r;
Expand Down
6 changes: 5 additions & 1 deletion Rx/v2/src/rxcpp/operators/rx-repeat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,16 @@ struct repeat : public operator_base<T>
}
composite_subscription source_lifetime;
output_type out;
composite_subscription::weak_subscription lifetime_token;

void do_subscribe() {
auto state = this->shared_from_this();

state->out.remove(state->lifetime_token);
state->source_lifetime.unsubscribe();

state->source_lifetime = composite_subscription();
state->out.add(state->source_lifetime);
state->lifetime_token = state->out.add(state->source_lifetime);

state->source.subscribe(
state->out,
Expand Down
28 changes: 16 additions & 12 deletions Rx/v2/src/rxcpp/operators/rx-subscribe_on.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,12 @@ struct subscribe_on : public operator_base<T>
: public std::enable_shared_from_this<subscribe_on_state_type>
, public subscribe_on_values
{
subscribe_on_state_type(const subscribe_on_values& i, coordinator_type coor, const output_type& oarg)
subscribe_on_state_type(const subscribe_on_values& i, const output_type& oarg)
: subscribe_on_values(i)
, coordinator(std::move(coor))
, out(oarg)
{
}
composite_subscription source_lifetime;
coordinator_type coordinator;
output_type out;
private:
subscribe_on_state_type& operator=(subscribe_on_state_type o) RXCPP_DELETE;
Expand All @@ -72,33 +70,39 @@ struct subscribe_on : public operator_base<T>
auto controller = coordinator.get_worker();

// take a copy of the values for each subscription
auto state = std::make_shared<subscribe_on_state_type>(initial, std::move(coordinator), std::move(s));
auto state = std::make_shared<subscribe_on_state_type>(initial, std::move(s));

auto sl = state->source_lifetime;
auto ol = state->out.get_subscription();

auto disposer = [=](const rxsc::schedulable&){
state->source_lifetime.unsubscribe();
state->out.unsubscribe();
sl.unsubscribe();
ol.unsubscribe();
coordinator_lifetime.unsubscribe();
};
auto selectedDisposer = on_exception(
[&](){return state->coordinator.act(disposer);},
[&](){return coordinator.act(disposer);},
state->out);
if (selectedDisposer.empty()) {
return;
}

state->out.add([=](){
controller.schedule(selectedDisposer.get());
});

state->source_lifetime.add([=](){
controller.schedule(selectedDisposer.get());
});

state->out.add([=](){
sl.unsubscribe();
ol.unsubscribe();
coordinator_lifetime.unsubscribe();
});

auto producer = [=](const rxsc::schedulable&){
state->source.subscribe(state->source_lifetime, state->out);
};

auto selectedProducer = on_exception(
[&](){return state->coordinator.act(producer);},
[&](){return coordinator.act(producer);},
state->out);
if (selectedProducer.empty()) {
return;
Expand Down
8 changes: 6 additions & 2 deletions Rx/v2/src/rxcpp/rx-scheduler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ inline bool operator==(const worker& lhs, const worker& rhs) {
inline bool operator!=(const worker& lhs, const worker& rhs) {
return !(lhs == rhs);
}

class weak_worker
{
detail::worker_interface_weak_ptr inner;
Expand All @@ -344,7 +344,7 @@ class weak_worker
, lifetime(owner.lifetime)
{
}

worker lock() const {
return worker(lifetime, inner.lock());
}
Expand Down Expand Up @@ -419,6 +419,9 @@ inline scheduler make_scheduler(ArgN&&... an) {
return scheduler(std::static_pointer_cast<scheduler_interface>(std::make_shared<Scheduler>(std::forward<ArgN>(an)...)));
}

inline scheduler make_scheduler(std::shared_ptr<scheduler_interface> si) {
return scheduler(si);
}

class schedulable : public schedulable_base
{
Expand Down Expand Up @@ -912,6 +915,7 @@ namespace rxsc=schedulers;
}

#include "schedulers/rx-currentthread.hpp"
#include "schedulers/rx-runloop.hpp"
#include "schedulers/rx-newthread.hpp"
#include "schedulers/rx-eventloop.hpp"
#include "schedulers/rx-immediate.hpp"
Expand Down
Loading

0 comments on commit 0ff6d6a

Please sign in to comment.