Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
don't convert host to name to host. Perl epoch is over.
[simgrid.git] / src / msg / msg_process.cpp
1 /* Copyright (c) 2004-2015. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include <functional>
8
9 #include "msg_private.h"
10 #include "xbt/sysdep.h"
11 #include "xbt/log.h"
12 #include "xbt/functional.hpp"
13 #include "src/simix/ActorImpl.hpp"
14 #include "src/simix/smx_private.h"
15
16 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(msg_process, msg, "Logging specific to MSG (process)");
17
18 /** @addtogroup m_process_management
19  *
20  *  Processes (#msg_process_t) are independent agents that can do stuff on their own. They are in charge of executing
21  *  your code interacting with the simulated world.
22  *  A process may be defined as a <em>code</em> with some <em>private data</em>.
23  *  Processes must be located on <em>hosts</em> (#msg_host_t), and they exchange data by sending tasks (#msg_task_t)
24  *  that are similar to envelops containing data.
25  */
26
27 /******************************** Process ************************************/
28 /**
29  * \brief Cleans the MSG data of a process.
30  * \param smx_proc a SIMIX process
31  */
32 void MSG_process_cleanup_from_SIMIX(smx_actor_t smx_proc)
33 {
34   simdata_process_t msg_proc;
35
36   // get the MSG process from the SIMIX process
37   if (smx_proc == SIMIX_process_self()) {
38     /* avoid a SIMIX request if this function is called by the process itself */
39     msg_proc = (simdata_process_t) SIMIX_process_self_get_data();
40     SIMIX_process_self_set_data(nullptr);
41   } else {
42     msg_proc = (simdata_process_t) simcall_process_get_data(smx_proc);
43     simcall_process_set_data(smx_proc, nullptr);
44   }
45
46   TRACE_msg_process_destroy(smx_proc->name.c_str(), smx_proc->pid);
47   // free the data if a function was provided
48   if (msg_proc && msg_proc->data && msg_global->process_data_cleanup) {
49     msg_global->process_data_cleanup(msg_proc->data);
50   }
51
52   // free the MSG process
53   xbt_free(msg_proc);
54   SIMIX_process_cleanup(smx_proc);
55 }
56
57 /* This function creates a MSG process. It has the prototype enforced by SIMIX_function_register_process_create */
58 smx_actor_t MSG_process_create_from_SIMIX(
59   const char *name, std::function<void()> code, void *data, sg_host_t host,
60   double kill_time, xbt_dict_t properties,
61   int auto_restart, smx_actor_t parent_process)
62 {
63   msg_process_t p = MSG_process_create_with_environment(name, std::move(code), data, host, properties);
64   if (p) {
65     MSG_process_set_kill_time(p,kill_time);
66     MSG_process_auto_restart_set(p,auto_restart);
67   }
68   return p;
69 }
70
71 /** \ingroup m_process_management
72  * \brief Creates and runs a new #msg_process_t.
73  *
74  * Does exactly the same as #MSG_process_create_with_arguments but without providing standard arguments
75  * (\a argc, \a argv, \a start_time, \a kill_time).
76  * \sa MSG_process_create_with_arguments
77  */
78 msg_process_t MSG_process_create(const char *name, xbt_main_func_t code, void *data, msg_host_t host)
79 {
80   return MSG_process_create_with_environment(name, code, data, host, 0, nullptr, nullptr);
81 }
82
83 /** \ingroup m_process_management
84  * \brief Creates and runs a new #msg_process_t.
85
86  * A constructor for #msg_process_t taking four arguments and returning the corresponding object. The structure (and
87  * the corresponding thread) is created, and put in the list of ready process.
88  * \param name a name for the object. It is for user-level information and can be nullptr.
89  * \param code is a function describing the behavior of the process. It should then only use functions described
90  * in \ref m_process_management (to create a new #msg_process_t for example),
91    in \ref m_host_management (only the read-only functions i.e. whose name contains the word get),
92    in \ref m_task_management (to create or destroy some #msg_task_t for example) and
93    in \ref msg_task_usage (to handle file transfers and task processing).
94  * \param data a pointer to any data one may want to attach to the new object.  It is for user-level information and
95  *        can be nullptr. It can be retrieved with the function \ref MSG_process_get_data.
96  * \param host the location where the new process is executed.
97  * \param argc first argument passed to \a code
98  * \param argv second argument passed to \a code
99  * \see msg_process_t
100  * \return The new corresponding object.
101  */
102
103 msg_process_t MSG_process_create_with_arguments(const char *name, xbt_main_func_t code, void *data, msg_host_t host,
104                                               int argc, char **argv)
105 {
106   return MSG_process_create_with_environment(name, code, data, host, argc, argv, nullptr);
107 }
108
109 /** \ingroup m_process_management
110  * \brief Creates and runs a new #msg_process_t.
111
112  * A constructor for #msg_process_t taking four arguments and returning the corresponding object. The structure (and
113  * the corresponding thread) is created, and put in the list of ready process.
114  * \param name a name for the object. It is for user-level information and can be nullptr.
115  * \param code is a function describing the behavior of the process. It should then only use functions described
116  * in \ref m_process_management (to create a new #msg_process_t for example),
117    in \ref m_host_management (only the read-only functions i.e. whose name contains the word get),
118    in \ref m_task_management (to create or destroy some #msg_task_t for example) and
119    in \ref msg_task_usage (to handle file transfers and task processing).
120  * \param data a pointer to any data one may want to attach to the new object.  It is for user-level information and
121  *        can be nullptr. It can be retrieved with the function \ref MSG_process_get_data.
122  * \param host the location where the new process is executed.
123  * \param argc first argument passed to \a code
124  * \param argv second argument passed to \a code. WARNING, these strings are freed by the SimGrid kernel when the
125  *             process exits, so they cannot be static nor shared between several processes.
126  * \param properties list a properties defined for this process
127  * \see msg_process_t
128  * \return The new corresponding object.
129  */
130 msg_process_t MSG_process_create_with_environment(const char *name, xbt_main_func_t code, void *data, msg_host_t host,
131                                                   int argc, char **argv, xbt_dict_t properties)
132 {
133   std::function<void()> function;
134   if (code)
135     function = simgrid::xbt::wrapMain(code, argc, const_cast<const char*const*>(argv));
136   msg_process_t res = MSG_process_create_with_environment(name,
137     std::move(function), data, host, properties);
138   for (int i = 0; i != argc; ++i)
139     xbt_free(argv[i]);
140   xbt_free(argv);
141   return res;
142 }
143
144 msg_process_t MSG_process_create_with_environment(
145   const char *name, std::function<void()> code, void *data,
146   msg_host_t host, xbt_dict_t properties)
147 {
148   xbt_assert(code != nullptr && host != nullptr, "Invalid parameters: host and code params must not be nullptr");
149   simdata_process_t simdata = xbt_new0(s_simdata_process_t, 1);
150   msg_process_t process;
151
152   /* Simulator data for MSG */
153   simdata->waiting_action = nullptr;
154   simdata->waiting_task = nullptr;
155   simdata->m_host = host;
156   simdata->data = data;
157   simdata->last_errno = MSG_OK;
158
159   /* Let's create the process: SIMIX may decide to start it right now,
160    * even before returning the flow control to us */
161   process = simcall_process_create(
162     name, std::move(code), simdata, host, -1,  properties, 0);
163
164   if (!process) {
165     /* Undo everything we have just changed */
166     xbt_free(simdata);
167     return nullptr;
168   }
169   else {
170     simcall_process_on_exit(process,(int_f_pvoid_pvoid_t)TRACE_msg_process_kill,process);
171   }
172   return process;
173 }
174
175 static int MSG_maestro(int argc, char** argv)
176 {
177   int res = MSG_main();
178   return res;
179 }
180
181 /* Become a process in the simulation
182  *
183  * Currently this can only be called by the main thread (once) and only work with some thread factories
184  * (currently ThreadContextFactory).
185  *
186  * In the future, it might be extended in order to attach other threads created by a third party library.
187  */
188 msg_process_t MSG_process_attach(const char *name, void *data, msg_host_t host, xbt_dict_t properties)
189 {
190   xbt_assert(host != nullptr, "Invalid parameters: host and code params must not be nullptr");
191   simdata_process_t simdata = xbt_new0(s_simdata_process_t, 1);
192   msg_process_t process;
193
194   /* Simulator data for MSG */
195   simdata->waiting_action = nullptr;
196   simdata->waiting_task = nullptr;
197   simdata->m_host = host;
198   simdata->data = data;
199   simdata->last_errno = MSG_OK;
200
201   /* Let's create the process: SIMIX may decide to start it right now, even before returning the flow control to us */
202   process = SIMIX_process_attach(name, simdata, sg_host_get_name(host), properties, nullptr);
203   if (!process)
204     xbt_die("Could not attach");
205   simcall_process_on_exit(process,(int_f_pvoid_pvoid_t)TRACE_msg_process_kill,process);
206   return process;
207 }
208
209 /** Detach a process attached with `MSG_process_attach()`
210  *
211  *  This is called when the current process has finished its job.
212  *  Used in the main thread, it waits for the simulation to finish before  returning. When it returns, the other
213  *  simulated processes and the maestro are destroyed.
214  */
215 void MSG_process_detach()
216 {
217   SIMIX_process_detach();
218 }
219
220 /** \ingroup m_process_management
221  * \param process poor victim
222  *
223  * This function simply kills a \a process... scary isn't it ? :)
224  */
225 void MSG_process_kill(msg_process_t process)
226 {
227 //  /* FIXME: why do we only cancel communication actions? is this useful? */
228 //  simdata_process_t p_simdata = simcall_process_get_data(process);
229 //  if (p_simdata->waiting_task && p_simdata->waiting_task->simdata->comm) {
230 //    simcall_comm_cancel(p_simdata->waiting_task->simdata->comm);
231 //  }
232   simcall_process_kill(process);
233 }
234
235 /**
236 * \brief Wait for the completion of a #msg_process_t.
237 *
238 * \param process the process to wait for
239 * \param timeout wait until the process is over, or the timeout occurs
240 */
241 msg_error_t MSG_process_join(msg_process_t process, double timeout){
242   simcall_process_join(process, timeout);
243   return MSG_OK;
244 }
245
246 /** \ingroup m_process_management
247  * \brief Migrates a process to another location.
248  *
249  * This function checks whether \a process and \a host are valid pointers and change the value of the #msg_host_t on
250  * which \a process is running.
251  */
252 msg_error_t MSG_process_migrate(msg_process_t process, msg_host_t host)
253 {
254   simdata_process_t simdata = (simdata_process_t) simcall_process_get_data(process);
255   simdata->m_host = host;
256   msg_host_t now = simdata->m_host;
257   TRACE_msg_process_change_host(process, now, host);
258   simcall_process_set_host(process, host);
259   return MSG_OK;
260 }
261
262 /** \ingroup m_process_management
263  * \brief Returns the user data of a process.
264  *
265  * This function checks whether \a process is a valid pointer and returns the user data associated to this process.
266  */
267 void* MSG_process_get_data(msg_process_t process)
268 {
269   xbt_assert(process != nullptr, "Invalid parameter: first parameter must not be nullptr!");
270
271   /* get from SIMIX the MSG process data, and then the user data */
272   simdata_process_t simdata = (simdata_process_t) simcall_process_get_data(process);
273   if (simdata)
274     return simdata->data;
275   else
276     return nullptr;
277 }
278
279 /** \ingroup m_process_management
280  * \brief Sets the user data of a process.
281  *
282  * This function checks whether \a process is a valid pointer and sets the user data associated to this process.
283  */
284 msg_error_t MSG_process_set_data(msg_process_t process, void *data)
285 {
286   xbt_assert(process != nullptr, "Invalid parameter: first parameter must not be nullptr!");
287
288   simdata_process_t simdata = (simdata_process_t) simcall_process_get_data(process);
289   simdata->data = data;
290
291   return MSG_OK;
292 }
293
294 /** \ingroup m_process_management
295  * \brief Sets a cleanup function to be called to free the userdata of a process when a process is destroyed.
296  * \param data_cleanup a cleanup function for the userdata of a process, or nullptr to call no function
297  */
298 XBT_PUBLIC(void) MSG_process_set_data_cleanup(void_f_pvoid_t data_cleanup) {
299   msg_global->process_data_cleanup = data_cleanup;
300 }
301
302 /** \ingroup m_process_management
303  * \brief Return the location on which a process is running.
304  * \param process a process (nullptr means the current one)
305  * \return the msg_host_t corresponding to the location on which \a process is running.
306  */
307 msg_host_t MSG_process_get_host(msg_process_t process)
308 {
309   simdata_process_t simdata;
310   if (process == nullptr) {
311     simdata = (simdata_process_t) SIMIX_process_self_get_data();
312   }
313   else {
314     simdata = (simdata_process_t) simcall_process_get_data(process);
315   }
316   return simdata ? simdata->m_host : nullptr;
317 }
318
319 /** \ingroup m_process_management
320  *
321  * \brief Return a #msg_process_t given its PID.
322  *
323  * This function search in the list of all the created msg_process_t for a msg_process_t  whose PID is equal to \a PID.
324  * If no host is found, \c nullptr is returned.
325    Note that the PID are uniq in the whole simulation, not only on a given host.
326  */
327 msg_process_t MSG_process_from_PID(int PID)
328 {
329   return SIMIX_process_from_PID(PID);
330 }
331
332 /** @brief returns a list of all currently existing processes */
333 xbt_dynar_t MSG_processes_as_dynar() {
334   return SIMIX_processes_as_dynar();
335 }
336
337 /** @brief Return the current number MSG processes. */
338 int MSG_process_get_number()
339 {
340   return SIMIX_process_count();
341 }
342
343 /** \ingroup m_process_management
344  * \brief Set the kill time of a process.
345  *
346  * \param process a process
347  * \param kill_time the time when the process is killed.
348  */
349 msg_error_t MSG_process_set_kill_time(msg_process_t process, double kill_time)
350 {
351   simcall_process_set_kill_time(process,kill_time);
352   return MSG_OK;
353 }
354
355 /** \ingroup m_process_management
356  * \brief Returns the process ID of \a process.
357  *
358  * This function checks whether \a process is a valid pointer and return its PID (or 0 in case of problem).
359  */
360 int MSG_process_get_PID(msg_process_t process)
361 {
362   /* Do not raise an exception here: this function is called by the logs
363    * and the exceptions, so it would be called back again and again */
364   if (process == nullptr)
365     return 0;
366   return process->pid;
367 }
368
369 /** \ingroup m_process_management
370  * \brief Returns the process ID of the parent of \a process.
371  *
372  * This function checks whether \a process is a valid pointer and return its PID.
373  * Returns -1 if the process has not been created by any other process.
374  */
375 int MSG_process_get_PPID(msg_process_t process)
376 {
377   return process->ppid;
378 }
379
380 /** \ingroup m_process_management
381  * \brief Return the name of a process.
382  *
383  * This function checks whether \a process is a valid pointer and return its name.
384  */
385 const char *MSG_process_get_name(msg_process_t process)
386 {
387   return process->name.c_str();
388 }
389
390 /** \ingroup m_process_management
391  * \brief Returns the value of a given process property
392  *
393  * \param process a process
394  * \param name a property name
395  * \return value of a property (or nullptr if the property is not set)
396  */
397 const char *MSG_process_get_property_value(msg_process_t process, const char *name)
398 {
399   return (char*) xbt_dict_get_or_null(MSG_process_get_properties(process), name);
400 }
401
402 /** \ingroup m_process_management
403  * \brief Return the list of properties
404  *
405  * This function returns all the parameters associated with a process
406  */
407 xbt_dict_t MSG_process_get_properties(msg_process_t process)
408 {
409   xbt_assert(process != nullptr, "Invalid parameter: First argument must not be nullptr");
410   return simcall_process_get_properties(process);
411 }
412
413 /** \ingroup m_process_management
414  * \brief Return the PID of the current process.
415  *
416  * This function returns the PID of the currently running #msg_process_t.
417  */
418 int MSG_process_self_PID()
419 {
420   return MSG_process_get_PID(MSG_process_self());
421 }
422
423 /** \ingroup m_process_management
424  * \brief Return the PPID of the current process.
425  *
426  * This function returns the PID of the parent of the currently running #msg_process_t.
427  */
428 int MSG_process_self_PPID()
429 {
430   return MSG_process_get_PPID(MSG_process_self());
431 }
432
433 /** \ingroup m_process_management
434  * \brief Return the current process.
435  *
436  * This function returns the currently running #msg_process_t.
437  */
438 msg_process_t MSG_process_self()
439 {
440   return SIMIX_process_self();
441 }
442
443 /** \ingroup m_process_management
444  * \brief Suspend the process.
445  *
446  * This function suspends the process by suspending the task on which it was waiting for the completion.
447  */
448 msg_error_t MSG_process_suspend(msg_process_t process)
449 {
450   xbt_assert(process != nullptr, "Invalid parameter: First argument must not be nullptr");
451
452   TRACE_msg_process_suspend(process);
453   simcall_process_suspend(process);
454   return MSG_OK;
455 }
456
457 /** \ingroup m_process_management
458  * \brief Resume a suspended process.
459  *
460  * This function resumes a suspended process by resuming the task on which it was waiting for the completion.
461  */
462 msg_error_t MSG_process_resume(msg_process_t process)
463 {
464   xbt_assert(process != nullptr, "Invalid parameter: First argument must not be nullptr");
465
466   TRACE_msg_process_resume(process);
467   simcall_process_resume(process);
468   return MSG_OK;
469 }
470
471 /** \ingroup m_process_management
472  * \brief Returns true if the process is suspended .
473  *
474  * This checks whether a process is suspended or not by inspecting the task on which it was waiting for the completion.
475  */
476 int MSG_process_is_suspended(msg_process_t process)
477 {
478   xbt_assert(process != nullptr, "Invalid parameter: First argument must not be nullptr");
479   return simcall_process_is_suspended(process);
480 }
481
482 smx_context_t MSG_process_get_smx_ctx(msg_process_t process) {
483   return SIMIX_process_get_context(process);
484 }
485 /**
486  * \ingroup m_process_management
487  * \brief Add a function to the list of "on_exit" functions for the current process.
488  * The on_exit functions are the functions executed when your process is killed.
489  * You should use them to free the data used by your process.
490  */
491 void MSG_process_on_exit(int_f_pvoid_pvoid_t fun, void *data) {
492   simcall_process_on_exit(MSG_process_self(),fun,data);
493 }
494 /**
495  * \ingroup m_process_management
496  * \brief Sets the "auto-restart" flag of the process.
497  * If the flag is set to 1, the process will be automatically restarted when its host comes back up.
498  */
499 XBT_PUBLIC(void) MSG_process_auto_restart_set(msg_process_t process, int auto_restart) {
500   simcall_process_auto_restart_set(process,auto_restart);
501 }
502 /*
503  * \ingroup m_process_management
504  * \brief Restarts a process from the beginning.
505  */
506 XBT_PUBLIC(msg_process_t) MSG_process_restart(msg_process_t process) {
507   return simcall_process_restart(process);
508 }