Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Use kernelImmediate for simcall cond_init.
[simgrid.git] / src / simix / libsmx.cpp
1 /* libsmx.c - public interface to simix                                       */
2 /* --------                                                                   */
3 /* These functions are the only ones that are visible from the higher levels  */
4 /* (most of them simply add some documentation to the generated simcall body) */
5 /*                                                                            */
6 /* This is somehow the "libc" of SimGrid                                      */
7
8 /* Copyright (c) 2010-2018. The SimGrid Team. All rights reserved.            */
9
10 /* This program is free software; you can redistribute it and/or modify it
11  * under the terms of the license (GNU LGPL) which comes with this package. */
12
13 #include <cmath>         /* std::isfinite() */
14
15 #include <functional>
16
17 #include "mc/mc.h"
18 #include "simgrid/s4u/VirtualMachine.hpp"
19 #include "simgrid/simix.hpp"
20 #include "simgrid/simix/blocking_simcall.hpp"
21 #include "smx_private.hpp"
22 #include "src/kernel/activity/CommImpl.hpp"
23 #include "src/kernel/activity/ConditionVariableImpl.hpp"
24 #include "src/kernel/activity/MutexImpl.hpp"
25 #include "src/mc/mc_forward.hpp"
26 #include "src/mc/mc_replay.hpp"
27 #include "src/plugins/vm/VirtualMachineImpl.hpp"
28 #include "src/simix/smx_host_private.hpp"
29 #include "xbt/ex.h"
30 #include "xbt/functional.hpp"
31
32 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(simix);
33
34 #include "popping_bodies.cpp"
35
36 void simcall_call(smx_actor_t actor)
37 {
38   if (actor != simix_global->maestro_process) {
39     XBT_DEBUG("Yield actor '%s' on simcall %s (%d)", actor->get_cname(), SIMIX_simcall_name(actor->simcall.call),
40               (int)actor->simcall.call);
41     SIMIX_process_yield(actor);
42   } else {
43     SIMIX_simcall_handle(&actor->simcall, 0);
44   }
45 }
46
47 /**
48  * \ingroup simix_process_management
49  * \brief Creates a synchro that executes some computation of an host.
50  *
51  * This function creates a SURF action and allocates the data necessary
52  * to create the SIMIX synchro. It can raise a host_error exception if the host crashed.
53  *
54  * \param name Name of the execution synchro to create
55  * \param flops_amount amount Computation amount (in flops)
56  * \param priority computation priority
57  * \param bound
58  * \param host host where the synchro will be executed
59  * \return A new SIMIX execution synchronization
60  */
61 smx_activity_t simcall_execution_start(const char* name, double flops_amount, double priority, double bound,
62                                        simgrid::s4u::Host* host)
63 {
64   /* checking for infinite values */
65   xbt_assert(std::isfinite(flops_amount), "flops_amount is not finite!");
66   xbt_assert(std::isfinite(priority), "priority is not finite!");
67
68   return simgrid::simix::kernelImmediate([name, flops_amount, priority, bound, host] {
69     return SIMIX_execution_start(name, flops_amount, priority, bound, host);
70   });
71 }
72
73 /**
74  * \ingroup simix_process_management
75  * \brief Creates a synchro that may involve parallel computation on
76  * several hosts and communication between them.
77  *
78  * \param name Name of the execution synchro to create
79  * \param host_nb Number of hosts where the synchro will be executed
80  * \param host_list Array (of size host_nb) of hosts where the synchro will be executed
81  * \param flops_amount Array (of size host_nb) of computation amount of hosts (in bytes)
82  * \param bytes_amount Array (of size host_nb * host_nb) representing the communication
83  * amount between each pair of hosts
84  * \param rate the SURF action rate
85  * \param timeout timeout
86  * \return A new SIMIX execution synchronization
87  */
88 smx_activity_t simcall_execution_parallel_start(const char* name, int host_nb, sg_host_t* host_list,
89                                                 double* flops_amount, double* bytes_amount, double rate, double timeout)
90 {
91   /* checking for infinite values */
92   for (int i = 0 ; i < host_nb ; ++i) {
93     xbt_assert(std::isfinite(flops_amount[i]), "flops_amount[%d] is not finite!", i);
94     if (bytes_amount != nullptr) {
95       for (int j = 0 ; j < host_nb ; ++j) {
96         xbt_assert(std::isfinite(bytes_amount[i + host_nb * j]),
97                    "bytes_amount[%d+%d*%d] is not finite!", i, host_nb, j);
98       }
99     }
100   }
101
102   xbt_assert(std::isfinite(rate), "rate is not finite!");
103
104   return simgrid::simix::kernelImmediate([name, host_nb, host_list, flops_amount, bytes_amount, rate, timeout] {
105     return SIMIX_execution_parallel_start(name, host_nb, host_list, flops_amount, bytes_amount, rate, timeout);
106   });
107 }
108
109 /**
110  * \ingroup simix_process_management
111  * \brief Cancels an execution synchro.
112  *
113  * This functions stops the execution. It calls a surf function.
114  * \param execution The execution synchro to cancel
115  */
116 void simcall_execution_cancel(smx_activity_t execution)
117 {
118   simgrid::kernel::activity::ExecImplPtr exec =
119       boost::static_pointer_cast<simgrid::kernel::activity::ExecImpl>(execution);
120   if (not exec->surfAction_)
121     return;
122   simgrid::simix::kernelImmediate([exec] {
123     XBT_DEBUG("Cancel synchro %p", exec.get());
124     if (exec->surfAction_)
125       exec->surfAction_->cancel();
126   });
127 }
128
129 /**
130  * \ingroup simix_process_management
131  * \brief Changes the priority of an execution synchro.
132  *
133  * This functions changes the priority only. It calls a surf function.
134  * \param execution The execution synchro
135  * \param priority The new priority
136  */
137 void simcall_execution_set_priority(smx_activity_t execution, double priority)
138 {
139   /* checking for infinite values */
140   xbt_assert(std::isfinite(priority), "priority is not finite!");
141   simgrid::simix::kernelImmediate([execution, priority] {
142
143     simgrid::kernel::activity::ExecImplPtr exec =
144         boost::static_pointer_cast<simgrid::kernel::activity::ExecImpl>(execution);
145     if (exec->surfAction_)
146       exec->surfAction_->set_priority(priority);
147   });
148 }
149
150 /**
151  * \ingroup simix_process_management
152  * \brief Changes the capping (the maximum CPU utilization) of an execution synchro.
153  *
154  * This functions changes the capping only. It calls a surf function.
155  * \param execution The execution synchro
156  * \param bound The new bound
157  */
158 void simcall_execution_set_bound(smx_activity_t execution, double bound)
159 {
160   simgrid::simix::kernelImmediate([execution, bound] {
161     simgrid::kernel::activity::ExecImplPtr exec =
162         boost::static_pointer_cast<simgrid::kernel::activity::ExecImpl>(execution);
163     if (exec->surfAction_)
164       exec->surfAction_->set_bound(bound);
165   });
166 }
167
168 /**
169  * \ingroup simix_host_management
170  * \brief Waits for the completion of an execution synchro and destroy it.
171  *
172  * \param execution The execution synchro
173  */
174 e_smx_state_t simcall_execution_wait(smx_activity_t execution)
175 {
176   return (e_smx_state_t) simcall_BODY_execution_wait(execution);
177 }
178
179 e_smx_state_t simcall_execution_test(smx_activity_t execution)
180 {
181   return (e_smx_state_t)simcall_BODY_execution_test(execution);
182 }
183
184 void simcall_process_join(smx_actor_t process, double timeout)
185 {
186   simcall_BODY_process_join(process, timeout);
187 }
188
189 /**
190  * \ingroup simix_process_management
191  * \brief Suspends a process.
192  *
193  * This function suspends the process by suspending the synchro
194  * it was waiting for completion.
195  *
196  * \param process a SIMIX process
197  */
198 void simcall_process_suspend(smx_actor_t process)
199 {
200   simcall_BODY_process_suspend(process);
201 }
202
203 /**
204  * \ingroup simix_process_management
205  * \brief Set the user data of a #smx_actor_t.
206  *
207  * This functions sets the user data associated to \a process.
208  * \param process SIMIX process
209  * \param data User data
210  */
211 void simcall_process_set_data(smx_actor_t process, void *data)
212 {
213   simgrid::simix::kernelImmediate([process, data] { process->setUserData(data); });
214 }
215
216 /**
217  * \ingroup simix_process_management
218  * \brief Set the kill time of a process.
219  */
220 void simcall_process_set_kill_time(smx_actor_t process, double kill_time)
221 {
222
223   if (kill_time <= SIMIX_get_clock() || simix_global->kill_process_function == nullptr)
224     return;
225   XBT_DEBUG("Set kill time %f for process %s@%s", kill_time, process->get_cname(), process->host->get_cname());
226   process->kill_timer = SIMIX_timer_set(kill_time, [process] {
227     simix_global->kill_process_function(process);
228     process->kill_timer=nullptr;
229   });
230 }
231
232 /**
233  * \ingroup simix_process_management
234  * \brief Creates a new sleep SIMIX synchro.
235  *
236  * This function creates a SURF action and allocates the data necessary
237  * to create the SIMIX synchro. It can raise a host_error exception if the
238  * host crashed. The default SIMIX name of the synchro is "sleep".
239  *
240  *   \param duration Time duration of the sleep.
241  *   \return A result telling whether the sleep was successful
242  */
243 e_smx_state_t simcall_process_sleep(double duration)
244 {
245   /* checking for infinite values */
246   xbt_assert(std::isfinite(duration), "duration is not finite!");
247   return (e_smx_state_t) simcall_BODY_process_sleep(duration);
248 }
249
250 /**
251  * \ingroup simix_comm_management
252  */
253 void simcall_comm_send(smx_actor_t sender, smx_mailbox_t mbox, double task_size, double rate, void* src_buff,
254                        size_t src_buff_size, int (*match_fun)(void*, void*, simgrid::kernel::activity::CommImpl*),
255                        void (*copy_data_fun)(smx_activity_t, void*, size_t), void* data, double timeout)
256 {
257   /* checking for infinite values */
258   xbt_assert(std::isfinite(task_size), "task_size is not finite!");
259   xbt_assert(std::isfinite(rate), "rate is not finite!");
260   xbt_assert(std::isfinite(timeout), "timeout is not finite!");
261
262   xbt_assert(mbox, "No rendez-vous point defined for send");
263
264   if (MC_is_active() || MC_record_replay_is_active()) {
265     /* the model-checker wants two separate simcalls */
266     smx_activity_t comm = nullptr; /* MC needs the comm to be set to nullptr during the simcall */
267     comm = simcall_comm_isend(sender, mbox, task_size, rate,
268         src_buff, src_buff_size, match_fun, nullptr, copy_data_fun, data, 0);
269     simcall_comm_wait(comm, timeout);
270     comm = nullptr;
271   }
272   else {
273     simcall_BODY_comm_send(sender, mbox, task_size, rate, src_buff, src_buff_size,
274                          match_fun, copy_data_fun, data, timeout);
275   }
276 }
277
278 /**
279  * \ingroup simix_comm_management
280  */
281 smx_activity_t simcall_comm_isend(smx_actor_t sender, smx_mailbox_t mbox, double task_size, double rate, void* src_buff,
282                                   size_t src_buff_size,
283                                   int (*match_fun)(void*, void*, simgrid::kernel::activity::CommImpl*),
284                                   void (*clean_fun)(void*), void (*copy_data_fun)(smx_activity_t, void*, size_t),
285                                   void* data, int detached)
286 {
287   /* checking for infinite values */
288   xbt_assert(std::isfinite(task_size), "task_size is not finite!");
289   xbt_assert(std::isfinite(rate), "rate is not finite!");
290
291   xbt_assert(mbox, "No rendez-vous point defined for isend");
292
293   return simcall_BODY_comm_isend(sender, mbox, task_size, rate, src_buff,
294                                  src_buff_size, match_fun,
295                                  clean_fun, copy_data_fun, data, detached);
296 }
297
298 /**
299  * \ingroup simix_comm_management
300  */
301 void simcall_comm_recv(smx_actor_t receiver, smx_mailbox_t mbox, void* dst_buff, size_t* dst_buff_size,
302                        int (*match_fun)(void*, void*, simgrid::kernel::activity::CommImpl*),
303                        void (*copy_data_fun)(smx_activity_t, void*, size_t), void* data, double timeout, double rate)
304 {
305   xbt_assert(std::isfinite(timeout), "timeout is not finite!");
306   xbt_assert(mbox, "No rendez-vous point defined for recv");
307
308   if (MC_is_active() || MC_record_replay_is_active()) {
309     /* the model-checker wants two separate simcalls */
310     smx_activity_t comm = nullptr; /* MC needs the comm to be set to nullptr during the simcall */
311     comm = simcall_comm_irecv(receiver, mbox, dst_buff, dst_buff_size,
312                               match_fun, copy_data_fun, data, rate);
313     simcall_comm_wait(comm, timeout);
314     comm = nullptr;
315   }
316   else {
317     simcall_BODY_comm_recv(receiver, mbox, dst_buff, dst_buff_size,
318                            match_fun, copy_data_fun, data, timeout, rate);
319   }
320 }
321 /**
322  * \ingroup simix_comm_management
323  */
324 smx_activity_t simcall_comm_irecv(smx_actor_t receiver, smx_mailbox_t mbox, void* dst_buff, size_t* dst_buff_size,
325                                   int (*match_fun)(void*, void*, simgrid::kernel::activity::CommImpl*),
326                                   void (*copy_data_fun)(smx_activity_t, void*, size_t), void* data, double rate)
327 {
328   xbt_assert(mbox, "No rendez-vous point defined for irecv");
329
330   return simcall_BODY_comm_irecv(receiver, mbox, dst_buff, dst_buff_size,
331                                  match_fun, copy_data_fun, data, rate);
332 }
333
334 /**
335  * \ingroup simix_comm_management
336  */
337 smx_activity_t simcall_comm_iprobe(smx_mailbox_t mbox, int type,
338                                    int (*match_fun)(void*, void*, simgrid::kernel::activity::CommImpl*), void* data)
339 {
340   xbt_assert(mbox, "No rendez-vous point defined for iprobe");
341
342   return simcall_BODY_comm_iprobe(mbox, type, match_fun, data);
343 }
344
345 /**
346  * \ingroup simix_comm_management
347  */
348 void simcall_comm_cancel(smx_activity_t synchro)
349 {
350   simgrid::simix::kernelImmediate([synchro] {
351     simgrid::kernel::activity::CommImplPtr comm =
352         boost::static_pointer_cast<simgrid::kernel::activity::CommImpl>(synchro);
353     comm->cancel();
354   });
355 }
356
357 /**
358  * \ingroup simix_comm_management
359  */
360 unsigned int simcall_comm_waitany(xbt_dynar_t comms, double timeout)
361 {
362   return simcall_BODY_comm_waitany(comms, timeout);
363 }
364
365 /**
366  * \ingroup simix_comm_management
367  */
368 int simcall_comm_testany(smx_activity_t* comms, size_t count)
369 {
370   if (count == 0)
371     return -1;
372   return simcall_BODY_comm_testany(comms, count);
373 }
374
375 /**
376  * \ingroup simix_comm_management
377  */
378 void simcall_comm_wait(smx_activity_t comm, double timeout)
379 {
380   xbt_assert(std::isfinite(timeout), "timeout is not finite!");
381   simcall_BODY_comm_wait(comm, timeout);
382 }
383
384 /**
385  * \brief Set the category of an synchro.
386  *
387  * This functions changes the category only. It calls a surf function.
388  * \param synchro The execution synchro
389  * \param category The tracing category
390  */
391 void simcall_set_category(smx_activity_t synchro, const char *category)
392 {
393   if (category == nullptr) {
394     return;
395   }
396   simgrid::simix::kernelImmediate([synchro, category] { SIMIX_set_category(synchro, category); });
397 }
398
399 /**
400  * \ingroup simix_comm_management
401  *
402  */
403 int simcall_comm_test(smx_activity_t comm)
404 {
405   return simcall_BODY_comm_test(comm);
406 }
407
408 /**
409  * \ingroup simix_synchro_management
410  *
411  */
412 smx_mutex_t simcall_mutex_init()
413 {
414   if (not simix_global) {
415     fprintf(stderr,"You must run MSG_init before using MSG\n"); // We can't use xbt_die since we may get there before the initialization
416     xbt_abort();
417   }
418   return simgrid::simix::kernelImmediate([] { return new simgrid::kernel::activity::MutexImpl(); });
419 }
420
421 /**
422  * \ingroup simix_synchro_management
423  *
424  */
425 void simcall_mutex_lock(smx_mutex_t mutex)
426 {
427   simcall_BODY_mutex_lock(mutex);
428 }
429
430 /**
431  * \ingroup simix_synchro_management
432  *
433  */
434 int simcall_mutex_trylock(smx_mutex_t mutex)
435 {
436   return simcall_BODY_mutex_trylock(mutex);
437 }
438
439 /**
440  * \ingroup simix_synchro_management
441  *
442  */
443 void simcall_mutex_unlock(smx_mutex_t mutex)
444 {
445   simcall_BODY_mutex_unlock(mutex);
446 }
447
448 /**
449  * \ingroup simix_synchro_management
450  *
451  */
452 smx_cond_t simcall_cond_init()
453 {
454   return simgrid::simix::kernelImmediate([] { return new simgrid::kernel::activity::ConditionVariableImpl(); });
455 }
456
457 /**
458  * \ingroup simix_synchro_management
459  *
460  */
461 void simcall_cond_wait(smx_cond_t cond, smx_mutex_t mutex)
462 {
463   simcall_BODY_cond_wait(cond, mutex);
464 }
465
466 /**
467  * \ingroup simix_synchro_management
468  *
469  */
470 void simcall_cond_wait_timeout(smx_cond_t cond, smx_mutex_t mutex, double timeout)
471 {
472   xbt_assert(std::isfinite(timeout), "timeout is not finite!");
473   simcall_BODY_cond_wait_timeout(cond, mutex, timeout);
474 }
475
476 /**
477  * \ingroup simix_synchro_management
478  *
479  */
480 void simcall_sem_acquire(smx_sem_t sem)
481 {
482   simcall_BODY_sem_acquire(sem);
483 }
484
485 /**
486  * \ingroup simix_synchro_management
487  *
488  */
489 void simcall_sem_acquire_timeout(smx_sem_t sem, double timeout)
490 {
491   xbt_assert(std::isfinite(timeout), "timeout is not finite!");
492   simcall_BODY_sem_acquire_timeout(sem, timeout);
493 }
494
495 sg_size_t simcall_storage_read(surf_storage_t st, sg_size_t size)
496 {
497   return simcall_BODY_storage_read(st, size);
498 }
499
500 sg_size_t simcall_storage_write(surf_storage_t st, sg_size_t size)
501 {
502   return simcall_BODY_storage_write(st, size);
503 }
504
505 void simcall_run_kernel(std::function<void()> const& code)
506 {
507   simcall_BODY_run_kernel(&code);
508 }
509
510 void simcall_run_blocking(std::function<void()> const& code)
511 {
512   simcall_BODY_run_blocking(&code);
513 }
514
515 int simcall_mc_random(int min, int max) {
516   return simcall_BODY_mc_random(min, max);
517 }
518
519 /* ************************************************************************** */
520
521 /** @brief returns a printable string representing a simcall */
522 const char *SIMIX_simcall_name(e_smx_simcall_t kind) {
523   return simcall_names[kind];
524 }
525
526 namespace simgrid {
527 namespace simix {
528
529 void unblock(smx_actor_t process)
530 {
531   xbt_assert(SIMIX_is_maestro());
532   SIMIX_simcall_answer(&process->simcall);
533 }
534
535 }
536 }