Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
finally putting in proper use of mutexes. code still needs work.
[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 xbt_fifo_t SIMIX_cond_get_actions(smx_cond_t cond)
203 {
204         xbt_assert0((cond != NULL), "Invalid parameters");
205         return cond->actions;
206 }
207
208 void __SIMIX_cond_wait(smx_cond_t cond)
209 {
210         smx_process_t self = SIMIX_process_self();
211         xbt_assert0((cond != NULL), "Invalid parameters");
212         
213         /* process status */    
214
215         self->simdata->cond = cond;
216         xbt_swag_insert(self, cond->sleeping);
217         xbt_context_yield();
218         self->simdata->cond = NULL;
219         while (self->simdata->suspended) {
220                 xbt_context_yield();
221         }
222         return;
223
224 }
225
226 /**
227  * \brief Waits on a condition with timeout.
228  *
229  * Same behavior of #SIMIX_cond_wait, but waits a maximum time.
230  * \param cond A condition
231  * \param mutex A mutex
232  * \param max_duration Timeout time
233  */
234 void SIMIX_cond_wait_timeout(smx_cond_t cond,smx_mutex_t mutex, double max_duration)
235 {
236         xbt_assert0((mutex != NULL), "Invalid parameters");
237         smx_action_t act_sleep;
238
239         cond->mutex = mutex;
240
241         SIMIX_mutex_unlock(mutex);
242         if (max_duration >=0) {
243                 act_sleep = SIMIX_action_sleep(SIMIX_host_self(), max_duration);
244                 SIMIX_register_action_to_condition(act_sleep,cond);
245                 SIMIX_register_condition_to_action(act_sleep,cond);
246                 __SIMIX_cond_wait(cond);
247                 xbt_fifo_remove(act_sleep->cond_list,cond);
248                 SIMIX_action_destroy(act_sleep);
249         }
250         else
251                 __SIMIX_cond_wait(cond);
252
253         /* get the mutex again */
254         SIMIX_mutex_lock(cond->mutex);
255
256         return;
257 }
258
259 /**
260  * \brief Broadcasts a condition.
261  *
262  * Signalizes a condition and wakes up ALL sleping process. If there are no process sleeping, no action is done.
263  * \param cond A condition
264  */
265 void SIMIX_cond_broadcast(smx_cond_t cond)
266 {
267         xbt_assert0((cond != NULL), "Invalid parameters");
268         smx_process_t proc = NULL;
269         smx_process_t proc_next = NULL;
270
271         xbt_swag_foreach_safe(proc,proc_next,cond->sleeping) {
272                 xbt_swag_remove(proc,cond->sleeping);
273                 xbt_swag_insert(proc, simix_global->process_to_run);
274         }
275
276         return;
277 }
278
279 /**
280  * \brief Destroys a contidion.
281  *
282  * Destroys and frees the condition's memory. 
283  * \param cond A condition
284  */
285 void SIMIX_cond_destroy(smx_cond_t cond)
286 {
287         if ( cond == NULL )
288                 return ;
289         else {
290                 xbt_assert0( xbt_swag_size(cond->sleeping) == 0 , "Cannot destroy conditional");
291                 xbt_swag_free(cond->sleeping);
292                 xbt_fifo_free(cond->actions);
293                 xbt_free(cond);
294                 return;
295         }
296 }
297
298 /**
299  *      \brief Set a condition to an action
300  *
301  *      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. 
302  *      \param action SIMIX action
303  *      \param cond SIMIX cond
304  */
305 void SIMIX_register_condition_to_action(smx_action_t action, smx_cond_t cond)
306 {
307         xbt_assert0( (action != NULL) && (cond != NULL), "Invalid parameters");
308
309         xbt_fifo_push(action->cond_list,cond);
310 }
311
312