Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
b80c933d83f50f86ed5cc18d0e872581c5257d89
[simgrid.git] / src / simix / smx_synchro.c
1 /*      $Id$     */
2
3 /* Copyright (c) 2007 Arnaud Legrand, Bruno Donnassolo.
4    All rights reserved.                                          */
5
6 /* This program is free software; you can redistribute it and/or modify it
7  * under the terms of the license (GNU LGPL) which comes with this package. */
8
9 #include "private.h"
10 #include "xbt/log.h"
11
12
13 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(simix_synchro, simix,
14                                 "Logging specific to SIMIX (synchronization)");
15
16
17 /****************************** Synchronization *******************************/
18
19 /*********************************** Mutex ************************************/
20
21 /**
22  * \brief Initialize a mutex.
23  *
24  * Allocs and creates the data for the mutex. It have to be called before the utilisation of the mutex.
25  * \return A mutex
26  */
27 smx_mutex_t SIMIX_mutex_init()
28 {
29         smx_mutex_t m = xbt_new0(s_smx_mutex_t,1);
30         s_smx_process_t p; /* useful to initialize sleeping swag */
31         /* structures initialization */
32         m->using = 0;
33         m->sleeping = xbt_swag_new(xbt_swag_offset(p, synchro_hookup));
34         return m;
35 }
36
37 /**
38  * \brief Locks a mutex.
39  *
40  * Tries to lock a mutex, if the mutex isn't used yet, the process can continue its execution, else it'll be blocked here. You have to call #SIMIX_mutex_unlock to free the mutex.
41  * \param mutex The mutex
42  */
43 void SIMIX_mutex_lock(smx_mutex_t mutex)
44 {
45         smx_process_t self = SIMIX_process_self();
46         xbt_assert0((mutex != NULL), "Invalid parameters");
47         
48
49         if (mutex->using) {
50                 /* somebody using the mutex, block */
51                 xbt_swag_insert(self, mutex->sleeping);
52                 self->simdata->mutex = mutex;
53                 /* wait for some process make the unlock and wake up me from mutex->sleeping */
54                 xbt_context_yield();
55                 self->simdata->mutex = NULL;
56
57                 /* verify if the process was suspended */
58                 while (self->simdata->suspended) {
59                         xbt_context_yield();
60                 }
61
62                 mutex->using = 1;
63         }
64         else {
65                 /* mutex free */
66                 mutex->using = 1;
67         }
68         return;
69 }
70
71 /**
72  * \brief Tries to lock a mutex.
73  *
74  * Tries to lock a mutex, return 1 if the mutex is free, 0 else. This function does not block the process if the mutex is used.
75  * \param mutex The mutex
76  * \return 1 - mutex free, 0 - mutex used
77  */
78 int SIMIX_mutex_trylock(smx_mutex_t mutex)
79 {
80         xbt_assert0((mutex != NULL), "Invalid parameters");
81         
82         if (mutex->using) 
83                 return 0;
84         else {
85                 mutex->using = 1;
86                 return 1;
87         }
88 }
89
90 /**
91  * \brief Unlocks a mutex.
92  *
93  * Unlocks the mutex and wakes up a process blocked on it. If there are no process sleeping, only sets the mutex as free.
94  * \param mutex The mutex
95  */
96 void SIMIX_mutex_unlock(smx_mutex_t mutex)
97 {
98         smx_process_t p;        /*process to wake up */
99
100         xbt_assert0((mutex != NULL), "Invalid parameters");
101
102         if (xbt_swag_size(mutex->sleeping) > 0) {
103                 p = xbt_swag_extract(mutex->sleeping);
104                 mutex->using = 0;
105                 xbt_swag_insert(p, simix_global->process_to_run);
106         }
107         else {
108                 /* nobody to wake up */
109                 mutex->using = 0;
110         }
111         return;
112 }
113
114 /**
115  * \brief Destroys a mutex.
116  *
117  * Destroys and frees the mutex's memory. 
118  * \param mutex A mutex
119  */
120 void SIMIX_mutex_destroy(smx_mutex_t mutex)
121 {
122         if ( mutex == NULL )
123                 return ;
124         else {
125                 xbt_swag_free(mutex->sleeping);
126                 xbt_free(mutex);
127                 return ;
128         }
129 }
130
131 /******************************** Conditional *********************************/
132
133 /**
134  * \brief Initialize a condition.
135  *
136  * Allocs and creates the data for the condition. It have to be called before the utilisation of the condition.
137  * \return A condition
138  */
139 smx_cond_t SIMIX_cond_init()
140 {
141         smx_cond_t cond = xbt_new0(s_smx_cond_t,1);
142         s_smx_process_t p;
143         
144         cond->sleeping = xbt_swag_new(xbt_swag_offset(p,synchro_hookup));
145         cond->actions = xbt_fifo_new();
146         cond->mutex = NULL;
147         return cond;
148 }
149
150 /**
151  * \brief Signalizes a condition.
152  *
153  * Signalizes a condition and wakes up a sleping process. If there are no process sleeping, no action is done.
154  * \param cond A condition
155  */
156 void SIMIX_cond_signal(smx_cond_t cond)
157 {
158    DEBUG1("Signal condition %p",cond);
159         xbt_assert0((cond != NULL), "Invalid parameters");
160         smx_process_t proc = NULL;
161
162         if (xbt_swag_size(cond->sleeping) >= 1) {
163                 proc = xbt_swag_extract(cond->sleeping);
164                 xbt_swag_insert(proc, simix_global->process_to_run);
165         }
166
167         return;
168 }
169
170 /**
171  * \brief Waits on a condition.
172  *
173  * Blocks a process until the signal is called. This functions frees the mutex associated and locks it after its execution.
174  * \param cond A condition
175  * \param mutex A mutex
176  */
177 void SIMIX_cond_wait(smx_cond_t cond,smx_mutex_t mutex)
178 {
179         smx_action_t act_sleep;
180         xbt_assert0((mutex != NULL), "Invalid parameters");
181         
182    DEBUG1("Wait condition %p",cond);
183         cond->mutex = mutex;
184
185         SIMIX_mutex_unlock(mutex);
186         /* create an action null only if there are no actions already on the condition, usefull if the host crashs */
187         if (xbt_fifo_size(cond->actions) ==0 ) {
188                 act_sleep = SIMIX_action_sleep(SIMIX_host_self(), -1);
189                 SIMIX_register_action_to_condition(act_sleep,cond);
190                 SIMIX_register_condition_to_action(act_sleep,cond);
191                 __SIMIX_cond_wait(cond);
192                 xbt_fifo_pop(act_sleep->cond_list);
193                 SIMIX_action_destroy(act_sleep);
194         }
195         else {
196                 __SIMIX_cond_wait(cond);
197         }
198         /* get the mutex again */
199         SIMIX_mutex_lock(cond->mutex);
200
201         return;
202 }
203
204 xbt_fifo_t SIMIX_cond_get_actions(smx_cond_t cond)
205 {
206         xbt_assert0((cond != NULL), "Invalid parameters");
207         return cond->actions;
208 }
209
210 void __SIMIX_cond_wait(smx_cond_t cond)
211 {
212         smx_process_t self = SIMIX_process_self();
213         xbt_assert0((cond != NULL), "Invalid parameters");
214         
215         /* process status */    
216
217         self->simdata->cond = cond;
218         xbt_swag_insert(self, cond->sleeping);
219         xbt_context_yield();
220         self->simdata->cond = NULL;
221         while (self->simdata->suspended) {
222                 xbt_context_yield();
223         }
224         return;
225
226 }
227
228 /**
229  * \brief Waits on a condition with timeout.
230  *
231  * Same behavior of #SIMIX_cond_wait, but waits a maximum time and throws an timeout_error if it happens.
232  * \param cond A condition
233  * \param mutex A mutex
234  * \param max_duration Timeout time
235  */
236 void SIMIX_cond_wait_timeout(smx_cond_t cond,smx_mutex_t mutex, double max_duration)
237 {
238         xbt_assert0((mutex != NULL), "Invalid parameters");
239         smx_action_t act_sleep;
240
241    DEBUG1("Timed wait condition %p",cond);
242         cond->mutex = mutex;
243
244         SIMIX_mutex_unlock(mutex);
245         if (max_duration >=0) {
246                 act_sleep = SIMIX_action_sleep(SIMIX_host_self(), max_duration);
247                 SIMIX_register_action_to_condition(act_sleep,cond);
248                 SIMIX_register_condition_to_action(act_sleep,cond);
249                 __SIMIX_cond_wait(cond);
250                 xbt_fifo_remove(act_sleep->cond_list,cond);
251                 if ( SIMIX_action_get_state(act_sleep) == SURF_ACTION_DONE) {
252                         SIMIX_action_destroy(act_sleep);
253                         THROW0(timeout_error,0,"Condition timeout"); 
254                 }
255                 else {
256                         SIMIX_action_destroy(act_sleep);
257                 }
258
259         }
260         else
261                 __SIMIX_cond_wait(cond);
262
263         /* get the mutex again */
264         SIMIX_mutex_lock(cond->mutex);
265
266         return;
267 }
268
269 /**
270  * \brief Broadcasts a condition.
271  *
272  * Signalizes a condition and wakes up ALL sleping process. If there are no process sleeping, no action is done.
273  * \param cond A condition
274  */
275 void SIMIX_cond_broadcast(smx_cond_t cond)
276 {
277         xbt_assert0((cond != NULL), "Invalid parameters");
278         smx_process_t proc = NULL;
279         smx_process_t proc_next = NULL;
280
281    DEBUG1("Broadcast condition %p",cond);
282         xbt_swag_foreach_safe(proc,proc_next,cond->sleeping) {
283                 xbt_swag_remove(proc,cond->sleeping);
284                 xbt_swag_insert(proc, simix_global->process_to_run);
285         }
286
287         return;
288 }
289
290 /**
291  * \brief Destroys a contidion.
292  *
293  * Destroys and frees the condition's memory. 
294  * \param cond A condition
295  */
296 void SIMIX_cond_destroy(smx_cond_t cond)
297 {
298    DEBUG1("Destroy condition %p",cond);
299    xbt_backtrace_display_current();
300         if ( cond == NULL )
301                 return ;
302         else {
303           xbt_fifo_item_t item = NULL;
304           smx_action_t action = NULL;
305
306                 xbt_assert0( xbt_swag_size(cond->sleeping) == 0 , "Cannot destroy conditional since someone is still using it");
307                 xbt_swag_free(cond->sleeping);
308
309                 xbt_fifo_foreach(cond->actions,item,action,smx_action_t) {
310                   SIMIX_unregister_condition_to_action(action, cond);
311                 }
312                 xbt_fifo_free(cond->actions);
313                 xbt_free(cond);
314                 return;
315         }
316 }
317
318 /**
319  *      \brief Set a condition to an action
320  *
321  *      Creates the "link" between an action and a condition. You have to call this function when you create an action and want to wait its ending. 
322  *      \param action SIMIX action
323  *      \param cond SIMIX cond
324  */
325 void SIMIX_register_condition_to_action(smx_action_t action, smx_cond_t cond)
326 {
327         xbt_assert0( (action != NULL) && (cond != NULL), "Invalid parameters");
328
329    DEBUG2("Register condition %p to action %p",cond,action);
330         xbt_fifo_push(action->cond_list,cond);
331 }
332
333 /**
334  *      \brief Unset a condition to an action
335  *
336  *      Destroys the "link" between an action and a condition. 
337  *      \param action SIMIX action
338  *      \param cond SIMIX cond
339  */
340 void SIMIX_unregister_condition_to_action(smx_action_t action, smx_cond_t cond)
341 {
342         xbt_assert0( (action != NULL) && (cond != NULL), "Invalid parameters");
343
344         while(xbt_fifo_remove(action->cond_list,cond)) {}
345 }
346
347
348