+ if (NULL == rc->peers)
+ goto cleanup_;
+ rc->shutdown = GNUNET_YES;
+ rcop = GNUNET_new (struct RunContextOperation);
+ rcop->rc = rc;
+ rcop->op = GNUNET_TESTBED_shutdown_peers (rc->c, rcop, NULL, NULL);
+ GNUNET_assert (NULL != rcop->op);
+ DEBUG ("Shutting down peers\n");
+ rc->pstart_time = GNUNET_TIME_absolute_get ();
+ insert_rcop (rc, rcop);
+ return;
+
+ cleanup_:
+ rc->state = RC_PEERS_SHUTDOWN;
+ cancel_interrupt_task (rc);
+ cleanup (rc);
+}
+
+
+/**
+ * Task run upon interrupts (SIGINT, SIGTERM) and upon scheduler shutdown.
+ *
+ * @param cls the RunContext which has to be acted upon
+ * @param tc the scheduler task context
+ */
+static void
+interrupt (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_TESTBED_RunHandle *rc = cls;
+ struct GNUNET_TESTBED_Controller *c = rc->c;
+ unsigned int size;
+
+ /* reschedule */
+ rc->interrupt_task = GNUNET_SCHEDULER_add_delayed
+ (GNUNET_TIME_UNIT_FOREVER_REL, &interrupt, rc);
+ rc_cleanup_operations (rc);
+ if ( (GNUNET_NO == rc->shutdown)
+ && (NULL != c)
+ && (0 != (size = GNUNET_CONTAINER_multihashmap32_size (c->opc_map))))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Shutdown postponed as there are "
+ "%u operations currently active\n", size);
+ c->opcq_empty_cb = &wait_op_completion;
+ c->opcq_empty_cls = rc;
+ return;
+ }
+ wait_op_completion (rc);
+}
+
+
+/**
+ * Function to return the string representation of the duration between current
+ * time and `pstart_time' in `RunContext'
+ *
+ * @param rc the RunContext
+ * @return the representation string; this is NOT reentrant
+ */
+static const char *
+prof_time (struct GNUNET_TESTBED_RunHandle *rc)
+{
+ struct GNUNET_TIME_Relative ptime;
+
+ ptime = GNUNET_TIME_absolute_get_duration (rc->pstart_time);
+ return GNUNET_STRINGS_relative_time_to_string (ptime, GNUNET_YES);
+}
+
+
+/**
+ * Task for starting peers
+ *
+ * @param cls the RunHandle
+ * @param tc the task context from scheduler
+ */
+static void
+start_peers_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_TESTBED_RunHandle *rc = cls;
+ struct RunContextOperation *rcop;
+ unsigned int peer;
+
+ DEBUG ("Starting Peers\n");
+ rc->pstart_time = GNUNET_TIME_absolute_get ();
+ for (peer = 0; peer < rc->num_peers; peer++)
+ {
+ rcop = GNUNET_new (struct RunContextOperation);
+ rcop->rc = rc;
+ rcop->op = GNUNET_TESTBED_peer_start (NULL, rc->peers[peer], NULL, NULL);
+ GNUNET_assert (NULL != rcop->op);
+ rcop->cls = rc->peers[peer];
+ insert_rcop (rc, rcop);
+ }
+ rc->peer_count = 0;
+}
+
+
+/**
+ * Functions of this signature are called when a peer has been successfully
+ * created
+ *
+ * @param cls the closure from GNUNET_TESTBED_peer_create()
+ * @param peer the handle for the created peer; NULL on any error during
+ * creation
+ * @param emsg NULL if peer is not NULL; else MAY contain the error description
+ */
+static void
+peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
+{
+ struct RunContextOperation *rcop = cls;
+ struct GNUNET_TESTBED_RunHandle *rc;
+
+ GNUNET_assert (NULL != rcop);
+ GNUNET_assert (NULL != (rc = rcop->rc));
+ remove_rcop (rc, rcop);
+ GNUNET_TESTBED_operation_done (rcop->op);
+ GNUNET_free (rcop);
+ if (NULL == peer)
+ {
+ if (NULL != emsg)
+ LOG (GNUNET_ERROR_TYPE_ERROR, "Error while creating a peer: %s\n",
+ emsg);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ rc->peers[rc->peer_count] = peer;
+ rc->peer_count++;
+ if (rc->peer_count < rc->num_peers)
+ return;
+ DEBUG ("%u peers created in %s\n", rc->num_peers, prof_time (rc));
+ rc->state = RC_PEERS_CREATED;
+ GNUNET_SCHEDULER_add_now (&start_peers_task, rc);