X-Git-Url: http://bilbo.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/4d648ebbbe5705878080b9cbf1ca61497323c592..874aec87c7ce1894a9f017d2adf07ce7b8abe71d:/src/kernel/activity/SemaphoreImpl.cpp diff --git a/src/kernel/activity/SemaphoreImpl.cpp b/src/kernel/activity/SemaphoreImpl.cpp index 66e9900edd..b53f45771b 100644 --- a/src/kernel/activity/SemaphoreImpl.cpp +++ b/src/kernel/activity/SemaphoreImpl.cpp @@ -1,65 +1,116 @@ -/* Copyright (c) 2019. The SimGrid Team. All rights reserved. */ +/* Copyright (c) 2019-2023. The SimGrid Team. All rights reserved. */ /* This program is free software; you can redistribute it and/or modify it * under the terms of the license (GNU LGPL) which comes with this package. */ +#include +#include + #include "src/kernel/activity/SemaphoreImpl.hpp" -#include "src/kernel/activity/SynchroRaw.hpp" +#include "src/kernel/activity/Synchro.hpp" +#include "src/kernel/actor/SynchroObserver.hpp" +#include "src/kernel/resource/CpuImpl.hpp" + +#include // std::isfinite -XBT_LOG_NEW_DEFAULT_SUBCATEGORY(simix_semaphore, simix_synchro, "Semaphore kernel-space implementation"); +XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ker_semaphore, ker_synchro, "Semaphore kernel-space implementation"); -namespace simgrid { -namespace kernel { -namespace activity { +namespace simgrid::kernel::activity { -void SemaphoreImpl::acquire(actor::ActorImpl* issuer, double timeout) +/* -------- Acquisition -------- */ + +void SemAcquisitionImpl::wait_for(actor::ActorImpl* issuer, double timeout) { - RawImplPtr synchro = nullptr; + xbt_assert(std::isfinite(timeout), "timeout is not finite!"); + xbt_assert(issuer == issuer_, "Cannot wait on acquisitions created by another actor (id %ld)", issuer_->get_pid()); XBT_DEBUG("Wait semaphore %p (timeout:%f)", this, timeout); - if (value_ <= 0) { - synchro = RawImplPtr(new RawImpl()); - (*synchro).set_host(issuer->get_host()).set_timeout(timeout).start(); - synchro->simcalls_.push_front(&issuer->simcall); - issuer->waiting_synchro = synchro; - sleeping_.push_back(*issuer); + + this->register_simcall(&issuer_->simcall_); // Block on that acquisition + + if (granted_) { + finish(); + } else if (timeout > 0) { + model_action_ = get_issuer()->get_host()->get_cpu()->sleep(timeout); + model_action_->set_activity(this); + } else { - value_--; - SIMIX_simcall_answer(&issuer->simcall); + // Already in the queue } } -void SemaphoreImpl::release() +void SemAcquisitionImpl::finish() { - XBT_DEBUG("Sem release semaphore %p", this); + xbt_assert(simcalls_.size() == 1, "Unexpected number of simcalls waiting: %zu", simcalls_.size()); + actor::Simcall* simcall = simcalls_.front(); + simcalls_.pop_front(); - if (not sleeping_.empty()) { - auto& actor = sleeping_.front(); - sleeping_.pop_front(); - actor.waiting_synchro = nullptr; - SIMIX_simcall_answer(&actor.simcall); - } else { - value_++; + if (model_action_ != nullptr) { // A timeout was declared + if (model_action_->get_state() == resource::Action::State::FINISHED) { // The timeout elapsed + if (granted_) { // but we got the semaphore, just in time! + set_state(State::DONE); + + } else { // we have to report that timeout + cancel(); // Unregister the acquisition from the semaphore + + /* Return to the englobing simcall that the wait_for timeouted */ + auto* observer = dynamic_cast(get_issuer()->simcall_.observer_); + xbt_assert(observer != nullptr); + observer->set_result(true); + } + } + model_action_->unref(); + model_action_ = nullptr; } + + simcall->issuer_->waiting_synchro_ = nullptr; + simcall->issuer_->simcall_answer(); +} +void SemAcquisitionImpl::cancel() +{ + /* Remove myself from the list of interested parties */ + const auto* issuer = get_issuer(); + auto it = std::find_if(semaphore_->ongoing_acquisitions_.begin(), semaphore_->ongoing_acquisitions_.end(), + [issuer](SemAcquisitionImplPtr acqui) { return acqui->get_issuer() == issuer; }); + xbt_assert(it != semaphore_->ongoing_acquisitions_.end(), + "Cannot find myself in the waiting queue that I have to leave"); + semaphore_->ongoing_acquisitions_.erase(it); } -} // namespace activity -} // namespace kernel -} // namespace simgrid +/* -------- Semaphore -------- */ +unsigned SemaphoreImpl::next_id_ = 0; -// Simcall handlers: -/** - * @brief Handles a sem acquire simcall without timeout. - */ -void simcall_HANDLER_sem_acquire(smx_simcall_t simcall, smx_sem_t sem) +SemAcquisitionImplPtr SemaphoreImpl::acquire_async(actor::ActorImpl* issuer) { - sem->acquire(simcall->issuer, -1); -} + auto res = SemAcquisitionImplPtr(new kernel::activity::SemAcquisitionImpl(issuer, this), true); -/** - * @brief Handles a sem acquire simcall with timeout. - */ -void simcall_HANDLER_sem_acquire_timeout(smx_simcall_t simcall, smx_sem_t sem, double timeout) + if (value_ > 0) { + value_--; + res->granted_ = true; + } else { + /* No free token in the semaphore; register the acquisition */ + ongoing_acquisitions_.push_back(res); + } + return res; +} +void SemaphoreImpl::release() { - simcall_sem_acquire_timeout__set__result(simcall, 0); // default result, will be set to 1 on timeout - sem->acquire(simcall->issuer, timeout); + XBT_DEBUG("Sem release semaphore %p", this); + + if (not ongoing_acquisitions_.empty()) { + /* Release the first waiting actor */ + + auto acqui = ongoing_acquisitions_.front(); + ongoing_acquisitions_.pop_front(); + + acqui->granted_ = true; + if (acqui == acqui->get_issuer()->waiting_synchro_) + acqui->finish(); + // else, the issuer is not blocked on this acquisition so no need to release it + + } else { + // nobody's waiting here + value_++; + } } + +} // namespace simgrid::kernel::activity