// Copyright (c) 2011-2016 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "ContextGroup.h" #include namespace System { ContextGroup::ContextGroup(Dispatcher& dispatcher) : dispatcher(&dispatcher) { contextGroup.firstContext = nullptr; } ContextGroup::ContextGroup(ContextGroup&& other) : dispatcher(other.dispatcher) { if (dispatcher != nullptr) { assert(other.contextGroup.firstContext == nullptr); contextGroup.firstContext = nullptr; other.dispatcher = nullptr; } } ContextGroup::~ContextGroup() { if (dispatcher != nullptr) { interrupt(); wait(); } } ContextGroup& ContextGroup::operator=(ContextGroup&& other) { assert(dispatcher == nullptr || contextGroup.firstContext == nullptr); dispatcher = other.dispatcher; if (dispatcher != nullptr) { assert(other.contextGroup.firstContext == nullptr); contextGroup.firstContext = nullptr; other.dispatcher = nullptr; } return *this; } void ContextGroup::interrupt() { assert(dispatcher != nullptr); for (NativeContext* context = contextGroup.firstContext; context != nullptr; context = context->groupNext) { dispatcher->interrupt(context); } } void ContextGroup::spawn(std::function&& procedure) { assert(dispatcher != nullptr); NativeContext& context = dispatcher->getReusableContext(); if (contextGroup.firstContext != nullptr) { context.groupPrev = contextGroup.lastContext; assert(contextGroup.lastContext->groupNext == nullptr); contextGroup.lastContext->groupNext = &context; } else { context.groupPrev = nullptr; contextGroup.firstContext = &context; contextGroup.firstWaiter = nullptr; } context.interrupted = false; context.group = &contextGroup; context.groupNext = nullptr; context.procedure = std::move(procedure); contextGroup.lastContext = &context; dispatcher->pushContext(&context); } void ContextGroup::wait() { if (contextGroup.firstContext != nullptr) { NativeContext* context = dispatcher->getCurrentContext(); context->next = nullptr; if (contextGroup.firstWaiter != nullptr) { assert(contextGroup.lastWaiter->next == nullptr); contextGroup.lastWaiter->next = context; } else { contextGroup.firstWaiter = context; } contextGroup.lastWaiter = context; dispatcher->dispatch(); assert(context == dispatcher->getCurrentContext()); } } }