This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH v2] gdb: Use C++11 std::chrono


On 11/17/2016 10:15 PM, Simon Marchi wrote:
> On 2016-11-17 12:15, Pedro Alves wrote:
>> This patch fixes a few problems with GDB's time handling.
>> [...]
> 
> Indeed, it makes the code very nice and readable.  My only opinion about
> std::chrono so far was that it was so much more painful to do
> std::this_thread::sleep_for(std::chrono::seconds(2)) than sleep(2). :)

:-)

> 
>> +/* Count the total amount of time spent executing in user mode.  */
>>
>> +user_cpu_time_clock::time_point
>> +user_cpu_time_clock::now () noexcept
>> +{
>> +  return time_point (microseconds (get_run_time ()));
> 
> Looking at get_run_time() in libiberty, it seems like it returns user
> time + system time.  Doesn't it contradict the naming of this clock and
> the comment of this method?

Wow, talk about missing the obvious.  I've fixed this now.
I added yet another clock (system_run_time, and renamed the files
accordingly) that has a "now ()" overload that returns both user and kernel
time, as separate time points, and deleted the "now()" method of the user
and kernel clocks, to force people to use the system_run_time
one (since the new clock can get the separate times with a single
system call).  I kept the user and kernel clocks in order to keep
the distinct time point types.

> 
>> -      /* If gettimeofday doesn't exist, and as a portability solution
>> it has
>> -     been replaced with, e.g., time, then it doesn't make sense to print
>> -     the microseconds field.  Is there a way to check for that?  */
>> -      fprintf (stderr, "%ld:%06ld ", (long) tm.tv_sec, (long)
>> tm.tv_usec);
>> +      fprintf (stderr, "%ld:%06ld ", s.count (), us.count ());
> 
> Unrelated to your change, but I find it weird to format the time as
> "seconds:useconds".  I wouldn't object if you sneakily changed it to
> "seconds.useconds". :)

I don't mind either way.  I changed it. 

> 
>> @@ -2390,8 +2383,8 @@ mi_load_progress (const char *section_name,
>>            unsigned long total_sent,
>>            unsigned long grand_total)
>>  {
>> -  struct timeval time_now, delta, update_threshold;
>> -  static struct timeval last_update;
>> +  using namespace std::chrono;
>> +  static steady_clock::time_point last_update;
>>    static char *previous_sect_name = NULL;
>>    int new_section;
>>    struct ui_out *saved_uiout;
>> @@ -2416,18 +2409,9 @@ mi_load_progress (const char *section_name,
>>
>>    uiout = current_uiout;
>>
>> -  update_threshold.tv_sec = 0;
>> -  update_threshold.tv_usec = 500000;
>> -  gettimeofday (&time_now, NULL);
>> -
>> -  delta.tv_usec = time_now.tv_usec - last_update.tv_usec;
>> -  delta.tv_sec = time_now.tv_sec - last_update.tv_sec;
>> -
>> -  if (delta.tv_usec < 0)
>> -    {
>> -      delta.tv_sec -= 1;
>> -      delta.tv_usec += 1000000L;
>> -    }
>> +  microseconds update_threshold (500000);
>> +  steady_clock::time_point time_now = steady_clock::now ();
>> +  steady_clock::duration delta = time_now - last_update;
> 
> Can this be simplified to avoid having the delta variable?  Since we can
> easily compare two time_points, we can probably make it look like:
> 
>   if (steady_clock::now () >= next_update)
>     {
>       next_update = steady_clock::now() + update_threshold;

Reading "now()" twice looks like an anti-pattern to me, since
that can return two different times.

>       ...
>     }
> 
> or
> 
>   if (steady_clock::now () >= (last_update + update_threshold))
>     {
>       last_update = steady_clock::now ();
>       ...
>     }
> 
> Also, wouldn't "update_period" or "update_rate" be more precise than
> "update_threshold"?

I was just using the old variable names.  I didn't even really
try to understand the code.  :-)

How about just getting rid of the variable altogether?
I did that in this version.  I realized that I might as well write
it in terms of 'milliseconds (500)' instead of 'microseconds (500000)'
too.

> 
>>  static void
>>  timestamp (struct mi_timestamp *tv)
>>  {
>> -  gettimeofday (&tv->wallclock, NULL);
>> -#ifdef HAVE_GETRUSAGE
>> -  getrusage (RUSAGE_SELF, &rusage);
>> -  tv->utime.tv_sec = rusage.ru_utime.tv_sec;
>> -  tv->utime.tv_usec = rusage.ru_utime.tv_usec;
>> -  tv->stime.tv_sec = rusage.ru_stime.tv_sec;
>> -  tv->stime.tv_usec = rusage.ru_stime.tv_usec;
>> -#else
>> -  {
>> -    long usec = get_run_time ();
>> -
>> -    tv->utime.tv_sec = usec/1000000L;
>> -    tv->utime.tv_usec = usec - 1000000L*tv->utime.tv_sec;
>> -    tv->stime.tv_sec = 0;
>> -    tv->stime.tv_usec = 0;
>> -  }
>> -#endif
>> +  using namespace std::chrono;
> 
> It's not written in the coding style guide, but I think it would be nice
> to have a newline between the "using" declaration and the following
> lines, like we do with variable declarations.

I don't mind.  Done.

> 
>> -/* Report how fast the transfer went.  */
>> +/* Report on STREAM the performance of a memory transfer operation,
>> +   such as 'load'.  DATA_COUNT is the number of bytes transferred.
>> +   WRITE_COUNT is the number of separate write operations, or 0, if
>> +   that information is not available.  TIME is the range of time in
>> +   which the operation lasted.  */
>>
>> -void
>> +static void
>>  print_transfer_performance (struct ui_file *stream,
>>                  unsigned long data_count,
>>                  unsigned long write_count,
>> -                const struct timeval *start_time,
>> -                const struct timeval *end_time)
>> +                const time_range &time)
> 
> Is there a reason you couldn't use a std::chrono::duration instead of a
> time_range here?  The function doesn't seem to care about the particular
> time_points, only their difference.

No real reason.  I've changed it.

> 
>> -      timestamp = xstrprintf ("%ld:%ld %s%s",
>> -                  (long) tm.tv_sec, (long) tm.tv_usec,
>> -                  linebuffer,
>> -                  need_nl ? "\n": "");
>> -      make_cleanup (xfree, timestamp);
>> -      fputs_unfiltered (timestamp, stream);
>> +      std::string timestamp = string_printf ("%ld:%ld %s%s",
> 
> Same comment about secs:usecs vs secs.usecs.

Changed here too.

Here's the updated version.  WDYT?

>From f028dd3033f8174a851481e23d31e2b089cd1873 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Wed, 23 Nov 2016 00:47:40 +0000
Subject: [PATCH v2] gdb: Use C++11 std::chrono

This patch fixes a few problems with GDB's time handling.

#1 - It avoids problems with gnulib's C++ namespace support

On MinGW, the struct timeval that should be passed to gnulib's
gettimeofday replacement is incompatible with libiberty's
timeval_sub/timeval_add.  That's because gnulib also replaces "struct
timeval" with its own definition, while libiberty expects the
system's.

E.g., in code like this:

  gettimeofday (&prompt_ended, NULL);
  timeval_sub (&prompt_delta, &prompt_ended, &prompt_started);
  timeval_add (&prompt_for_continue_wait_time,
               &prompt_for_continue_wait_time, &prompt_delta);

That's currently handled in gdb by not using gnulib's gettimeofday at
all (see common/gdb_sys_time.h), but that #undef hack won't work with
if/when we enable gnulib's C++ namespace support, because that mode
adds compile time warnings for uses of ::gettimeofday, which are hard
errors with -Werror.

#2 - But there's an elephant in the room: gettimeofday is not monotonic...

We're using it to:

  a) check how long functions take, for performance analysis
  b) compute when in the future to fire events in the event-loop
  c) print debug timestamps

But that's exactly what gettimeofday is NOT meant for.  Straight from
the man page:

~~~
       The time returned by gettimeofday() is affected by
       discontinuous jumps in the system time (e.g., if the system
       administrator manually changes the system time).  If you need a
       monotonically increasing clock, see clock_gettime(2).
~~~

std::chrono (part of the C++11 standard library) has a monotonic clock
exactly for such purposes (std::chrono::steady_clock).  This commit
switches to use that instead of gettimeofday, fixing all the issues
mentioned above.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* Makefile.in (SFILES): Add common/run-time-clock.c.
	(HFILES_NO_SRCDIR): Add common/run-time-clock.h.
	(COMMON_OBS): Add run-time-clock.o.
	* common/run-time-clock.c, common/run-time-clock.h: New files.
	* defs.h (struct timeval, print_transfer_performance): Delete
	declarations.
	* event-loop.c (struct gdb_timer) <when>: Now a
	std::chrono::steady_clock::time_point.
	(create_timer): use std::chrono::steady_clock instead of
	gettimeofday.  Use new instead of malloc.
	(delete_timer): Use delete instead of xfree.
	(duration_cast_timeval): New.
	(update_wait_timeout): Use std::chrono::steady_clock instead of
	gettimeofday.

gdb/gdbserver/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* debug.c: Include <chrono> instead of "gdb_sys_time.h".
	(debug_vprintf): Use std::chrono::steady_clock instead of
	gettimeofday.  Use '.' instead of ':'.
	* tracepoint.c: Include <chrono> instead of "gdb_sys_time.h".
	(get_timestamp): Use std::chrono::steady_clock instead of
	gettimeofday.
	* maint.c: Include <chrono> instead of "gdb_sys_time.h", <time.h>
	and "timeval-utils.h".
	(scoped_command_stats::~scoped_command_stats)
	(scoped_command_stats::scoped_command_stats): Use
	std::chrono::steady_clock instead of gettimeofday.  Use
	user_cpu_time_clock instead of get_run_time.
	* maint.h: Include "run-time-clock.h" and <chrono>.
	(scoped_command_stats): <m_start_cpu_time>: Now a
	user_cpu_time_clock::time_point.
	<m_start_wall_time>: Now a std::chrono::steady_clock::time_point.
	* mi/mi-main.c: Include "run-time-clock.h" and <chrono> instead of
	"gdb_sys_time.h" and <sys/resource.h>.
	(rusage): Delete.
	(mi_execute_command): Use new instead of XNEW.
	(mi_load_progress): Use std::chrono::steady_clock instead of
	gettimeofday.
	(timestamp): Rewrite in terms of std::chrono::steady_clock,
	user_cpu_time_clock and system_cpu_time_clock.
	(timeval_diff): Delete.
	(print_diff): Adjust to use std::chrono::steady_clock,
	user_cpu_time_clock and system_cpu_time_clock.
	* mi/mi-parse.h: Include "run-time-clock.h" and <chrono> instead
	of "gdb_sys_time.h".
	(struct mi_timestamp): Change fields types to
	std::chrono::steady_clock::time_point, user_cpu_time_clock::time
	and system_cpu_time_clock::time_point, instead of struct timeval.
	* symfile.c: Include <chrono> instead of <time.h> and
	"gdb_sys_time.h".
	(struct time_range): New.
	(generic_load): Use std::chrono::steady_clock instead of
	gettimeofday.
	(print_transfer_performance): Replace timeval parameters with a
	std::chrono::steady_clock::duration parameter.  Adjust.
	* utils.c: Include <chrono> instead of "timeval-utils.h",
	"gdb_sys_time.h", and <time.h>.
	(prompt_for_continue_wait_time): Now a
	std::chrono::steady_clock::duration.
	(defaulted_query, prompt_for_continue): Use
	std::chrono::steady_clock instead of
	gettimeofday/timeval_sub/timeval_add.
	(reset_prompt_for_continue_wait_time): Use
	std::chrono::steady_clock::duration instead of struct timeval.
	(get_prompt_for_continue_wait_time): Return a
	std::chrono::steady_clock::duration instead of struct timeval.
	(vfprintf_unfiltered): Use std::chrono::steady_clock instead of
	gettimeofday.  Use std::string.  Use '.' instead of ':'.
	* utils.h: Include <chrono>.
	(get_prompt_for_continue_wait_time): Return a
	std::chrono::steady_clock::duration instead of struct timeval.
---
 gdb/Makefile.in             |  5 ++-
 gdb/common/run-time-clock.c | 58 ++++++++++++++++++++++++++++
 gdb/common/run-time-clock.h | 75 ++++++++++++++++++++++++++++++++++++
 gdb/defs.h                  | 14 -------
 gdb/event-loop.c            | 94 +++++++++++++++++++++------------------------
 gdb/gdbserver/debug.c       | 13 +++----
 gdb/gdbserver/tracepoint.c  | 10 ++---
 gdb/maint.c                 | 31 +++++++--------
 gdb/maint.h                 |  7 +++-
 gdb/mi/mi-main.c            | 73 +++++++++--------------------------
 gdb/mi/mi-parse.h           | 12 +++---
 gdb/symfile.c               | 39 +++++++++++--------
 gdb/utils.c                 | 58 ++++++++++++----------------
 gdb/utils.h                 |  3 +-
 14 files changed, 282 insertions(+), 210 deletions(-)
 create mode 100644 gdb/common/run-time-clock.c
 create mode 100644 gdb/common/run-time-clock.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 3ea47a7..67db97d 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -895,6 +895,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	common/errors.c common/common-debug.c common/common-exceptions.c \
 	common/btrace-common.c common/fileio.c common/common-regcache.c \
 	common/signals-state-save-restore.c common/new-op.c \
+	common/run-time-clock.c \
 	$(SUBDIR_GCC_COMPILE_SRCS)
 
 LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@@ -988,7 +989,7 @@ common/common-regcache.h fbsd-tdep.h nat/linux-personality.h \
 common/fileio.h nat/x86-linux.h nat/x86-linux-dregs.h nat/amd64-linux-siginfo.h\
 nat/linux-namespaces.h arch/arm.h common/gdb_sys_time.h arch/aarch64-insn.h \
 tid-parse.h ser-event.h \
-common/signals-state-save-restore.h
+common/signals-state-save-restore.h common/run-time-clock.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -1088,7 +1089,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	format.o registry.o btrace.o record-btrace.o waitstatus.o \
 	print-utils.o rsp-low.o errors.o common-debug.o debug.o \
 	common-exceptions.o btrace-common.o fileio.o \
-	common-regcache.o new-op.o \
+	common-regcache.o new-op.o run-time-clock.o \
 	$(SUBDIR_GCC_COMPILE_OBS)
 
 TSOBS = inflow.o
diff --git a/gdb/common/run-time-clock.c b/gdb/common/run-time-clock.c
new file mode 100644
index 0000000..f9dc7a0
--- /dev/null
+++ b/gdb/common/run-time-clock.c
@@ -0,0 +1,58 @@
+/* User/system CPU time clocks that follow the std::chrono interface.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "common-defs.h"
+#include "run-time-clock.h"
+#if defined HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+using namespace std::chrono;
+
+run_time_clock::time_point
+run_time_clock::now () noexcept
+{
+  return time_point (microseconds (get_run_time ()));
+}
+
+#ifdef HAVE_GETRUSAGE
+static std::chrono::microseconds
+timeval_to_microseconds (struct timeval *tv)
+{
+  return (seconds (tv->tv_sec) + microseconds (tv->tv_usec));
+}
+#endif
+
+void
+run_time_clock::now (user_cpu_time_clock::time_point &user,
+		     system_cpu_time_clock::time_point &system) noexcept
+{
+#ifdef HAVE_GETRUSAGE
+  struct rusage rusage;
+
+  getrusage (RUSAGE_SELF, &rusage);
+
+  microseconds utime = timeval_to_microseconds (&rusage.ru_utime);
+  microseconds stime = timeval_to_microseconds (&rusage.ru_stime);
+  user = user_cpu_time_clock::time_point (utime);
+  system = system_cpu_time_clock::time_point (stime);
+#else
+  user = user_cpu_time_clock::time_point (microseconds (get_run_time ()));
+  system = system_cpu_time_clock::time_point (microseconds::zero ());
+#endif
+}
diff --git a/gdb/common/run-time-clock.h b/gdb/common/run-time-clock.h
new file mode 100644
index 0000000..ee531bb
--- /dev/null
+++ b/gdb/common/run-time-clock.h
@@ -0,0 +1,75 @@
+/* User/system CPU time clocks that follow the std::chrono interface.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef RUN_TIME_CLOCK_H
+#define RUN_TIME_CLOCK_H
+
+#include <chrono>
+
+/* Count the total amount of time spent executing in user mode.  */
+
+struct user_cpu_time_clock
+{
+  using duration = std::chrono::microseconds;
+  using rep = duration::rep;
+  using period = duration::period;
+  using time_point = std::chrono::time_point<user_cpu_time_clock>;
+
+  static constexpr bool is_steady = true;
+
+  /* Use run_time_clock::now instead.  */
+  static time_point now () noexcept = delete;
+};
+
+/* Count the total amount of time spent executing in kernel mode.  */
+
+struct system_cpu_time_clock
+{
+  using duration = std::chrono::microseconds;
+  using rep = duration::rep;
+  using period = duration::period;
+  using time_point = std::chrono::time_point<system_cpu_time_clock>;
+
+  static constexpr bool is_steady = true;
+
+  /* Use run_time_clock::now instead.  */
+  static time_point now () noexcept = delete;
+};
+
+/* Count the total amount of time spent executing in userspace+kernel
+   mode.  */
+
+struct run_time_clock
+{
+  using duration = std::chrono::microseconds;
+  using rep = duration::rep;
+  using period = duration::period;
+  using time_point = std::chrono::time_point<run_time_clock>;
+
+  static constexpr bool is_steady = true;
+
+  static time_point now () noexcept;
+
+  /* Return the user/system time as separate time points, if
+     supported.  If not supported, then the combined user+kernel time
+     is returned in USER and SYSTEM is set to zero.  */
+  static void now (user_cpu_time_clock::time_point &user,
+		   system_cpu_time_clock::time_point &system) noexcept;
+};
+
+#endif
diff --git a/gdb/defs.h b/gdb/defs.h
index 6d0d2dd..3d21f62 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -303,20 +303,6 @@ extern void symbol_file_command (char *, int);
 /* * Remote targets may wish to use this as their load function.  */
 extern void generic_load (const char *name, int from_tty);
 
-/* * Report on STREAM the performance of memory transfer operation,
-   such as 'load'.
-   @param DATA_COUNT is the number of bytes transferred.
-   @param WRITE_COUNT is the number of separate write operations, or 0,
-   if that information is not available.
-   @param START_TIME is the time at which an operation was started.
-   @param END_TIME is the time at which an operation ended.  */
-struct timeval;
-extern void print_transfer_performance (struct ui_file *stream,
-					unsigned long data_count,
-					unsigned long write_count,
-					const struct timeval *start_time,
-					const struct timeval *end_time);
-
 /* From top.c */
 
 typedef void initialize_file_ftype (void);
diff --git a/gdb/event-loop.c b/gdb/event-loop.c
index f94a6fa..9e8cf66 100644
--- a/gdb/event-loop.c
+++ b/gdb/event-loop.c
@@ -212,7 +212,7 @@ gdb_notifier;
    first occasion after WHEN.  */
 struct gdb_timer
   {
-    struct timeval when;
+    std::chrono::steady_clock::time_point when;
     int timer_id;
     struct gdb_timer *next;
     timer_handler_func *proc;	    /* Function to call to do the work.  */
@@ -1097,33 +1097,22 @@ delete_async_event_handler (async_event_handler **async_handler_ptr)
   *async_handler_ptr = NULL;
 }
 
-/* Create a timer that will expire in MILLISECONDS from now.  When the
-   timer is ready, PROC will be executed.  At creation, the timer is
-   aded to the timers queue.  This queue is kept sorted in order of
-   increasing timers.  Return a handle to the timer struct.  */
+/* Create a timer that will expire in MS milliseconds from now.  When
+   the timer is ready, PROC will be executed.  At creation, the timer
+   is added to the timers queue.  This queue is kept sorted in order
+   of increasing timers.  Return a handle to the timer struct.  */
+
 int
-create_timer (int milliseconds, timer_handler_func * proc, 
+create_timer (int ms, timer_handler_func *proc,
 	      gdb_client_data client_data)
 {
+  using namespace std::chrono;
   struct gdb_timer *timer_ptr, *timer_index, *prev_timer;
-  struct timeval time_now, delta;
-
-  /* Compute seconds.  */
-  delta.tv_sec = milliseconds / 1000;
-  /* Compute microseconds.  */
-  delta.tv_usec = (milliseconds % 1000) * 1000;
 
-  gettimeofday (&time_now, NULL);
+  steady_clock::time_point time_now = steady_clock::now ();
 
-  timer_ptr = XNEW (struct gdb_timer);
-  timer_ptr->when.tv_sec = time_now.tv_sec + delta.tv_sec;
-  timer_ptr->when.tv_usec = time_now.tv_usec + delta.tv_usec;
-  /* Carry?  */
-  if (timer_ptr->when.tv_usec >= 1000000)
-    {
-      timer_ptr->when.tv_sec += 1;
-      timer_ptr->when.tv_usec -= 1000000;
-    }
+  timer_ptr = new gdb_timer ();
+  timer_ptr->when = time_now + milliseconds (ms);
   timer_ptr->proc = proc;
   timer_ptr->client_data = client_data;
   timer_list.num_timers++;
@@ -1136,11 +1125,7 @@ create_timer (int milliseconds, timer_handler_func * proc,
        timer_index != NULL;
        timer_index = timer_index->next)
     {
-      /* If the seconds field is greater or if it is the same, but the
-         microsecond field is greater.  */
-      if ((timer_index->when.tv_sec > timer_ptr->when.tv_sec)
-	  || ((timer_index->when.tv_sec == timer_ptr->when.tv_sec)
-	      && (timer_index->when.tv_usec > timer_ptr->when.tv_usec)))
+      if (timer_index->when > timer_ptr->when)
 	break;
     }
 
@@ -1194,47 +1179,56 @@ delete_timer (int id)
 	;
       prev_timer->next = timer_ptr->next;
     }
-  xfree (timer_ptr);
+  delete timer_ptr;
 
   gdb_notifier.timeout_valid = 0;
 }
 
+/* Convert a std::chrono duration to a struct timeval.  */
+
+template<typename Duration>
+static struct timeval
+duration_cast_timeval (const Duration &d)
+{
+  using namespace std::chrono;
+  seconds sec = duration_cast<seconds> (d);
+  microseconds msec = duration_cast<microseconds> (d - sec);
+
+  struct timeval tv;
+  tv.tv_sec = sec.count ();
+  tv.tv_usec = msec.count ();
+  return tv;
+}
+
 /* Update the timeout for the select() or poll().  Returns true if the
    timer has already expired, false otherwise.  */
 
 static int
 update_wait_timeout (void)
 {
-  struct timeval time_now, delta;
-
   if (timer_list.first_timer != NULL)
     {
-      gettimeofday (&time_now, NULL);
-      delta.tv_sec = timer_list.first_timer->when.tv_sec - time_now.tv_sec;
-      delta.tv_usec = timer_list.first_timer->when.tv_usec - time_now.tv_usec;
-      /* Borrow?  */
-      if (delta.tv_usec < 0)
-	{
-	  delta.tv_sec -= 1;
-	  delta.tv_usec += 1000000;
-	}
+      using namespace std::chrono;
+      steady_clock::time_point time_now = steady_clock::now ();
+      struct timeval timeout;
 
-      /* Cannot simply test if delta.tv_sec is negative because time_t
-         might be unsigned.  */
-      if (timer_list.first_timer->when.tv_sec < time_now.tv_sec
-	  || (timer_list.first_timer->when.tv_sec == time_now.tv_sec
-	      && timer_list.first_timer->when.tv_usec < time_now.tv_usec))
+      if (timer_list.first_timer->when < time_now)
 	{
 	  /* It expired already.  */
-	  delta.tv_sec = 0;
-	  delta.tv_usec = 0;
+	  timeout.tv_sec = 0;
+	  timeout.tv_usec = 0;
+	}
+      else
+	{
+	  steady_clock::duration d = timer_list.first_timer->when - time_now;
+	  timeout = duration_cast_timeval (d);
 	}
 
       /* Update the timeout for select/ poll.  */
       if (use_poll)
 	{
 #ifdef HAVE_POLL
-	  gdb_notifier.poll_timeout = delta.tv_sec * 1000;
+	  gdb_notifier.poll_timeout = timeout.tv_sec * 1000;
 #else
 	  internal_error (__FILE__, __LINE__,
 			  _("use_poll without HAVE_POLL"));
@@ -1242,12 +1236,12 @@ update_wait_timeout (void)
 	}
       else
 	{
-	  gdb_notifier.select_timeout.tv_sec = delta.tv_sec;
-	  gdb_notifier.select_timeout.tv_usec = delta.tv_usec;
+	  gdb_notifier.select_timeout.tv_sec = timeout.tv_sec;
+	  gdb_notifier.select_timeout.tv_usec = timeout.tv_usec;
 	}
       gdb_notifier.timeout_valid = 1;
 
-      if (delta.tv_sec == 0 && delta.tv_usec == 0)
+      if (timer_list.first_timer->when < time_now)
 	return 1;
     }
   else
diff --git a/gdb/gdbserver/debug.c b/gdb/gdbserver/debug.c
index 54f2665..63fbe82 100644
--- a/gdb/gdbserver/debug.c
+++ b/gdb/gdbserver/debug.c
@@ -17,7 +17,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
-#include "gdb_sys_time.h"
+#include <chrono>
 
 /* Enable miscellaneous debugging output.  The name is historical - it
    was originally used to debug LinuxThreads support.  */
@@ -41,14 +41,13 @@ debug_vprintf (const char *format, va_list ap)
 
   if (debug_timestamp && new_line)
     {
-      struct timeval tm;
+      using namespace std::chrono;
 
-      gettimeofday (&tm, NULL);
+      steady_clock::time_point now = steady_clock::now ();
+      seconds s = duration_cast<seconds> (now.time_since_epoch ());
+      microseconds us = duration_cast<microseconds> (now.time_since_epoch ()) - s;
 
-      /* If gettimeofday doesn't exist, and as a portability solution it has
-	 been replaced with, e.g., time, then it doesn't make sense to print
-	 the microseconds field.  Is there a way to check for that?  */
-      fprintf (stderr, "%ld:%06ld ", (long) tm.tv_sec, (long) tm.tv_usec);
+      fprintf (stderr, "%ld.%06ld ", (long) s.count (), (long) us.count ());
     }
 #endif
 
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index 7700ad1..1444a0d 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -25,7 +25,7 @@
 #include <ctype.h>
 #include <fcntl.h>
 #include <unistd.h>
-#include "gdb_sys_time.h"
+#include <chrono>
 #include <inttypes.h>
 #include "ax.h"
 #include "tdesc.h"
@@ -7410,12 +7410,10 @@ getauxval (unsigned long type)
 static LONGEST
 get_timestamp (void)
 {
-   struct timeval tv;
+  using namespace std::chrono;
 
-   if (gettimeofday (&tv, 0) != 0)
-     return -1;
-   else
-     return (LONGEST) tv.tv_sec * 1000000 + tv.tv_usec;
+  steady_clock::time_point now = steady_clock::now ();
+  return duration_cast<microseconds> (now.time_since_epoch ()).count ();
 }
 
 void
diff --git a/gdb/maint.c b/gdb/maint.c
index 738571c..b43dbf9 100644
--- a/gdb/maint.c
+++ b/gdb/maint.c
@@ -24,8 +24,6 @@
 #include "arch-utils.h"
 #include <ctype.h>
 #include <signal.h>
-#include "gdb_sys_time.h"
-#include <time.h>
 #include "command.h"
 #include "gdbcmd.h"
 #include "symtab.h"
@@ -39,7 +37,6 @@
 #include "objfiles.h"
 #include "value.h"
 #include "top.h"
-#include "timeval-utils.h"
 #include "maint.h"
 #include "selftest.h"
 
@@ -822,23 +819,21 @@ scoped_command_stats::~scoped_command_stats ()
 
   if (m_time_enabled && per_command_time)
     {
-      long cmd_time = get_run_time () - m_start_cpu_time;
-      struct timeval now_wall_time, delta_wall_time, wait_time;
+      using namespace std::chrono;
 
-      gettimeofday (&now_wall_time, NULL);
-      timeval_sub (&delta_wall_time,
-		   &now_wall_time, &m_start_wall_time);
+      run_time_clock::duration cmd_time
+	= run_time_clock::now () - m_start_cpu_time;
 
+      steady_clock::duration wall_time
+	= steady_clock::now () - m_start_wall_time;
       /* Subtract time spend in prompt_for_continue from walltime.  */
-      wait_time = get_prompt_for_continue_wait_time ();
-      timeval_sub (&delta_wall_time, &delta_wall_time, &wait_time);
+      wall_time -= get_prompt_for_continue_wait_time ();
 
       printf_unfiltered (!m_msg_type
-			 ? _("Startup time: %ld.%06ld (cpu), %ld.%06ld (wall)\n")
-			 : _("Command execution time: %ld.%06ld (cpu), %ld.%06ld (wall)\n"),
-			 cmd_time / 1000000, cmd_time % 1000000,
-			 (long) delta_wall_time.tv_sec,
-			 (long) delta_wall_time.tv_usec);
+			 ? _("Startup time: %.6f (cpu), %.6f (wall)\n")
+			 : _("Command execution time: %.6f (cpu), %.6f (wall)\n"),
+			 duration<double> (cmd_time).count (),
+			 duration<double> (wall_time).count ());
     }
 
   if (m_space_enabled && per_command_space)
@@ -892,8 +887,10 @@ scoped_command_stats::scoped_command_stats (bool msg_type)
 
   if (msg_type == 0 || per_command_time)
     {
-      m_start_cpu_time = get_run_time ();
-      gettimeofday (&m_start_wall_time, NULL);
+      using namespace std::chrono;
+
+      m_start_cpu_time = run_time_clock::now ();
+      m_start_wall_time = steady_clock::now ();
       m_time_enabled = 1;
     }
   else
diff --git a/gdb/maint.h b/gdb/maint.h
index 8d03800..2af405d 100644
--- a/gdb/maint.h
+++ b/gdb/maint.h
@@ -19,6 +19,9 @@
 #ifndef MAINT_H
 #define MAINT_H
 
+#include "run-time-clock.h"
+#include <chrono>
+
 extern void set_per_command_time (int);
 
 extern void set_per_command_space (int);
@@ -48,8 +51,8 @@ class scoped_command_stats
   int m_time_enabled : 1;
   int m_space_enabled : 1;
   int m_symtab_enabled : 1;
-  long m_start_cpu_time;
-  struct timeval m_start_wall_time;
+  run_time_clock::time_point m_start_cpu_time;
+  std::chrono::steady_clock::time_point m_start_wall_time;
   long m_start_space;
   /* Total number of symtabs (over all objfiles).  */
   int m_start_nr_symtabs;
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 984a415..4d276c8 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -56,15 +56,8 @@
 #include "observer.h"
 
 #include <ctype.h>
-#include "gdb_sys_time.h"
-
-#if defined HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
-#endif
-
-#ifdef HAVE_GETRUSAGE
-struct rusage rusage;
-#endif
+#include "run-time-clock.h"
+#include <chrono>
 
 enum
   {
@@ -2169,7 +2162,7 @@ mi_execute_command (const char *cmd, int from_tty)
 
       if (do_timings)
 	{
-	  command->cmd_start = XNEW (struct mi_timestamp);
+	  command->cmd_start = new mi_timestamp ();
 	  timestamp (command->cmd_start);
 	}
 
@@ -2390,8 +2383,8 @@ mi_load_progress (const char *section_name,
 		  unsigned long total_sent,
 		  unsigned long grand_total)
 {
-  struct timeval time_now, delta, update_threshold;
-  static struct timeval last_update;
+  using namespace std::chrono;
+  static steady_clock::time_point last_update;
   static char *previous_sect_name = NULL;
   int new_section;
   struct ui_out *saved_uiout;
@@ -2416,19 +2409,6 @@ mi_load_progress (const char *section_name,
 
   uiout = current_uiout;
 
-  update_threshold.tv_sec = 0;
-  update_threshold.tv_usec = 500000;
-  gettimeofday (&time_now, NULL);
-
-  delta.tv_usec = time_now.tv_usec - last_update.tv_usec;
-  delta.tv_sec = time_now.tv_sec - last_update.tv_sec;
-
-  if (delta.tv_usec < 0)
-    {
-      delta.tv_sec -= 1;
-      delta.tv_usec += 1000000L;
-    }
-
   new_section = (previous_sect_name ?
 		 strcmp (previous_sect_name, section_name) : 1);
   if (new_section)
@@ -2451,13 +2431,12 @@ mi_load_progress (const char *section_name,
       gdb_flush (mi->raw_stdout);
     }
 
-  if (delta.tv_sec >= update_threshold.tv_sec &&
-      delta.tv_usec >= update_threshold.tv_usec)
+  steady_clock::time_point time_now = steady_clock::now ();
+  if (time_now - last_update > milliseconds (500))
     {
       struct cleanup *cleanup_tuple;
 
-      last_update.tv_sec = time_now.tv_sec;
-      last_update.tv_usec = time_now.tv_usec;
+      last_update = time_now;
       if (current_token)
 	fputs_unfiltered (current_token, mi->raw_stdout);
       fputs_unfiltered ("+download", mi->raw_stdout);
@@ -2480,23 +2459,10 @@ mi_load_progress (const char *section_name,
 static void
 timestamp (struct mi_timestamp *tv)
 {
-  gettimeofday (&tv->wallclock, NULL);
-#ifdef HAVE_GETRUSAGE
-  getrusage (RUSAGE_SELF, &rusage);
-  tv->utime.tv_sec = rusage.ru_utime.tv_sec;
-  tv->utime.tv_usec = rusage.ru_utime.tv_usec;
-  tv->stime.tv_sec = rusage.ru_stime.tv_sec;
-  tv->stime.tv_usec = rusage.ru_stime.tv_usec;
-#else
-  {
-    long usec = get_run_time ();
+  using namespace std::chrono;
 
-    tv->utime.tv_sec = usec/1000000L;
-    tv->utime.tv_usec = usec - 1000000L*tv->utime.tv_sec;
-    tv->stime.tv_sec = 0;
-    tv->stime.tv_usec = 0;
-  }
-#endif
+  tv->wallclock = steady_clock::now ();
+  run_time_clock::now (tv->utime, tv->stime);
 }
 
 static void
@@ -2517,23 +2483,20 @@ mi_print_timing_maybe (struct ui_file *file)
     print_diff_now (file, current_command_ts);
 }
 
-static long
-timeval_diff (struct timeval start, struct timeval end)
-{
-  return ((end.tv_sec - start.tv_sec) * 1000000L)
-    + (end.tv_usec - start.tv_usec);
-}
-
 static void
 print_diff (struct ui_file *file, struct mi_timestamp *start,
 	    struct mi_timestamp *end)
 {
+  using namespace std::chrono;
+
+  duration<double> wallclock = end->wallclock - start->wallclock;
+  duration<double> utime = end->utime - start->utime;
+  duration<double> stime = end->stime - start->stime;
+
   fprintf_unfiltered
     (file,
      ",time={wallclock=\"%0.5f\",user=\"%0.5f\",system=\"%0.5f\"}",
-     timeval_diff (start->wallclock, end->wallclock) / 1000000.0,
-     timeval_diff (start->utime, end->utime) / 1000000.0,
-     timeval_diff (start->stime, end->stime) / 1000000.0);
+     wallclock.count (), utime.count (), stime.count ());
 }
 
 void
diff --git a/gdb/mi/mi-parse.h b/gdb/mi/mi-parse.h
index d5595b3..dc8d21b 100644
--- a/gdb/mi/mi-parse.h
+++ b/gdb/mi/mi-parse.h
@@ -20,15 +20,17 @@
 #ifndef MI_PARSE_H
 #define MI_PARSE_H
 
-#include "gdb_sys_time.h"
+#include "run-time-clock.h"
+#include <chrono>
 
 /* MI parser */
 
 /* Timestamps for current command and last asynchronous command.  */
-struct mi_timestamp {
-  struct timeval wallclock;
-  struct timeval utime;
-  struct timeval stime;
+struct mi_timestamp
+{
+  std::chrono::steady_clock::time_point wallclock;
+  user_cpu_time_clock::time_point utime;
+  system_cpu_time_clock::time_point stime;
 };
 
 enum mi_command_type
diff --git a/gdb/symfile.c b/gdb/symfile.c
index f524f56..517c277 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -61,8 +61,7 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <ctype.h>
-#include <time.h>
-#include "gdb_sys_time.h"
+#include <chrono>
 
 #include "psymtab.h"
 
@@ -2066,11 +2065,15 @@ clear_memory_write_data (void *arg)
   VEC_free (memory_write_request_s, vec);
 }
 
+static void print_transfer_performance (struct ui_file *stream,
+					unsigned long data_count,
+					unsigned long write_count,
+				        std::chrono::steady_clock::duration d);
+
 void
 generic_load (const char *args, int from_tty)
 {
   bfd *loadfile_bfd;
-  struct timeval start_time, end_time;
   char *filename;
   struct cleanup *old_cleanups = make_cleanup (null_cleanup, 0);
   struct load_section_data cbdata;
@@ -2131,13 +2134,15 @@ generic_load (const char *args, int from_tty)
 
   bfd_map_over_sections (loadfile_bfd, load_section_callback, &cbdata);
 
-  gettimeofday (&start_time, NULL);
+  using namespace std::chrono;
+
+  steady_clock::time_point start_time = steady_clock::now ();
 
   if (target_write_memory_blocks (cbdata.requests, flash_discard,
 				  load_progress) != 0)
     error (_("Load failed"));
 
-  gettimeofday (&end_time, NULL);
+  steady_clock::time_point end_time = steady_clock::now ();
 
   entry = bfd_get_start_address (loadfile_bfd);
   entry = gdbarch_addr_bits_remove (target_gdbarch (), entry);
@@ -2160,32 +2165,32 @@ generic_load (const char *args, int from_tty)
 
   print_transfer_performance (gdb_stdout, total_progress.data_count,
 			      total_progress.write_count,
-			      &start_time, &end_time);
+			      end_time - start_time);
 
   do_cleanups (old_cleanups);
 }
 
-/* Report how fast the transfer went.  */
+/* Report on STREAM the performance of a memory transfer operation,
+   such as 'load'.  DATA_COUNT is the number of bytes transferred.
+   WRITE_COUNT is the number of separate write operations, or 0, if
+   that information is not available.  TIME is how long the operation
+   lasted.  */
 
-void
+static void
 print_transfer_performance (struct ui_file *stream,
 			    unsigned long data_count,
 			    unsigned long write_count,
-			    const struct timeval *start_time,
-			    const struct timeval *end_time)
+			    std::chrono::steady_clock::duration time)
 {
-  ULONGEST time_count;
+  using namespace std::chrono;
   struct ui_out *uiout = current_uiout;
 
-  /* Compute the elapsed time in milliseconds, as a tradeoff between
-     accuracy and overflow.  */
-  time_count = (end_time->tv_sec - start_time->tv_sec) * 1000;
-  time_count += (end_time->tv_usec - start_time->tv_usec) / 1000;
+  milliseconds ms = duration_cast<milliseconds> (time);
 
   ui_out_text (uiout, "Transfer rate: ");
-  if (time_count > 0)
+  if (ms.count () > 0)
     {
-      unsigned long rate = ((ULONGEST) data_count * 1000) / time_count;
+      unsigned long rate = ((ULONGEST) data_count * 1000) / ms.count ();
 
       if (ui_out_is_mi_like_p (uiout))
 	{
diff --git a/gdb/utils.c b/gdb/utils.c
index 751f099..8ca0a2e 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -37,7 +37,6 @@
 #endif
 
 #include <signal.h>
-#include "timeval-utils.h"
 #include "gdbcmd.h"
 #include "serial.h"
 #include "bfd.h"
@@ -61,8 +60,7 @@
 
 #include "readline/readline.h"
 
-#include "gdb_sys_time.h"
-#include <time.h>
+#include <chrono>
 
 #include "gdb_usleep.h"
 #include "interps.h"
@@ -98,7 +96,7 @@ static void set_width (void);
    Modified in prompt_for_continue and defaulted_query.
    Used in report_command_stats.  */
 
-static struct timeval prompt_for_continue_wait_time;
+static std::chrono::steady_clock::duration prompt_for_continue_wait_time;
 
 /* A flag indicating whether to timestamp debugging messages.  */
 
@@ -1184,9 +1182,6 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args)
   int def_value;
   char def_answer, not_def_answer;
   char *y_string, *n_string, *question, *prompt;
-  /* Used to add duration we waited for user to respond to
-     prompt_for_continue_wait_time.  */
-  struct timeval prompt_started, prompt_ended, prompt_delta;
   struct cleanup *old_chain;
 
   /* Set up according to which answer is the default.  */
@@ -1261,8 +1256,10 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args)
 		      annotation_level > 1 ? "\n\032\032query\n" : "");
   make_cleanup (xfree, prompt);
 
-  /* Used for calculating time spend waiting for user.  */
-  gettimeofday (&prompt_started, NULL);
+  /* Used to add duration we waited for user to respond to
+     prompt_for_continue_wait_time.  */
+  using namespace std::chrono;
+  steady_clock::time_point prompt_started = steady_clock::now ();
 
   prepare_to_handle_input ();
 
@@ -1307,10 +1304,7 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args)
     }
 
   /* Add time spend in this routine to prompt_for_continue_wait_time.  */
-  gettimeofday (&prompt_ended, NULL);
-  timeval_sub (&prompt_delta, &prompt_ended, &prompt_started);
-  timeval_add (&prompt_for_continue_wait_time,
-               &prompt_for_continue_wait_time, &prompt_delta);
+  prompt_for_continue_wait_time += steady_clock::now () - prompt_started;
 
   if (annotation_level > 1)
     printf_filtered (("\n\032\032post-query\n"));
@@ -1816,12 +1810,11 @@ prompt_for_continue (void)
 {
   char *ignore;
   char cont_prompt[120];
+  struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
   /* Used to add duration we waited for user to respond to
      prompt_for_continue_wait_time.  */
-  struct timeval prompt_started, prompt_ended, prompt_delta;
-  struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
-
-  gettimeofday (&prompt_started, NULL);
+  using namespace std::chrono;
+  steady_clock::time_point prompt_started = steady_clock::now ();
 
   if (annotation_level > 1)
     printf_unfiltered (("\n\032\032pre-prompt-for-continue\n"));
@@ -1844,10 +1837,7 @@ prompt_for_continue (void)
   make_cleanup (xfree, ignore);
 
   /* Add time spend in this routine to prompt_for_continue_wait_time.  */
-  gettimeofday (&prompt_ended, NULL);
-  timeval_sub (&prompt_delta, &prompt_ended, &prompt_started);
-  timeval_add (&prompt_for_continue_wait_time,
-               &prompt_for_continue_wait_time, &prompt_delta);
+  prompt_for_continue_wait_time += steady_clock::now () - prompt_started;
 
   if (annotation_level > 1)
     printf_unfiltered (("\n\032\032post-prompt-for-continue\n"));
@@ -1877,15 +1867,15 @@ prompt_for_continue (void)
 void
 reset_prompt_for_continue_wait_time (void)
 {
-  static const struct timeval zero_timeval = { 0 };
+  using namespace std::chrono;
 
-  prompt_for_continue_wait_time = zero_timeval;
+  prompt_for_continue_wait_time = steady_clock::duration::zero ();
 }
 
 /* Fetch the cumulative time spent in prompt_for_continue.  */
 
-struct timeval
-get_prompt_for_continue_wait_time (void)
+std::chrono::steady_clock::duration
+get_prompt_for_continue_wait_time ()
 {
   return prompt_for_continue_wait_time;
 }
@@ -2308,21 +2298,21 @@ vfprintf_unfiltered (struct ui_file *stream, const char *format, va_list args)
   old_cleanups = make_cleanup (xfree, linebuffer);
   if (debug_timestamp && stream == gdb_stdlog)
     {
-      struct timeval tm;
-      char *timestamp;
+      using namespace std::chrono;
       int len, need_nl;
 
-      gettimeofday (&tm, NULL);
+      steady_clock::time_point now = steady_clock::now ();
+      seconds s = duration_cast<seconds> (now.time_since_epoch ());
+      microseconds us = duration_cast<microseconds> (now.time_since_epoch () - s);
 
       len = strlen (linebuffer);
       need_nl = (len > 0 && linebuffer[len - 1] != '\n');
 
-      timestamp = xstrprintf ("%ld:%ld %s%s",
-			      (long) tm.tv_sec, (long) tm.tv_usec,
-			      linebuffer,
-			      need_nl ? "\n": "");
-      make_cleanup (xfree, timestamp);
-      fputs_unfiltered (timestamp, stream);
+      std::string timestamp = string_printf ("%ld.%06ld %s%s",
+					     (long) s.count (),
+					     (long) us.count (),
+					     linebuffer, need_nl ? "\n": "");
+      fputs_unfiltered (timestamp.c_str (), stream);
     }
   else
     fputs_unfiltered (linebuffer, stream);
diff --git a/gdb/utils.h b/gdb/utils.h
index 36f5294..62091f0 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -23,6 +23,7 @@
 
 #include "exceptions.h"
 #include "common/scoped_restore.h"
+#include <chrono>
 
 extern void initialize_utils (void);
 
@@ -51,7 +52,7 @@ extern const char *gdb_bfd_errmsg (bfd_error_type error_tag, char **matching);
 /* Reset the prompt_for_continue clock.  */
 void reset_prompt_for_continue_wait_time (void);
 /* Return the time spent in prompt_for_continue.  */
-struct timeval get_prompt_for_continue_wait_time (void);
+std::chrono::steady_clock::duration get_prompt_for_continue_wait_time ();
 
 /* Parsing utilites.  */
 
-- 
2.5.5



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]