+/* As indicated by display_time and display_space, report GDB's elapsed time
+ and space usage from the base time and space provided in ARG, which
+ must be a pointer to a struct cmd_stat. This function is intended
+ to be called as a cleanup. */
+static void
+report_command_stats (void *arg)
+{
+ struct cmd_stats *start_stats = (struct cmd_stats *) arg;
+ int msg_type = start_stats->msg_type;
+
+ if (display_time)
+ {
+ long cmd_time = get_run_time () - start_stats->start_time;
+
+ printf_unfiltered (msg_type == 0
+ ? _("Startup time: %ld.%06ld\n")
+ : _("Command execution time: %ld.%06ld\n"),
+ cmd_time / 1000000, cmd_time % 1000000);
+ }
+
+ if (display_space)
+ {
+#ifdef HAVE_SBRK
+ char *lim = (char *) sbrk (0);
+
+ long space_now = lim - lim_at_start;
+ long space_diff = space_now - start_stats->start_space;
+
+ printf_unfiltered (msg_type == 0
+ ? _("Space used: %ld (%c%ld during startup)\n")
+ : _("Space used: %ld (%c%ld for this command)\n"),
+ space_now,
+ (space_diff >= 0 ? '+' : '-'),
+ space_diff);
+#endif
+ }
+}
+
+/* Create a cleanup that reports time and space used since its
+ creation. Precise messages depend on MSG_TYPE:
+ 0: Initial time/space
+ 1: Individual command time/space. */
+struct cleanup *
+make_command_stats_cleanup (int msg_type)
+{
+ struct cmd_stats *new_stat = XMALLOC (struct cmd_stats);
+
+#ifdef HAVE_SBRK
+ char *lim = (char *) sbrk (0);
+ new_stat->start_space = lim - lim_at_start;
+#endif
+
+ new_stat->msg_type = msg_type;
+ new_stat->start_time = get_run_time ();
+
+ return make_cleanup_dtor (report_command_stats, new_stat, xfree);
+}
+
+/* Continuations are implemented as cleanups internally. Inherit from
+ cleanups. */
+struct continuation
+{
+ struct cleanup base;
+};
+
+/* Add a continuation to the continuation list of THREAD. The new
+ continuation will be added at the front. */
+void
+add_continuation (struct thread_info *thread,
+ void (*continuation_hook) (void *), void *args,
+ void (*continuation_free_args) (void *))
+{
+ struct cleanup *as_cleanup = &thread->continuations->base;
+ make_cleanup_ftype *continuation_hook_fn = continuation_hook;
+
+ make_my_cleanup2 (&as_cleanup,
+ continuation_hook_fn,
+ args,
+ continuation_free_args);
+
+ thread->continuations = (struct continuation *) as_cleanup;
+}
+
+/* Add a continuation to the continuation list of INFERIOR. The new
+ continuation will be added at the front. */
+
+void
+add_inferior_continuation (void (*continuation_hook) (void *), void *args,
+ void (*continuation_free_args) (void *))
+{
+ struct inferior *inf = current_inferior ();
+ struct cleanup *as_cleanup = &inf->continuations->base;
+ make_cleanup_ftype *continuation_hook_fn = continuation_hook;
+
+ make_my_cleanup2 (&as_cleanup,
+ continuation_hook_fn,
+ args,
+ continuation_free_args);
+
+ inf->continuations = (struct continuation *) as_cleanup;
+}
+
+/* Do all continuations of the current inferior. */
+