Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Separate ConditionVariableImpl into its own files
[simgrid.git] / src / simix / smx_synchro.cpp
1 /* Copyright (c) 2007-2018. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include "smx_private.hpp"
7 #include "src/kernel/activity/ConditionVariableImpl.hpp"
8 #include "src/kernel/activity/MutexImpl.hpp"
9 #include "src/kernel/activity/SynchroRaw.hpp"
10 #include "src/simix/smx_synchro_private.hpp"
11 #include "src/surf/cpu_interface.hpp"
12 #include <xbt/ex.hpp>
13
14 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(simix_synchro, simix, "SIMIX Synchronization (mutex, semaphores and conditions)");
15
16 static void _SIMIX_cond_wait(smx_cond_t cond, smx_mutex_t mutex, double timeout,
17                              smx_actor_t issuer, smx_simcall_t simcall);
18 static void _SIMIX_sem_wait(smx_sem_t sem, double timeout, smx_actor_t issuer,
19                             smx_simcall_t simcall);
20
21 /***************************** Raw synchronization *********************************/
22
23 smx_activity_t SIMIX_synchro_wait(sg_host_t smx_host, double timeout)
24 {
25   XBT_IN("(%p, %f)",smx_host,timeout);
26
27   simgrid::kernel::activity::RawImplPtr sync =
28       simgrid::kernel::activity::RawImplPtr(new simgrid::kernel::activity::RawImpl());
29   sync->sleep                          = smx_host->pimpl_cpu->sleep(timeout);
30   sync->sleep->set_data(sync.get());
31   XBT_OUT();
32   return sync;
33 }
34
35 void SIMIX_synchro_stop_waiting(smx_actor_t process, smx_simcall_t simcall)
36 {
37   XBT_IN("(%p, %p)",process,simcall);
38   switch (simcall->call) {
39
40     case SIMCALL_MUTEX_LOCK:
41       simgrid::xbt::intrusive_erase(simcall_mutex_lock__get__mutex(simcall)->sleeping, *process);
42       break;
43
44     case SIMCALL_COND_WAIT:
45       simgrid::xbt::intrusive_erase(simcall_cond_wait__get__cond(simcall)->sleeping, *process);
46       break;
47
48     case SIMCALL_COND_WAIT_TIMEOUT:
49       simgrid::xbt::intrusive_erase(simcall_cond_wait_timeout__get__cond(simcall)->sleeping, *process);
50       break;
51
52     case SIMCALL_SEM_ACQUIRE:
53       simgrid::xbt::intrusive_erase(simcall_sem_acquire__get__sem(simcall)->sleeping, *process);
54       break;
55
56     case SIMCALL_SEM_ACQUIRE_TIMEOUT:
57       simgrid::xbt::intrusive_erase(simcall_sem_acquire_timeout__get__sem(simcall)->sleeping, *process);
58       break;
59
60     default:
61       THROW_IMPOSSIBLE;
62   }
63   XBT_OUT();
64 }
65
66 void SIMIX_synchro_finish(smx_activity_t synchro)
67 {
68   XBT_IN("(%p)", synchro.get());
69   smx_simcall_t simcall = synchro->simcalls.front();
70   synchro->simcalls.pop_front();
71
72   switch (synchro->state) {
73
74     case SIMIX_SRC_TIMEOUT:
75       SMX_EXCEPTION(simcall->issuer, timeout_error, 0, "Synchro's wait timeout");
76       break;
77
78     case SIMIX_FAILED:
79         simcall->issuer->context->iwannadie = 1;
80       break;
81
82     default:
83       THROW_IMPOSSIBLE;
84       break;
85   }
86
87   SIMIX_synchro_stop_waiting(simcall->issuer, simcall);
88   simcall->issuer->waiting_synchro = nullptr;
89   SIMIX_simcall_answer(simcall);
90   XBT_OUT();
91 }
92
93 /******************************** Semaphores **********************************/
94 /** @brief Initialize a semaphore */
95 smx_sem_t SIMIX_sem_init(unsigned int value)
96 {
97   XBT_IN("(%u)",value);
98   smx_sem_t sem = new s_smx_sem_t;
99   sem->value = value;
100   XBT_OUT();
101   return sem;
102 }
103
104 /** @brief Destroys a semaphore */
105 void SIMIX_sem_destroy(smx_sem_t sem)
106 {
107   XBT_IN("(%p)",sem);
108   XBT_DEBUG("Destroy semaphore %p", sem);
109   if (sem != nullptr) {
110     xbt_assert(sem->sleeping.empty(), "Cannot destroy semaphore since someone is still using it");
111     delete sem;
112   }
113   XBT_OUT();
114 }
115
116 /** @brief release the semaphore
117  *
118  * Unlock a process waiting on the semaphore.
119  * If no one was blocked, the semaphore capacity is increased by 1.
120  */
121 void SIMIX_sem_release(smx_sem_t sem)
122 {
123   XBT_IN("(%p)",sem);
124   XBT_DEBUG("Sem release semaphore %p", sem);
125   if (not sem->sleeping.empty()) {
126     auto& proc = sem->sleeping.front();
127     sem->sleeping.pop_front();
128     proc.waiting_synchro = nullptr;
129     SIMIX_simcall_answer(&proc.simcall);
130   } else {
131     sem->value++;
132   }
133   XBT_OUT();
134 }
135
136 /** @brief Returns true if acquiring this semaphore would block */
137 int SIMIX_sem_would_block(smx_sem_t sem)
138 {
139   XBT_IN("(%p)",sem);
140   XBT_OUT();
141   return (sem->value <= 0);
142 }
143
144 /** @brief Returns the current capacity of the semaphore */
145 int SIMIX_sem_get_capacity(smx_sem_t sem)
146 {
147   XBT_IN("(%p)",sem);
148   XBT_OUT();
149   return sem->value;
150 }
151
152 static void _SIMIX_sem_wait(smx_sem_t sem, double timeout, smx_actor_t issuer,
153                             smx_simcall_t simcall)
154 {
155   XBT_IN("(%p, %f, %p, %p)",sem,timeout,issuer,simcall);
156   smx_activity_t synchro = nullptr;
157
158   XBT_DEBUG("Wait semaphore %p (timeout:%f)", sem, timeout);
159   if (sem->value <= 0) {
160     synchro = SIMIX_synchro_wait(issuer->host, timeout);
161     synchro->simcalls.push_front(simcall);
162     issuer->waiting_synchro = synchro;
163     sem->sleeping.push_back(*issuer);
164   } else {
165     sem->value--;
166     SIMIX_simcall_answer(simcall);
167   }
168   XBT_OUT();
169 }
170
171 /**
172  * \brief Handles a sem acquire simcall without timeout.
173  * \param simcall the simcall
174  */
175 void simcall_HANDLER_sem_acquire(smx_simcall_t simcall, smx_sem_t sem)
176 {
177   XBT_IN("(%p)",simcall);
178   _SIMIX_sem_wait(sem, -1, simcall->issuer, simcall);
179   XBT_OUT();
180 }
181
182 /**
183  * \brief Handles a sem acquire simcall with timeout.
184  * \param simcall the simcall
185  */
186 void simcall_HANDLER_sem_acquire_timeout(smx_simcall_t simcall, smx_sem_t sem, double timeout)
187 {
188   XBT_IN("(%p)",simcall);
189   _SIMIX_sem_wait(sem, timeout, simcall->issuer, simcall);
190   XBT_OUT();
191 }