void execute() { Futures inputFutures; for (const auto& namePort : _inputMap) { const Futures& futures = namePort.second.getFutures(); for (const auto& future : futures) inputFutures.emplace_back(future, namePort.second.getName()); } const FutureMap futures(inputFutures); PromiseMap promises(getOutputPromises()); try { _filter->execute(futures, promises); promises.flush(); } catch (const std::runtime_error& err) { promises.flush(); throw err; } catch (const std::logic_error& err) { promises.flush(); throw err; } }
// static already_AddRefed<Promise> Promise::All(const GlobalObject& aGlobal, const nsTArray<RefPtr<Promise>>& aPromiseList, ErrorResult& aRv) { nsCOMPtr<nsIGlobalObject> global; global = do_QueryInterface(aGlobal.GetAsSupports()); if (!global) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } JSContext* cx = aGlobal.Context(); JS::AutoObjectVector promises(cx); if (!promises.reserve(aPromiseList.Length())) { aRv.NoteJSContextException(cx); return nullptr; } for (auto& promise : aPromiseList) { JS::Rooted<JSObject*> promiseObj(cx, promise->PromiseObj()); // Just in case, make sure these are all in the context compartment. if (!JS_WrapObject(cx, &promiseObj)) { aRv.NoteJSContextException(cx); return nullptr; } promises.infallibleAppend(promiseObj); } JS::Rooted<JSObject*> result(cx, JS::GetWaitForAllPromise(cx, promises)); if (!result) { aRv.NoteJSContextException(cx); return nullptr; } return CreateFromExisting(global, result); }
folly::Future<bool> Barrier::wait() { // Load the current control block first. As we know there is at least // one thread in the current epoch (us), this means that the value is // < size_, so controlBlock_ can't change until we bump the value below. auto block = controlBlock_.load(std::memory_order_acquire); auto p = promises(block); // Bump the value and record ourselves as reader. // This ensures that block stays allocated, as the reader count is > 0. auto prev = block->valueAndReaderCount.fetch_add( kReader + 1, std::memory_order_acquire); auto prevValue = static_cast<uint32_t>(prev & kValueMask); DCHECK_LT(prevValue, size_); auto future = p[prevValue].getFuture(); if (prevValue + 1 == size_) { // Need to reset the barrier before fulfilling any futures. This is // when the epoch is flipped to the next. controlBlock_.store(allocateControlBlock(), std::memory_order_release); p[0].setValue(true); for (uint32_t i = 1; i < size_; ++i) { p[i].setValue(false); } } // Free the control block if we're the last reader at max value. prev = block->valueAndReaderCount.fetch_sub(kReader, std::memory_order_acq_rel); if (prev == (kReader | uint64_t(size_))) { freeControlBlock(block); } return future; }
int main(int argc, const char * argv[]) { promises(); return 0; }
void CPUUncontrolledApproximation::perform() { const auto &ctx = kernel->context(); auto &stateModel = kernel->getCPUKernelStateModel(); auto nl = stateModel.getNeighborList(); auto &data = nl->data(); const auto &box = ctx.boxSize().data(); const auto &pbc = ctx.periodicBoundaryConditions().data(); if (ctx.recordReactionsWithPositions()) { kernel->getCPUKernelStateModel().reactionRecords().clear(); } if (ctx.recordReactionCounts()) { stateModel.resetReactionCounts(); } // gather events std::vector<std::promise<std::size_t>> n_events_promises(kernel->getNThreads()); std::vector<event_promise_t> promises(kernel->getNThreads()); { auto &pool = kernel->pool(); std::vector<std::function<void(std::size_t)>> executables; executables.reserve(kernel->getNThreads()); std::size_t grainSize = data.size() / kernel->getNThreads(); std::size_t nlGrainSize = nl->nCells() / kernel->getNThreads(); auto it = data.cbegin(); std::size_t it_nl = 0; for (auto i = 0U; i < kernel->getNThreads()-1 ; ++i) { auto itNext = std::min(it+grainSize, data.cend()); auto nlNext = std::min(it_nl + nlGrainSize, nl->nCells()); auto bounds_nl = std::make_tuple(it_nl, nlNext); pool.push(findEvents, it, itNext, bounds_nl, kernel, timeStep(), false, std::cref(*nl), std::ref(promises.at(i)), std::ref(n_events_promises.at(i))); it = itNext; it_nl = nlNext; } pool.push(findEvents, it, data.cend(), std::make_tuple(it_nl, nl->nCells()), kernel, timeStep(), false, std::cref(*nl), std::ref(promises.back()), std::ref(n_events_promises.back())); } // collect events std::vector<event_t> events; { std::size_t n_events = 0; for (auto &&f : n_events_promises) { n_events += f.get_future().get(); } events.reserve(n_events); for (auto &&f : promises) { auto eventUpdate = std::move(f.get_future().get()); auto mBegin = std::make_move_iterator(eventUpdate.begin()); auto mEnd = std::make_move_iterator(eventUpdate.end()); events.insert(events.end(), mBegin, mEnd); } } // shuffle reactions std::shuffle(events.begin(), events.end(), std::mt19937(std::random_device()())); // execute reactions { data_t::EntriesUpdate newParticles{}; std::vector<data_t::size_type> decayedEntries{}; // todo better conflict detection? for (auto it = events.begin(); it != events.end(); ++it) { auto &event = *it; if (event.cumulativeRate == 0) { auto entry1 = event.idx1; if (event.nEducts == 1) { auto reaction = ctx.reactions().order1ByType(event.t1)[event.reactionIndex]; if (ctx.recordReactionsWithPositions()) { record_t record; record.id = reaction->id(); performReaction(&data, ctx, entry1, entry1, newParticles, decayedEntries, reaction, &record); bcs::fixPosition(record.where, box, pbc); kernel->getCPUKernelStateModel().reactionRecords().push_back(record); } else { performReaction(&data, ctx, entry1, entry1, newParticles, decayedEntries, reaction, nullptr); } if (ctx.recordReactionCounts()) { auto &counts = stateModel.reactionCounts(); counts.at(reaction->id())++; } for (auto _it2 = it + 1; _it2 != events.end(); ++_it2) { if (_it2->idx1 == entry1 || _it2->idx2 == entry1) { _it2->cumulativeRate = 1; } } } else { auto reaction = ctx.reactions().order2ByType(event.t1, event.t2)[event.reactionIndex]; if (ctx.recordReactionsWithPositions()) { record_t record; record.id = reaction->id(); performReaction(&data, ctx, entry1, event.idx2, newParticles, decayedEntries, reaction, &record); bcs::fixPosition(record.where, box, pbc); kernel->getCPUKernelStateModel().reactionRecords().push_back(record); } else { performReaction(&data, ctx, entry1, event.idx2, newParticles, decayedEntries, reaction, nullptr); } if (ctx.recordReactionCounts()) { auto &counts = stateModel.reactionCounts(); counts.at(reaction->id())++; } for (auto _it2 = it + 1; _it2 != events.end(); ++_it2) { if (_it2->idx1 == entry1 || _it2->idx2 == entry1 || _it2->idx1 == event.idx2 || _it2->idx2 == event.idx2) { _it2->cumulativeRate = 1; } } } } } data.update(std::make_pair(std::move(newParticles), std::move(decayedEntries))); } }