From: Martin Quinson <624847+mquinson@users.noreply.github.com> Date: Mon, 1 Oct 2018 18:33:16 +0000 (+0200) Subject: Merge pull request #303 from mpoquet/s4u-semaphore X-Git-Tag: v3_21~15^2 X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/62534c29d0fe83dbec6b7e7642d2ecbe100f3d7b?hp=31760320be7d37b9e87f60db1e1dc5407bf36be6 Merge pull request #303 from mpoquet/s4u-semaphore S4u semaphore --- diff --git a/examples/s4u/CMakeLists.txt b/examples/s4u/CMakeLists.txt index 9ae63e2ac8..b9ed396239 100644 --- a/examples/s4u/CMakeLists.txt +++ b/examples/s4u/CMakeLists.txt @@ -12,7 +12,7 @@ foreach (example actor-create actor-daemon actor-join actor-kill platform-failures platform-properties plugin-hostload replay-comm replay-storage routing-get-clusters - synchro-barrier synchro-mutex + synchro-barrier synchro-mutex synchro-semaphore trace-platform) add_executable (s4u-${example} ${example}/s4u-${example}.cpp) target_link_libraries(s4u-${example} simgrid) @@ -109,7 +109,7 @@ foreach(example actor-create actor-daemon actor-join actor-kill io-async io-file-system io-file-remote io-storage-raw replay-comm replay-storage routing-get-clusters - synchro-barrier synchro-mutex + synchro-barrier synchro-mutex synchro-semaphore ) ADD_TESH_FACTORIES(s4u-${example} "thread;ucontext;raw;boost" --setenv bindir=${CMAKE_CURRENT_BINARY_DIR}/${example} diff --git a/examples/s4u/synchro-semaphore/s4u-synchro-semaphore.cpp b/examples/s4u/synchro-semaphore/s4u-synchro-semaphore.cpp new file mode 100644 index 0000000000..8c96391e57 --- /dev/null +++ b/examples/s4u/synchro-semaphore/s4u-synchro-semaphore.cpp @@ -0,0 +1,67 @@ +/* Copyright (c) 2006-2018. 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 "simgrid/s4u.hpp" + +#include + +XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_test, "a sample log category"); + +// This example implements a one-time use barrier with 1 semaphore and 1 mutex. + +static void worker(simgrid::s4u::SemaphorePtr semaphore, simgrid::s4u::MutexPtr mutex, int process_count, std::shared_ptr count) +{ + mutex->lock(); + XBT_INFO("Got mutex. Incrementing count."); + XBT_INFO("Count is %d", *count); + *count = (*count) + 1; + XBT_INFO("Count is now %d. Process count is %d.", *count, process_count); + + if (*count == process_count) { + XBT_INFO("Releasing the semaphore %d times.", process_count-1); + for (int i = 0; i < process_count-1; i++) { + semaphore->release(); + } + + XBT_INFO("Releasing mutex."); + mutex->unlock(); + } + else { + XBT_INFO("Releasing mutex."); + mutex->unlock(); + XBT_INFO("Acquiring semaphore."); + semaphore->acquire(); + } + + XBT_INFO("Bye!"); +} + +static void master(unsigned int process_count) +{ + simgrid::s4u::SemaphorePtr semaphore = simgrid::s4u::Semaphore::create(0); + simgrid::s4u::MutexPtr mutex = simgrid::s4u::Mutex::create(); + std::shared_ptr count(new int); + *count = 0; + + XBT_INFO("Spawning %d workers", process_count); + for (unsigned int i = 0; i < process_count; i++) { + simgrid::s4u::Actor::create("worker", simgrid::s4u::Host::by_name("Jupiter"), worker, semaphore, mutex, process_count, count); + } +} + +int main(int argc, char **argv) +{ + // Parameter: Number of processes in the barrier + xbt_assert(argc >= 2, "Usage: %s \n", argv[0]); + unsigned int process_count = std::stoi(argv[1]); + xbt_assert(process_count > 0, " must be greater than 0"); + + simgrid::s4u::Engine e(&argc, argv); + e.load_platform("../../platforms/two_hosts.xml"); + simgrid::s4u::Actor::create("master", simgrid::s4u::Host::by_name("Tremblay"), master, process_count); + e.run(); + + return 0; +} diff --git a/examples/s4u/synchro-semaphore/s4u-synchro-semaphore.tesh b/examples/s4u/synchro-semaphore/s4u-synchro-semaphore.tesh new file mode 100644 index 0000000000..477a7a07e3 --- /dev/null +++ b/examples/s4u/synchro-semaphore/s4u-synchro-semaphore.tesh @@ -0,0 +1,109 @@ +#!/usr/bin/env tesh + +$ $SG_TEST_EXENV ${bindir:=.}/s4u-synchro-semaphore 1 +> [Tremblay:master:(1) 0.000000] [s4u_test/INFO] Spawning 1 workers +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Got mutex. Incrementing count. +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Count is 0 +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Count is now 1. Process count is 1. +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Releasing the semaphore 0 times. +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Releasing mutex. +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Bye! + +$ $SG_TEST_EXENV ${bindir:=.}/s4u-synchro-semaphore 2 +> [Tremblay:master:(1) 0.000000] [s4u_test/INFO] Spawning 2 workers +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Got mutex. Incrementing count. +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Count is 0 +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Count is now 1. Process count is 2. +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Releasing mutex. +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Acquiring semaphore. +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Got mutex. Incrementing count. +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Count is 1 +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Count is now 2. Process count is 2. +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Releasing the semaphore 1 times. +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Bye! +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Releasing mutex. +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Bye! + +$ $SG_TEST_EXENV ${bindir:=.}/s4u-synchro-semaphore 3 +> [Tremblay:master:(1) 0.000000] [s4u_test/INFO] Spawning 3 workers +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Got mutex. Incrementing count. +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Count is 0 +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Count is now 1. Process count is 3. +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Releasing mutex. +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Acquiring semaphore. +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Got mutex. Incrementing count. +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Count is 1 +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Count is now 2. Process count is 3. +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Releasing mutex. +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Acquiring semaphore. +> [Jupiter:worker:(4) 0.000000] [s4u_test/INFO] Got mutex. Incrementing count. +> [Jupiter:worker:(4) 0.000000] [s4u_test/INFO] Count is 2 +> [Jupiter:worker:(4) 0.000000] [s4u_test/INFO] Count is now 3. Process count is 3. +> [Jupiter:worker:(4) 0.000000] [s4u_test/INFO] Releasing the semaphore 2 times. +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Bye! +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Bye! +> [Jupiter:worker:(4) 0.000000] [s4u_test/INFO] Releasing mutex. +> [Jupiter:worker:(4) 0.000000] [s4u_test/INFO] Bye! + +$ $SG_TEST_EXENV ${bindir:=.}/s4u-synchro-semaphore 10 +> [Tremblay:master:(1) 0.000000] [s4u_test/INFO] Spawning 10 workers +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Got mutex. Incrementing count. +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Count is 0 +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Count is now 1. Process count is 10. +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Releasing mutex. +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Acquiring semaphore. +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Got mutex. Incrementing count. +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Count is 1 +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Count is now 2. Process count is 10. +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Releasing mutex. +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Acquiring semaphore. +> [Jupiter:worker:(4) 0.000000] [s4u_test/INFO] Got mutex. Incrementing count. +> [Jupiter:worker:(4) 0.000000] [s4u_test/INFO] Count is 2 +> [Jupiter:worker:(4) 0.000000] [s4u_test/INFO] Count is now 3. Process count is 10. +> [Jupiter:worker:(4) 0.000000] [s4u_test/INFO] Releasing mutex. +> [Jupiter:worker:(4) 0.000000] [s4u_test/INFO] Acquiring semaphore. +> [Jupiter:worker:(5) 0.000000] [s4u_test/INFO] Got mutex. Incrementing count. +> [Jupiter:worker:(5) 0.000000] [s4u_test/INFO] Count is 3 +> [Jupiter:worker:(5) 0.000000] [s4u_test/INFO] Count is now 4. Process count is 10. +> [Jupiter:worker:(5) 0.000000] [s4u_test/INFO] Releasing mutex. +> [Jupiter:worker:(5) 0.000000] [s4u_test/INFO] Acquiring semaphore. +> [Jupiter:worker:(6) 0.000000] [s4u_test/INFO] Got mutex. Incrementing count. +> [Jupiter:worker:(6) 0.000000] [s4u_test/INFO] Count is 4 +> [Jupiter:worker:(6) 0.000000] [s4u_test/INFO] Count is now 5. Process count is 10. +> [Jupiter:worker:(6) 0.000000] [s4u_test/INFO] Releasing mutex. +> [Jupiter:worker:(6) 0.000000] [s4u_test/INFO] Acquiring semaphore. +> [Jupiter:worker:(7) 0.000000] [s4u_test/INFO] Got mutex. Incrementing count. +> [Jupiter:worker:(7) 0.000000] [s4u_test/INFO] Count is 5 +> [Jupiter:worker:(7) 0.000000] [s4u_test/INFO] Count is now 6. Process count is 10. +> [Jupiter:worker:(7) 0.000000] [s4u_test/INFO] Releasing mutex. +> [Jupiter:worker:(7) 0.000000] [s4u_test/INFO] Acquiring semaphore. +> [Jupiter:worker:(8) 0.000000] [s4u_test/INFO] Got mutex. Incrementing count. +> [Jupiter:worker:(8) 0.000000] [s4u_test/INFO] Count is 6 +> [Jupiter:worker:(8) 0.000000] [s4u_test/INFO] Count is now 7. Process count is 10. +> [Jupiter:worker:(8) 0.000000] [s4u_test/INFO] Releasing mutex. +> [Jupiter:worker:(8) 0.000000] [s4u_test/INFO] Acquiring semaphore. +> [Jupiter:worker:(9) 0.000000] [s4u_test/INFO] Got mutex. Incrementing count. +> [Jupiter:worker:(9) 0.000000] [s4u_test/INFO] Count is 7 +> [Jupiter:worker:(9) 0.000000] [s4u_test/INFO] Count is now 8. Process count is 10. +> [Jupiter:worker:(9) 0.000000] [s4u_test/INFO] Releasing mutex. +> [Jupiter:worker:(9) 0.000000] [s4u_test/INFO] Acquiring semaphore. +> [Jupiter:worker:(10) 0.000000] [s4u_test/INFO] Got mutex. Incrementing count. +> [Jupiter:worker:(10) 0.000000] [s4u_test/INFO] Count is 8 +> [Jupiter:worker:(10) 0.000000] [s4u_test/INFO] Count is now 9. Process count is 10. +> [Jupiter:worker:(10) 0.000000] [s4u_test/INFO] Releasing mutex. +> [Jupiter:worker:(10) 0.000000] [s4u_test/INFO] Acquiring semaphore. +> [Jupiter:worker:(11) 0.000000] [s4u_test/INFO] Got mutex. Incrementing count. +> [Jupiter:worker:(11) 0.000000] [s4u_test/INFO] Count is 9 +> [Jupiter:worker:(11) 0.000000] [s4u_test/INFO] Count is now 10. Process count is 10. +> [Jupiter:worker:(11) 0.000000] [s4u_test/INFO] Releasing the semaphore 9 times. +> [Jupiter:worker:(2) 0.000000] [s4u_test/INFO] Bye! +> [Jupiter:worker:(3) 0.000000] [s4u_test/INFO] Bye! +> [Jupiter:worker:(4) 0.000000] [s4u_test/INFO] Bye! +> [Jupiter:worker:(5) 0.000000] [s4u_test/INFO] Bye! +> [Jupiter:worker:(6) 0.000000] [s4u_test/INFO] Bye! +> [Jupiter:worker:(7) 0.000000] [s4u_test/INFO] Bye! +> [Jupiter:worker:(8) 0.000000] [s4u_test/INFO] Bye! +> [Jupiter:worker:(9) 0.000000] [s4u_test/INFO] Bye! +> [Jupiter:worker:(10) 0.000000] [s4u_test/INFO] Bye! +> [Jupiter:worker:(11) 0.000000] [s4u_test/INFO] Releasing mutex. +> [Jupiter:worker:(11) 0.000000] [s4u_test/INFO] Bye! diff --git a/include/simgrid/forward.h b/include/simgrid/forward.h index 86a28bd641..fd0ab86093 100644 --- a/include/simgrid/forward.h +++ b/include/simgrid/forward.h @@ -74,6 +74,13 @@ typedef boost::intrusive_ptr MutexPtr; class NetZone; class VirtualMachine; class File; + +class Semaphore; +/** Smart pointer to a simgrid::s4u::Semaphore */ +typedef boost::intrusive_ptr SemaphorePtr; +XBT_PUBLIC void intrusive_ptr_release(Semaphore* m); +XBT_PUBLIC void intrusive_ptr_add_ref(Semaphore* m); + class Storage; } // namespace s4u diff --git a/include/simgrid/s4u.hpp b/include/simgrid/s4u.hpp index 485ed2d433..d3182a50ba 100644 --- a/include/simgrid/s4u.hpp +++ b/include/simgrid/s4u.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include diff --git a/include/simgrid/s4u/Semaphore.hpp b/include/simgrid/s4u/Semaphore.hpp new file mode 100644 index 0000000000..442b147eb1 --- /dev/null +++ b/include/simgrid/s4u/Semaphore.hpp @@ -0,0 +1,54 @@ +/* Copyright (c) 2006-2018. 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. */ + +#ifndef SIMGRID_S4U_SEMAPHORE_HPP +#define SIMGRID_S4U_SEMAPHORE_HPP + +#include +#include + +namespace simgrid { +namespace s4u { + +/** @brief A classical semaphore, but blocking in the simulation world + * @ingroup s4u_api + * + * It is strictly impossible to use a real semaphore, such as + * sem_init, + * because it would block the whole simulation. + * Instead, you should use the present class, that offers a very similar interface. + * + * As for any S4U object, Semaphores are using the @ref s4u_raii "RAII idiom" for memory management. + * Use createSemaphore() to get a ::SemaphorePtr to a newly created semaphore + * and only manipulate ::SemaphorePtr. + * + */ +class XBT_PUBLIC Semaphore { + smx_sem_t sem_; + std::atomic_int_fast32_t refcount_{0}; + + explicit Semaphore(unsigned int initial_capacity); + ~Semaphore(); + + friend void intrusive_ptr_add_ref(Semaphore* sem); + friend void intrusive_ptr_release(Semaphore* sem); + +public: + // No copy: + /** You cannot create a new semaphore by copying an existing one. Use SemaphorePtr instead */ + Semaphore(Semaphore const&) = delete; + /** You cannot create a new semaphore by value assignment either. Use SemaphorePtr instead */ + Semaphore& operator=(Semaphore const&) = delete; + + /** Constructs a new semaphore */ + static SemaphorePtr create(unsigned int initial_capacity); + + void acquire(); + void release(); +}; + +}} // namespace simgrid::s4u + +#endif /* SIMGRID_S4U_SEMAPHORE_HPP */ diff --git a/src/s4u/s4u_Semaphore.cpp b/src/s4u/s4u_Semaphore.cpp new file mode 100644 index 0000000000..191094aeb9 --- /dev/null +++ b/src/s4u/s4u_Semaphore.cpp @@ -0,0 +1,56 @@ +/* Copyright (c) 2006-201. 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 "src/msg/msg_private.hpp" +#include "src/simix/smx_synchro_private.hpp" +#include "xbt/log.h" + +#include "simgrid/s4u/Semaphore.hpp" + +namespace simgrid { +namespace s4u { + +Semaphore::Semaphore(unsigned int initial_capacity) +{ + sem_ = simgrid::simix::simcall([initial_capacity] { return SIMIX_sem_init(initial_capacity); }); +} + +Semaphore::~Semaphore() +{ + SIMIX_sem_destroy(sem_); +} + +SemaphorePtr Semaphore::create(unsigned int initial_capacity) +{ + return SemaphorePtr(new Semaphore(initial_capacity)); +} + +void Semaphore::acquire() +{ + simcall_sem_acquire(sem_); +} + +void Semaphore::release() +{ + simgrid::simix::simcall([this] { SIMIX_sem_release(sem_); }); +} + +void intrusive_ptr_add_ref(Semaphore* sem) +{ + xbt_assert(sem); + sem->refcount_.fetch_add(1, std::memory_order_relaxed); +} + +void intrusive_ptr_release(Semaphore* sem) +{ + xbt_assert(sem); + if (sem->refcount_.fetch_sub(1, std::memory_order_release) == 1) { + std::atomic_thread_fence(std::memory_order_acquire); + delete sem; + } +} + +} +} diff --git a/tools/cmake/DefinePackages.cmake b/tools/cmake/DefinePackages.cmake index f580465713..3cbd633fb6 100644 --- a/tools/cmake/DefinePackages.cmake +++ b/tools/cmake/DefinePackages.cmake @@ -440,6 +440,7 @@ set(S4U_SRC src/s4u/s4u_Mailbox.cpp src/s4u/s4u_Mutex.cpp src/s4u/s4u_Netzone.cpp + src/s4u/s4u_Semaphore.cpp src/s4u/s4u_Storage.cpp ) @@ -707,6 +708,7 @@ set(headers_to_install include/simgrid/s4u/Mailbox.hpp include/simgrid/s4u/Mutex.hpp include/simgrid/s4u/NetZone.hpp + include/simgrid/s4u/Semaphore.hpp include/simgrid/s4u/Storage.hpp include/simgrid/s4u/VirtualMachine.hpp include/simgrid/s4u.hpp