1 /* Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009, 2010. The SimGrid Team.
2 * All rights reserved. */
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. */
8 #include "xbt/sysdep.h"
14 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(msg_gos, msg,
15 "Logging specific to MSG (gos)");
17 /** \ingroup msg_gos_functions
19 * \brief Return the last value returned by a MSG function (except
22 MSG_error_t MSG_get_errno(void)
24 return PROCESS_GET_ERRNO();
27 /** \ingroup msg_gos_functions
28 * \brief Executes a task and waits for its termination.
30 * This function is used for describing the behavior of an agent. It
31 * takes only one parameter.
32 * \param task a #m_task_t to execute on the location on which the
34 * \return #MSG_FATAL if \a task is not properly initialized and
37 MSG_error_t MSG_task_execute(m_task_t task)
39 simdata_task_t simdata = NULL;
40 m_process_t self = MSG_process_self();
41 e_smx_state_t comp_state;
44 simdata = task->simdata;
46 xbt_assert0(simdata->host_nb == 0,
47 "This is a parallel task. Go to hell.");
50 TRACE_msg_task_execute_start(task);
53 xbt_assert1((!simdata->compute) && (task->simdata->isused == 0),
54 "This task is executed somewhere else. Go fix your code! %d",
55 task->simdata->isused);
57 DEBUG1("Computing on %s", MSG_process_self()->simdata->m_host->name);
59 if (simdata->computation_amount == 0) {
61 TRACE_msg_task_execute_end(task);
67 SIMIX_req_host_execute(task->name, SIMIX_host_self(),
68 simdata->computation_amount,
71 SIMIX_req_set_category(simdata->compute, task->category);
74 self->simdata->waiting_action = simdata->compute;
75 comp_state = SIMIX_req_host_execution_wait(simdata->compute);
76 self->simdata->waiting_action = NULL;
80 DEBUG2("Execution task '%s' finished in state %d", task->name, comp_state);
81 if (comp_state == SIMIX_DONE) {
82 /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
83 SIMIX_req_host_execution_destroy(task->simdata->compute);
84 simdata->computation_amount = 0.0;
86 simdata->compute = NULL;
88 TRACE_msg_task_execute_end(task);
91 } else if (SIMIX_req_host_get_state(SIMIX_host_self()) == 0) {
92 /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
93 SIMIX_req_host_execution_destroy(task->simdata->compute);
95 simdata->compute = NULL;
97 TRACE_msg_task_execute_end(task);
99 MSG_RETURN(MSG_HOST_FAILURE);
101 /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
102 SIMIX_req_host_execution_destroy(task->simdata->compute);
103 simdata->comm = NULL;
104 simdata->compute = NULL;
106 TRACE_msg_task_execute_end(task);
108 MSG_RETURN(MSG_TASK_CANCELLED);
112 /** \ingroup m_task_management
113 * \brief Creates a new #m_task_t (a parallel one....).
115 * A constructor for #m_task_t taking six arguments and returning the
116 corresponding object.
117 * \param name a name for the object. It is for user-level information
119 * \param host_nb the number of hosts implied in the parallel task.
120 * \param host_list an array of \p host_nb m_host_t.
121 * \param computation_amount an array of \p host_nb
122 doubles. computation_amount[i] is the total number of operations
123 that have to be performed on host_list[i].
124 * \param communication_amount an array of \p host_nb* \p host_nb doubles.
125 * \param data a pointer to any data may want to attach to the new
126 object. It is for user-level information and can be NULL. It can
127 be retrieved with the function \ref MSG_task_get_data.
129 * \return The new corresponding object.
132 MSG_parallel_task_create(const char *name, int host_nb,
133 const m_host_t * host_list,
134 double *computation_amount,
135 double *communication_amount, void *data)
138 simdata_task_t simdata = xbt_new0(s_simdata_task_t, 1);
139 m_task_t task = xbt_new0(s_m_task_t, 1);
140 task->simdata = simdata;
143 task->name = xbt_strdup(name);
147 simdata->computation_amount = 0;
148 simdata->message_size = 0;
149 simdata->compute = NULL;
150 simdata->comm = NULL;
151 simdata->rate = -1.0;
153 simdata->sender = NULL;
154 simdata->receiver = NULL;
155 simdata->source = NULL;
157 simdata->host_nb = host_nb;
158 simdata->host_list = xbt_new0(smx_host_t, host_nb);
159 simdata->comp_amount = computation_amount;
160 simdata->comm_amount = communication_amount;
162 for (i = 0; i < host_nb; i++)
163 simdata->host_list[i] = host_list[i]->simdata->smx_host;
168 MSG_error_t MSG_parallel_task_execute(m_task_t task)
170 simdata_task_t simdata = NULL;
171 m_process_t self = MSG_process_self();
174 simdata = task->simdata;
176 xbt_assert0((!simdata->compute)
177 && (task->simdata->isused == 0),
178 "This task is executed somewhere else. Go fix your code!");
180 xbt_assert0(simdata->host_nb,
181 "This is not a parallel task. Go to hell.");
183 DEBUG1("Parallel computing on %s", MSG_process_self()->simdata->m_host->name);
188 SIMIX_req_host_parallel_execute(task->name, simdata->host_nb,
190 simdata->comp_amount,
191 simdata->comm_amount, 1.0, -1.0);
192 DEBUG1("Parallel execution action created: %p", simdata->compute);
194 self->simdata->waiting_action = simdata->compute;
195 SIMIX_req_host_execution_wait(simdata->compute);
196 self->simdata->waiting_action = NULL;
198 DEBUG2("Finished waiting for execution of action %p, state = %d", simdata->compute, SIMIX_req_host_execution_get_state(task->simdata->compute));
202 if (SIMIX_req_host_execution_get_state(task->simdata->compute) == SIMIX_DONE) {
203 /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
204 SIMIX_req_host_execution_destroy(task->simdata->compute);
205 simdata->computation_amount = 0.0;
206 simdata->comm = NULL;
207 simdata->compute = NULL;
209 } else if (SIMIX_req_host_get_state(SIMIX_host_self()) == 0) {
210 /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
211 SIMIX_req_host_execution_destroy(task->simdata->compute);
212 simdata->comm = NULL;
213 simdata->compute = NULL;
214 MSG_RETURN(MSG_HOST_FAILURE);
216 /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
217 SIMIX_req_host_execution_destroy(task->simdata->compute);
218 simdata->comm = NULL;
219 simdata->compute = NULL;
220 MSG_RETURN(MSG_TASK_CANCELLED);
225 /** \ingroup msg_gos_functions
226 * \brief Sleep for the specified number of seconds
228 * Makes the current process sleep until \a time seconds have elapsed.
230 * \param nb_sec a number of second
232 MSG_error_t MSG_process_sleep(double nb_sec)
235 /*m_process_t proc = MSG_process_self();*/
238 TRACE_msg_process_sleep_in(MSG_process_self());
241 /* create action to sleep */
242 state = SIMIX_req_process_sleep(nb_sec);
244 /*proc->simdata->waiting_action = act_sleep;
246 FIXME: check if not setting the waiting_action breaks something on msg
248 proc->simdata->waiting_action = NULL;*/
250 if (state == SIMIX_DONE) {
251 if (SIMIX_req_host_get_state(SIMIX_host_self()) == SURF_RESOURCE_OFF) {
253 TRACE_msg_process_sleep_out(MSG_process_self());
255 MSG_RETURN(MSG_HOST_FAILURE);
259 TRACE_msg_process_sleep_out(MSG_process_self());
261 MSG_RETURN(MSG_HOST_FAILURE);
264 TRACE_msg_process_sleep_out(MSG_process_self());
269 /** \ingroup msg_gos_functions
270 * \brief Listen on \a channel and waits for receiving a task from \a host.
272 * It takes three parameters.
273 * \param task a memory location for storing a #m_task_t. It will
274 hold a task when this function will return. Thus \a task should not
275 be equal to \c NULL and \a *task should be equal to \c NULL. If one of
276 those two condition does not hold, there will be a warning message.
277 * \param channel the channel on which the agent should be
278 listening. This value has to be >=0 and < than the maximal
279 number of channels fixed with MSG_set_channel_number().
280 * \param host the host that is to be watched.
281 * \return #MSG_FATAL if \a task is equal to \c NULL, #MSG_WARNING
282 if \a *task is not equal to \c NULL, and #MSG_OK otherwise.
285 MSG_task_get_from_host(m_task_t * task, m_channel_t channel, m_host_t host)
287 return MSG_task_get_ext(task, channel, -1, host);
290 /** \ingroup msg_gos_functions
291 * \brief Listen on a channel and wait for receiving a task.
293 * It takes two parameters.
294 * \param task a memory location for storing a #m_task_t. It will
295 hold a task when this function will return. Thus \a task should not
296 be equal to \c NULL and \a *task should be equal to \c NULL. If one of
297 those two condition does not hold, there will be a warning message.
298 * \param channel the channel on which the agent should be
299 listening. This value has to be >=0 and < than the maximal
300 number of channels fixed with MSG_set_channel_number().
301 * \return #MSG_FATAL if \a task is equal to \c NULL, #MSG_WARNING
302 * if \a *task is not equal to \c NULL, and #MSG_OK otherwise.
304 MSG_error_t MSG_task_get(m_task_t * task, m_channel_t channel)
306 return MSG_task_get_with_timeout(task, channel, -1);
309 /** \ingroup msg_gos_functions
310 * \brief Listen on a channel and wait for receiving a task with a timeout.
312 * It takes three parameters.
313 * \param task a memory location for storing a #m_task_t. It will
314 hold a task when this function will return. Thus \a task should not
315 be equal to \c NULL and \a *task should be equal to \c NULL. If one of
316 those two condition does not hold, there will be a warning message.
317 * \param channel the channel on which the agent should be
318 listening. This value has to be >=0 and < than the maximal
319 number of channels fixed with MSG_set_channel_number().
320 * \param max_duration the maximum time to wait for a task before giving
321 up. In such a case, #MSG_TRANSFER_FAILURE will be returned, \a task
322 will not be modified and will still be
323 equal to \c NULL when returning.
324 * \return #MSG_FATAL if \a task is equal to \c NULL, #MSG_WARNING
325 if \a *task is not equal to \c NULL, and #MSG_OK otherwise.
328 MSG_task_get_with_timeout(m_task_t * task, m_channel_t channel,
331 return MSG_task_get_ext(task, channel, max_duration, NULL);
334 /** \defgroup msg_gos_functions MSG Operating System Functions
335 * \brief This section describes the functions that can be used
336 * by an agent for handling some task.
340 MSG_task_get_ext(m_task_t * task, m_channel_t channel, double timeout,
343 xbt_assert1((channel >= 0)
344 && (channel < msg_global->max_channel), "Invalid channel %d",
348 MSG_mailbox_get_task_ext(MSG_mailbox_get_by_channel
349 (MSG_host_self(), channel), task, host,
354 MSG_task_receive_from_host(m_task_t * task, const char *alias,
357 return MSG_task_receive_ext(task, alias, -1, host);
360 MSG_error_t MSG_task_receive(m_task_t * task, const char *alias)
362 return MSG_task_receive_with_timeout(task, alias, -1);
366 MSG_task_receive_with_timeout(m_task_t * task, const char *alias,
369 return MSG_task_receive_ext(task, alias, timeout, NULL);
373 MSG_task_receive_ext(m_task_t * task, const char *alias, double timeout,
377 ("MSG_task_receive_ext: Trying to receive a message on mailbox '%s'",
379 return MSG_mailbox_get_task_ext(MSG_mailbox_get_by_alias(alias), task,
383 /** \ingroup msg_gos_functions
384 * \brief Send a task on a channel.
386 * This function takes two parameter.
387 * \param task a #m_task_t to send on another location.
388 * \param alias the channel on which the agent should put this
389 task. This value has to be >=0 and < than the maximal number of
390 channels fixed with MSG_set_channel_number().
391 * \return the msg_comm_t communication.
393 msg_comm_t MSG_task_isend(m_task_t task, const char *alias)
395 simdata_task_t t_simdata = NULL;
396 m_process_t process = MSG_process_self();
397 msg_mailbox_t mailbox = MSG_mailbox_get_by_alias(alias);
401 /* FIXME: these functions are not tracable */
403 /* Prepare the task to send */
404 t_simdata = task->simdata;
405 t_simdata->sender = process;
406 t_simdata->source = MSG_host_self();
408 xbt_assert0(t_simdata->isused == 0,
409 "This task is still being used somewhere else. You cannot send it now. Go fix your code!");
412 msg_global->sent_msg++;
414 /* Send it by calling SIMIX network layer */
416 SIMIX_req_comm_isend(mailbox, t_simdata->message_size,
417 t_simdata->rate, task, sizeof(void *), NULL, NULL);
418 return t_simdata->comm;
421 /** \ingroup msg_gos_functions
422 * \brief Listen on a channel for receiving a task from an asynchronous communication.
424 * It takes two parameters.
425 * \param task a memory location for storing a #m_task_t.
426 * \param alias the channel on which the agent should be
427 listening. This value has to be >=0 and < than the maximal
428 number of channels fixed with MSG_set_channel_number().
429 * \return the msg_comm_t communication.
431 msg_comm_t MSG_task_irecv(m_task_t * task, const char *alias)
433 smx_rdv_t rdv = MSG_mailbox_get_by_alias(alias);
437 /* FIXME: these functions are not tracable */
440 xbt_assert0(task, "Null pointer for the task storage");
444 ("MSG_task_get() was asked to write in a non empty task struct.");
446 /* Try to receive it by calling SIMIX network layer */
447 return SIMIX_req_comm_irecv(rdv, task, NULL, NULL, NULL);
450 /** \ingroup msg_gos_functions
451 * \brief Returns whether a communication is finished.
452 * \param comm the communication to test
453 * \return TRUE if the communication is finished
454 * (but it may have failed, use MSG_comm_get_status() to know its status)
455 * or FALSE if the communication is not finished yet
456 * If the status is FALSE, don't forget to use MSG_process_sleep() after the test.
458 int MSG_comm_test(msg_comm_t comm)
463 finished = SIMIX_req_comm_test(comm);
466 switch (e.category) {
482 /** \ingroup msg_gos_functions
483 * \brief This function checks if a communication is finished
484 * \param comms a vector of communications
485 * \return the position of the finished communication if any
486 * (but it may have failed, use MSG_comm_get_status() to know its status),
487 * or -1 if none is finished
489 int MSG_comm_testany(xbt_dynar_t comms)
492 int finished_index = -1;
494 finished_index = SIMIX_req_comm_testany(comms);
497 switch (e.category) {
502 finished_index = e.value;
510 return finished_index;
513 /** \ingroup msg_gos_functions
514 * \brief After received TRUE to MSG_comm_test(), the communication should be destroyed.
516 * It takes one parameter.
517 * \param comm the communication to destroy.
519 void MSG_comm_destroy(msg_comm_t comm)
521 if (SIMIX_req_comm_get_src_proc(comm) != SIMIX_process_self()
522 && MSG_comm_get_status(comm) == MSG_OK) {
524 task = (m_task_t) SIMIX_req_comm_get_src_buff(comm);
525 task->simdata->isused=0;
527 SIMIX_req_comm_destroy(comm);
530 /** \ingroup msg_gos_functions
531 * \brief Wait for the completion of a communication.
533 * It takes two parameters.
534 * \param comm the communication to wait.
535 * \param timeout Wait until the communication terminates or the timeout occurs
536 * \return MSG_error_t
538 MSG_error_t MSG_comm_wait(msg_comm_t comm, double timeout)
541 MSG_error_t res = MSG_OK;
543 SIMIX_req_comm_wait(comm, timeout);
545 if (SIMIX_req_comm_get_src_proc(comm) != SIMIX_process_self()) {
547 task = (m_task_t) SIMIX_req_comm_get_src_buff(comm);
548 task->simdata->isused=0;
551 /* FIXME: these functions are not tracable */
554 switch (e.category) {
556 res = MSG_HOST_FAILURE;
559 res = MSG_TRANSFER_FAILURE;
572 /** \ingroup msg_gos_functions
573 * \brief This function is called by a sender and permit to wait for each communication
575 * It takes three parameters.
576 * \param comm a vector of communication
577 * \param nb_elem is the size of the comm vector
578 * \param timeout for each call of MSG_comm_wait
580 void MSG_comm_waitall(msg_comm_t * comm, int nb_elem, double timeout)
583 for (i = 0; i < nb_elem; i++) {
584 MSG_comm_wait(comm[i], timeout);
588 /** \ingroup msg_gos_functions
589 * \brief This function wait for the first completed communication
591 * It takes on parameter.
592 * \param comms a vector of communication
593 * \return the position of the completed communication from the xbt_dynar_t.
595 int MSG_comm_waitany(xbt_dynar_t comms)
598 int finished_index = -1;
600 finished_index = SIMIX_req_comm_waitany(comms);
603 switch (e.category) {
608 finished_index = e.value;
614 return finished_index;
618 * \ingroup msg_gos_functions
619 * \brief Returns the error (if any) that occured during a finished communication.
620 * \param comm a finished communication
621 * \return the status of the communication, or MSG_OK if the communication
622 * was successfully completed
624 MSG_error_t MSG_comm_get_status(msg_comm_t comm) {
627 e_smx_state_t smx_state = SIMIX_req_comm_get_state(comm);
632 result = MSG_TASK_CANCELLED;
636 case SIMIX_SRC_HOST_FAILURE:
637 case SIMIX_DST_HOST_FAILURE:
638 result = MSG_HOST_FAILURE;
641 case SIMIX_LINK_FAILURE:
642 result = MSG_TRANSFER_FAILURE;
645 case SIMIX_SRC_TIMEOUT:
646 case SIMIX_DST_TIMEOUT:
647 result = MSG_TIMEOUT;
657 m_task_t MSG_comm_get_task(msg_comm_t comm)
659 xbt_assert0(comm, "Invalid parameters");
660 return (m_task_t) SIMIX_req_comm_get_src_buff(comm);
663 /** \ingroup msg_gos_functions
664 * \brief Put a task on a channel of an host and waits for the end of the
667 * This function is used for describing the behavior of an agent. It
668 * takes three parameter.
669 * \param task a #m_task_t to send on another location. This task
670 will not be usable anymore when the function will return. There is
671 no automatic task duplication and you have to save your parameters
672 before calling this function. Tasks are unique and once it has been
673 sent to another location, you should not access it anymore. You do
674 not need to call MSG_task_destroy() but to avoid using, as an
675 effect of inattention, this task anymore, you definitely should
676 renitialize it with #MSG_TASK_UNINITIALIZED. Note that this task
677 can be transfered iff it has been correctly created with
679 * \param dest the destination of the message
680 * \param channel the channel on which the agent should put this
681 task. This value has to be >=0 and < than the maximal number of
682 channels fixed with MSG_set_channel_number().
683 * \return #MSG_FATAL if \a task is not properly initialized and
684 * #MSG_OK otherwise. Returns #MSG_HOST_FAILURE if the host on which
685 * this function was called was shut down. Returns
686 * #MSG_TRANSFER_FAILURE if the transfer could not be properly done
687 * (network failure, dest failure)
689 MSG_error_t MSG_task_put(m_task_t task, m_host_t dest, m_channel_t channel)
691 return MSG_task_put_with_timeout(task, dest, channel, -1.0);
694 /** \ingroup msg_gos_functions
695 * \brief Does exactly the same as MSG_task_put but with a bounded transmition
701 MSG_task_put_bounded(m_task_t task, m_host_t dest, m_channel_t channel,
704 task->simdata->rate = maxrate;
705 return MSG_task_put(task, dest, channel);
708 /** \ingroup msg_gos_functions \brief Put a task on a channel of an
709 * host (with a timeout on the waiting of the destination host) and
710 * waits for the end of the transmission.
712 * This function is used for describing the behavior of an agent. It
713 * takes four parameter.
714 * \param task a #m_task_t to send on another location. This task
715 will not be usable anymore when the function will return. There is
716 no automatic task duplication and you have to save your parameters
717 before calling this function. Tasks are unique and once it has been
718 sent to another location, you should not access it anymore. You do
719 not need to call MSG_task_destroy() but to avoid using, as an
720 effect of inattention, this task anymore, you definitely should
721 renitialize it with #MSG_TASK_UNINITIALIZED. Note that this task
722 can be transfered iff it has been correctly created with
724 * \param dest the destination of the message
725 * \param channel the channel on which the agent should put this
726 task. This value has to be >=0 and < than the maximal number of
727 channels fixed with MSG_set_channel_number().
728 * \param timeout the maximum time to wait for a task before giving
729 up. In such a case, #MSG_TRANSFER_FAILURE will be returned, \a task
731 * \return #MSG_FATAL if \a task is not properly initialized and
732 #MSG_OK otherwise. Returns #MSG_HOST_FAILURE if the host on which
733 this function was called was shut down. Returns
734 #MSG_TRANSFER_FAILURE if the transfer could not be properly done
735 (network failure, dest failure, timeout...)
738 MSG_task_put_with_timeout(m_task_t task, m_host_t dest,
739 m_channel_t channel, double timeout)
741 xbt_assert1((channel >= 0)
742 && (channel < msg_global->max_channel), "Invalid channel %d",
745 DEBUG1("MSG_task_put_with_timout: Trying to send a task to '%s'", dest->name);
747 MSG_mailbox_put_with_timeout(MSG_mailbox_get_by_channel
748 (dest, channel), task, timeout);
751 MSG_error_t MSG_task_send(m_task_t task, const char *alias)
753 DEBUG1("MSG_task_send: Trying to send a message on mailbox '%s'", alias);
754 return MSG_task_send_with_timeout(task, alias, -1);
759 MSG_task_send_bounded(m_task_t task, const char *alias, double maxrate)
761 task->simdata->rate = maxrate;
762 return MSG_task_send(task, alias);
767 MSG_task_send_with_timeout(m_task_t task, const char *alias,
770 return MSG_mailbox_put_with_timeout(MSG_mailbox_get_by_alias(alias),
774 int MSG_task_listen(const char *alias)
778 return !MSG_mailbox_is_empty(MSG_mailbox_get_by_alias(alias));
781 /** \ingroup msg_gos_functions
782 * \brief Test whether there is a pending communication on a channel.
784 * It takes one parameter.
785 * \param channel the channel on which the agent should be
786 listening. This value has to be >=0 and < than the maximal
787 number of channels fixed with MSG_set_channel_number().
788 * \return 1 if there is a pending communication and 0 otherwise
790 int MSG_task_Iprobe(m_channel_t channel)
792 xbt_assert1((channel >= 0)
793 && (channel < msg_global->max_channel), "Invalid channel %d",
799 !MSG_mailbox_is_empty(MSG_mailbox_get_by_channel
800 (MSG_host_self(), channel));
803 /** \ingroup msg_gos_functions
805 * \brief Return the number of tasks waiting to be received on a \a
806 channel and sent by \a host.
808 * It takes two parameters.
809 * \param channel the channel on which the agent should be
810 listening. This value has to be >=0 and < than the maximal
811 number of channels fixed with MSG_set_channel_number().
812 * \param host the host that is to be watched.
813 * \return the number of tasks waiting to be received on \a channel
816 int MSG_task_probe_from_host(int channel, m_host_t host)
818 xbt_assert1((channel >= 0)
819 && (channel < msg_global->max_channel), "Invalid channel %d",
825 MSG_mailbox_get_count_host_waiting_tasks(MSG_mailbox_get_by_channel
826 (MSG_host_self(), channel),
831 int MSG_task_listen_from_host(const char *alias, m_host_t host)
836 MSG_mailbox_get_count_host_waiting_tasks(MSG_mailbox_get_by_alias
840 /** \ingroup msg_gos_functions
841 * \brief Test whether there is a pending communication on a channel, and who sent it.
843 * It takes one parameter.
844 * \param channel the channel on which the agent should be
845 listening. This value has to be >=0 and < than the maximal
846 number of channels fixed with MSG_set_channel_number().
847 * \return -1 if there is no pending communication and the PID of the process who sent it otherwise
849 int MSG_task_probe_from(m_channel_t channel)
855 xbt_assert1((channel >= 0)
856 && (channel < msg_global->max_channel), "Invalid channel %d",
861 MSG_mailbox_get_head(MSG_mailbox_get_by_channel
862 (MSG_host_self(), channel))))
865 return MSG_process_get_PID(task->simdata->sender);
868 int MSG_task_listen_from(const char *alias)
875 (task = MSG_mailbox_get_head(MSG_mailbox_get_by_alias(alias))))
878 return MSG_process_get_PID(task->simdata->sender);