- msg_host_t old_pm = (msg_host_t) simcall_vm_get_pm(vm);
-
- if(MSG_host_is_off(old_pm))
- THROWF(vm_error, 0, "SRC host(%s) seems off, cannot start a migration", sg_host_get_name(old_pm));
-
- if(MSG_host_is_off(new_pm))
- THROWF(vm_error, 0, "DST host(%s) seems off, cannot start a migration", sg_host_get_name(new_pm));
-
- if (!MSG_vm_is_running(vm))
- THROWF(vm_error, 0, "VM(%s) is not running", sg_host_get_name(vm));
-
- if (MSG_vm_is_migrating(vm))
- THROWF(vm_error, 0, "VM(%s) is already migrating", sg_host_get_name(vm));
-
- msg_host_priv_t priv = sg_host_msg(vm);
- priv->is_migrating = 1;
-
- {
-
- int ret = do_migration(vm, old_pm, new_pm);
- if (ret == -1){
- priv->is_migrating = 0;
- THROWF(host_error, 0, "SRC host failed during migration");
- }
- else if(ret == -2){
- priv->is_migrating = 0;
- THROWF(host_error, 0, "DST host failed during migration");
- }
+ msg_host_t src_pm = vm->pimpl_vm_->getPm();
+
+ if (src_pm->isOff())
+ THROWF(vm_error, 0, "Cannot migrate VM '%s' from host '%s', which is offline.", vm->getCname(), src_pm->getCname());
+ if (dst_pm->isOff())
+ THROWF(vm_error, 0, "Cannot migrate VM '%s' to host '%s', which is offline.", vm->getCname(), dst_pm->getCname());
+ if (not MSG_vm_is_running(vm))
+ THROWF(vm_error, 0, "Cannot migrate VM '%s' that is not running yet.", vm->getCname());
+ if (vm->isMigrating())
+ THROWF(vm_error, 0, "Cannot migrate VM '%s' that is already migrating.", vm->getCname());
+
+ vm->pimpl_vm_->isMigrating = true;
+
+ struct migration_session *ms = xbt_new(struct migration_session, 1);
+ ms->vm = vm;
+ ms->src_pm = src_pm;
+ ms->dst_pm = dst_pm;
+
+ /* We have two mailboxes. mbox is used to transfer migration data between source and destination PMs. mbox_ctl is used
+ * to detect the completion of a migration. The names of these mailboxes must not conflict with others. */
+ ms->mbox_ctl = bprintf("__mbox_mig_ctl:%s(%s-%s)", vm->getCname(), src_pm->getCname(), dst_pm->getCname());
+ ms->mbox = bprintf("__mbox_mig_src_dst:%s(%s-%s)", vm->getCname(), src_pm->getCname(), dst_pm->getCname());
+
+ char *pr_rx_name = get_mig_process_rx_name(vm, src_pm, dst_pm);
+ char *pr_tx_name = get_mig_process_tx_name(vm, src_pm, dst_pm);
+
+ char** argv = xbt_new(char*, 2);
+ argv[0] = pr_rx_name;
+ argv[1] = nullptr;
+ MSG_process_create_with_arguments(pr_rx_name, migration_rx_fun, ms, dst_pm, 1, argv);
+
+ argv = xbt_new(char*, 2);
+ argv[0] = pr_tx_name;
+ argv[1] = nullptr;
+ MSG_process_create_with_arguments(pr_tx_name, migration_tx_fun, ms, src_pm, 1, argv);
+
+ /* wait until the migration have finished or on error has occurred */
+ XBT_DEBUG("wait for reception of the final ACK (i.e. migration has been correctly performed");
+ msg_task_t task = nullptr;
+ msg_error_t ret = MSG_task_receive(&task, ms->mbox_ctl);
+
+ vm->pimpl_vm_->isMigrating = false;
+
+ xbt_free(ms->mbox_ctl);
+ xbt_free(ms->mbox);
+ xbt_free(ms);
+
+ if (ret == MSG_HOST_FAILURE) {
+ // Note that since the communication failed, the owner did not change and the task should be destroyed on the
+ // other side. Hence, just throw the execption
+ XBT_ERROR("SRC crashes, throw an exception (m-control)");
+ // MSG_process_kill(tx_process); // Adrien, I made a merge on Nov 28th 2014, I'm not sure whether this line is
+ // required or not
+ THROWF(host_error, 0, "Source host '%s' failed during the migration of VM '%s'.", src_pm->getCname(),
+ vm->getCname());
+ } else if ((ret == MSG_TRANSFER_FAILURE) || (ret == MSG_TIMEOUT)) {
+ // MSG_TIMEOUT here means that MSG_host_is_avail() returned false.
+ XBT_ERROR("DST crashes, throw an exception (m-control)");
+ THROWF(host_error, 0, "Destination host '%s' failed during the migration of VM '%s'.", dst_pm->getCname(),
+ vm->getCname());