Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
f2feb6b61c2c2c138e0dabdd15f64141c02c2912
[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         xbt_assert0((cond != NULL), "Invalid parameters");
159         smx_process_t proc = NULL;
160
161         if (xbt_swag_size(cond->sleeping) >= 1) {
162                 proc = xbt_swag_extract(cond->sleeping);
163                 xbt_swag_insert(proc, simix_global->process_to_run);
164         }
165
166         return;
167 }
168
169 /**
170  * \brief Waits on a condition.
171  *
172  * Blocks a process until the signal is called. This functions frees the mutex associated and locks it after its execution.
173  * \param cond A condition
174  * \param mutex A mutex
175  */
176 void SIMIX_cond_wait(smx_cond_t cond,smx_mutex_t mutex)
177 {
178         smx_action_t act_sleep;
179         xbt_assert0((mutex != NULL), "Invalid parameters");
180         
181         cond->mutex = mutex;
182
183         SIMIX_mutex_unlock(mutex);
184         /* create an action null only if there are no actions already on the condition, usefull if the host crashs */
185         if (xbt_fifo_size(cond->actions) ==0 ) {
186                 act_sleep = SIMIX_action_sleep(SIMIX_host_self(), -1);
187                 SIMIX_register_action_to_condition(act_sleep,cond);
188                 SIMIX_register_condition_to_action(act_sleep,cond);
189                 __SIMIX_cond_wait(cond);
190                 xbt_fifo_pop(act_sleep->cond_list);
191                 SIMIX_action_destroy(act_sleep);
192         }
193         else {
194                 __SIMIX_cond_wait(cond);
195         }
196         /* get the mutex again */
197         SIMIX_mutex_lock(cond->mutex);
198
199         return;
200 }
201
202
203 void __SIMIX_cond_wait(smx_cond_t cond)
204 {
205         smx_process_t self = SIMIX_process_self();
206         xbt_assert0((cond != NULL), "Invalid parameters");
207         
208         /* process status */    
209
210         self->simdata->cond = cond;
211         xbt_swag_insert(self, cond->sleeping);
212         xbt_context_yield();
213         self->simdata->cond = NULL;
214         while (self->simdata->suspended) {
215                 xbt_context_yield();
216         }
217         return;
218
219 }
220
221 /**
222  * \brief Waits on a condition with timeout.
223  *
224  * Same behavior of #SIMIX_cond_wait, but waits a maximum time.
225  * \param cond A condition
226  * \param mutex A mutex
227  * \param max_duration Timeout time
228  */
229 void SIMIX_cond_wait_timeout(smx_cond_t cond,smx_mutex_t mutex, double max_duration)
230 {
231         xbt_assert0((mutex != NULL), "Invalid parameters");
232         smx_action_t act_sleep;
233
234         cond->mutex = mutex;
235
236         SIMIX_mutex_unlock(mutex);
237         if (max_duration >=0) {
238                 act_sleep = SIMIX_action_sleep(SIMIX_host_self(), max_duration);
239                 SIMIX_register_action_to_condition(act_sleep,cond);
240                 SIMIX_register_condition_to_action(act_sleep,cond);
241         }
242         __SIMIX_cond_wait(cond);
243
244         /* get the mutex again */
245         SIMIX_mutex_lock(cond->mutex);
246
247         return;
248 }
249
250 /**
251  * \brief Broadcasts a condition.
252  *
253  * Signalizes a condition and wakes up ALL sleping process. If there are no process sleeping, no action is done.
254  * \param cond A condition
255  */
256 void SIMIX_cond_broadcast(smx_cond_t cond)
257 {
258         xbt_assert0((cond != NULL), "Invalid parameters");
259         smx_process_t proc = NULL;
260         smx_process_t proc_next = NULL;
261
262         xbt_swag_foreach_safe(proc,proc_next,cond->sleeping) {
263                 xbt_swag_remove(proc,cond->sleeping);
264                 xbt_swag_insert(proc, simix_global->process_to_run);
265         }
266
267         return;
268 }
269
270 /**
271  * \brief Destroys a contidion.
272  *
273  * Destroys and frees the condition's memory. 
274  * \param cond A condition
275  */
276 void SIMIX_cond_destroy(smx_cond_t cond)
277 {
278         if ( cond == NULL )
279                 return ;
280         else {
281                 xbt_assert0( xbt_swag_size(cond->sleeping) == 0 , "Cannot destroy conditional");
282                 xbt_swag_free(cond->sleeping);
283                 xbt_fifo_free(cond->actions);
284                 xbt_free(cond);
285                 return;
286         }
287 }
288
289 /**
290  *      \brief Set a condition to an action
291  *
292  *      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. 
293  *      \param action SIMIX action
294  *      \param cond SIMIX cond
295  */
296 void SIMIX_register_condition_to_action(smx_action_t action, smx_cond_t cond)
297 {
298         xbt_assert0( (action != NULL) && (cond != NULL), "Invalid parameters");
299
300         xbt_fifo_push(action->cond_list,cond);
301 }
302
303