From 88086373db8c1d933f40d0275c4b9c8a8c9b9723 Mon Sep 17 00:00:00 2001
From: Jan Tattermusch <jtattermusch@google.com>
Date: Thu, 10 Dec 2015 10:54:12 -0800
Subject: [PATCH] make gpr_timespec platform agnostic

---
 include/grpc/support/time.h                   |  4 +-
 src/core/iomgr/timer.c                        |  4 +-
 src/core/profiling/basic_timers.c             |  7 +-
 src/core/security/credentials.c               |  4 +-
 src/core/statistics/window_stats.c            |  2 +-
 src/core/support/log_linux.c                  |  4 +-
 src/core/support/log_posix.c                  |  4 +-
 src/core/support/log_win32.c                  |  4 +-
 src/core/support/time.c                       | 64 +++++--------
 src/core/support/time_posix.c                 | 17 +++-
 src/core/support/time_precise.c               |  4 +-
 src/core/support/time_win32.c                 |  6 +-
 src/core/surface/channel.c                    |  8 +-
 src/core/surface/channel_connectivity.c       |  6 +-
 src/core/surface/completion_queue.c           |  8 +-
 src/core/transport/chttp2/timeout_encoding.c  | 10 +-
 src/core/transport/transport_op_string.c      |  4 +-
 src/cpp/util/time.cc                          |  8 +-
 .../Grpc.Core.Tests/Internal/TimespecTest.cs  | 91 ++++++-------------
 src/csharp/Grpc.Core/Internal/Timespec.cs     | 23 ++---
 .../grpcio/grpc/_cython/_cygrpc/grpc.pxd      |  6 +-
 src/ruby/ext/grpc/rb_grpc.c                   |  4 +-
 test/core/iomgr/tcp_client_posix_test.c       |  5 +-
 test/core/support/sync_test.c                 |  2 +-
 test/core/support/time_test.c                 |  4 +-
 25 files changed, 133 insertions(+), 170 deletions(-)

diff --git a/include/grpc/support/time.h b/include/grpc/support/time.h
index f8ed893bc0..722866aa46 100644
--- a/include/grpc/support/time.h
+++ b/include/grpc/support/time.h
@@ -61,8 +61,8 @@ typedef enum {
 } gpr_clock_type;
 
 typedef struct gpr_timespec {
-  time_t tv_sec;
-  int tv_nsec;
+  gpr_int64 tv_sec;
+  gpr_int32 tv_nsec;
   /** Against which clock was this time measured? (or GPR_TIMESPAN if
       this is a relative time meaure) */
   gpr_clock_type clock_type;
diff --git a/src/core/iomgr/timer.c b/src/core/iomgr/timer.c
index 66fafe75ad..c0e3175c4c 100644
--- a/src/core/iomgr/timer.c
+++ b/src/core/iomgr/timer.c
@@ -126,8 +126,8 @@ static double ts_to_dbl(gpr_timespec ts) {
 
 static gpr_timespec dbl_to_ts(double d) {
   gpr_timespec ts;
-  ts.tv_sec = (time_t)d;
-  ts.tv_nsec = (int)(1e9 * (d - (double)ts.tv_sec));
+  ts.tv_sec = (gpr_int64)d;
+  ts.tv_nsec = (gpr_int32)(1e9 * (d - (double)ts.tv_sec));
   ts.clock_type = GPR_TIMESPAN;
   return ts;
 }
diff --git a/src/core/profiling/basic_timers.c b/src/core/profiling/basic_timers.c
index f0fce7858d..eedd387ebc 100644
--- a/src/core/profiling/basic_timers.c
+++ b/src/core/profiling/basic_timers.c
@@ -141,10 +141,11 @@ static void write_log(gpr_timer_log *log) {
       entry->tm = gpr_time_0(entry->tm.clock_type);
     }
     fprintf(output_file,
-            "{\"t\": %ld.%09d, \"thd\": \"%d\", \"type\": \"%c\", \"tag\": "
+            "{\"t\": %lld.%09d, \"thd\": \"%d\", \"type\": \"%c\", \"tag\": "
             "\"%s\", \"file\": \"%s\", \"line\": %d, \"imp\": %d}\n",
-            entry->tm.tv_sec, entry->tm.tv_nsec, entry->thd, entry->type,
-            entry->tagstr, entry->file, entry->line, entry->important);
+            (long long)entry->tm.tv_sec, (int)entry->tm.tv_nsec, entry->thd,
+            entry->type, entry->tagstr, entry->file, entry->line,
+            entry->important);
   }
 }
 
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 543c75044b..cbaec7d050 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -511,9 +511,9 @@ grpc_call_credentials *grpc_service_account_jwt_access_credentials_create(
       "grpc_service_account_jwt_access_credentials_create("
       "json_key=%s, "
       "token_lifetime="
-      "gpr_timespec { tv_sec: %ld, tv_nsec: %d, clock_type: %d }, "
+      "gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
       "reserved=%p)",
-      5, (json_key, (long)token_lifetime.tv_sec, token_lifetime.tv_nsec,
+      5, (json_key, (long long)token_lifetime.tv_sec, (int)token_lifetime.tv_nsec,
           (int)token_lifetime.clock_type, reserved));
   GPR_ASSERT(reserved == NULL);
   return grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
diff --git a/src/core/statistics/window_stats.c b/src/core/statistics/window_stats.c
index 4d0d3cca4a..e744006bb5 100644
--- a/src/core/statistics/window_stats.c
+++ b/src/core/statistics/window_stats.c
@@ -94,7 +94,7 @@ static gpr_int64 timespec_to_ns(const gpr_timespec ts) {
   if (ts.tv_sec > max_seconds) {
     return GPR_INT64_MAX - 1;
   }
-  return (gpr_int64)ts.tv_sec * GPR_NS_PER_SEC + ts.tv_nsec;
+  return ts.tv_sec * GPR_NS_PER_SEC + ts.tv_nsec;
 }
 
 static void cws_initialize_statistic(void *statistic,
diff --git a/src/core/support/log_linux.c b/src/core/support/log_linux.c
index 02f64d8b7e..d66b7a3cc0 100644
--- a/src/core/support/log_linux.c
+++ b/src/core/support/log_linux.c
@@ -76,16 +76,18 @@ void gpr_default_log(gpr_log_func_args *args) {
   char *prefix;
   const char *display_file;
   char time_buffer[64];
+  time_t timer;
   gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
   struct tm tm;
 
+  timer = (time_t)now.tv_sec;
   final_slash = strrchr(args->file, '/');
   if (final_slash == NULL)
     display_file = args->file;
   else
     display_file = final_slash + 1;
 
-  if (!localtime_r(&now.tv_sec, &tm)) {
+  if (!localtime_r(&timer, &tm)) {
     strcpy(time_buffer, "error:localtime");
   } else if (0 ==
              strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) {
diff --git a/src/core/support/log_posix.c b/src/core/support/log_posix.c
index 8b050dbee7..8986254e4e 100644
--- a/src/core/support/log_posix.c
+++ b/src/core/support/log_posix.c
@@ -75,16 +75,18 @@ void gpr_default_log(gpr_log_func_args *args) {
   char *final_slash;
   const char *display_file;
   char time_buffer[64];
+  time_t timer;
   gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
   struct tm tm;
 
+  timer = (time_t)now.tv_sec;
   final_slash = strrchr(args->file, '/');
   if (final_slash == NULL)
     display_file = args->file;
   else
     display_file = final_slash + 1;
 
-  if (!localtime_r(&now.tv_sec, &tm)) {
+  if (!localtime_r(&timer, &tm)) {
     strcpy(time_buffer, "error:localtime");
   } else if (0 ==
              strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) {
diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c
index b68239f8f5..28e7768f80 100644
--- a/src/core/support/log_win32.c
+++ b/src/core/support/log_win32.c
@@ -84,16 +84,18 @@ void gpr_default_log(gpr_log_func_args *args) {
   char *final_slash;
   const char *display_file;
   char time_buffer[64];
+  time_t timer;
   gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
   struct tm tm;
 
+  timer = (time_t)now.tv_sec;
   final_slash = strrchr(args->file, '\\');
   if (final_slash == NULL)
     display_file = args->file;
   else
     display_file = final_slash + 1;
 
-  if (localtime_s(&tm, &now.tv_sec)) {
+  if (localtime_s(&tm, &timer)) {
     strcpy(time_buffer, "error:localtime");
   } else if (0 ==
              strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) {
diff --git a/src/core/support/time.c b/src/core/support/time.c
index 929adac918..197fa9ad44 100644
--- a/src/core/support/time.c
+++ b/src/core/support/time.c
@@ -56,22 +56,6 @@ gpr_timespec gpr_time_max(gpr_timespec a, gpr_timespec b) {
   return gpr_time_cmp(a, b) > 0 ? a : b;
 }
 
-/* There's no standard TIME_T_MIN and TIME_T_MAX, so we construct them.  The
-   following assumes that signed types are two's-complement and that bytes are
-   8 bits.  */
-
-/* The top bit of integral type t. */
-#define TOP_BIT_OF_TYPE(t) (((gpr_uintmax)1) << ((8 * sizeof(t)) - 1))
-
-/* Return whether integral type t is signed. */
-#define TYPE_IS_SIGNED(t) (((t)1) > (t) ~(t)0)
-
-/* The minimum and maximum value of integral type t. */
-#define TYPE_MIN(t) ((t)(TYPE_IS_SIGNED(t) ? TOP_BIT_OF_TYPE(t) : 0))
-#define TYPE_MAX(t)                                 \
-  ((t)(TYPE_IS_SIGNED(t) ? (TOP_BIT_OF_TYPE(t) - 1) \
-                         : ((TOP_BIT_OF_TYPE(t) - 1) << 1) + 1))
-
 gpr_timespec gpr_time_0(gpr_clock_type type) {
   gpr_timespec out;
   out.tv_sec = 0;
@@ -82,7 +66,7 @@ gpr_timespec gpr_time_0(gpr_clock_type type) {
 
 gpr_timespec gpr_inf_future(gpr_clock_type type) {
   gpr_timespec out;
-  out.tv_sec = TYPE_MAX(time_t);
+  out.tv_sec = INT64_MAX;
   out.tv_nsec = 0;
   out.clock_type = type;
   return out;
@@ -90,7 +74,7 @@ gpr_timespec gpr_inf_future(gpr_clock_type type) {
 
 gpr_timespec gpr_inf_past(gpr_clock_type type) {
   gpr_timespec out;
-  out.tv_sec = TYPE_MIN(time_t);
+  out.tv_sec = INT64_MIN;
   out.tv_nsec = 0;
   out.clock_type = type;
   return out;
@@ -108,11 +92,11 @@ gpr_timespec gpr_time_from_nanos(long ns, gpr_clock_type type) {
     result = gpr_inf_past(type);
   } else if (ns >= 0) {
     result.tv_sec = ns / GPR_NS_PER_SEC;
-    result.tv_nsec = (int)(ns - result.tv_sec * GPR_NS_PER_SEC);
+    result.tv_nsec = (gpr_int32)(ns - result.tv_sec * GPR_NS_PER_SEC);
   } else {
     /* Calculation carefully formulated to avoid any possible under/overflow. */
     result.tv_sec = (-(999999999 - (ns + GPR_NS_PER_SEC)) / GPR_NS_PER_SEC) - 1;
-    result.tv_nsec = (int)(ns - result.tv_sec * GPR_NS_PER_SEC);
+    result.tv_nsec = (gpr_int32)(ns - result.tv_sec * GPR_NS_PER_SEC);
   }
   return result;
 }
@@ -126,11 +110,11 @@ gpr_timespec gpr_time_from_micros(long us, gpr_clock_type type) {
     result = gpr_inf_past(type);
   } else if (us >= 0) {
     result.tv_sec = us / 1000000;
-    result.tv_nsec = (int)((us - result.tv_sec * 1000000) * 1000);
+    result.tv_nsec = (gpr_int32)((us - result.tv_sec * 1000000) * 1000);
   } else {
     /* Calculation carefully formulated to avoid any possible under/overflow. */
     result.tv_sec = (-(999999 - (us + 1000000)) / 1000000) - 1;
-    result.tv_nsec = (int)((us - result.tv_sec * 1000000) * 1000);
+    result.tv_nsec = (gpr_int32)((us - result.tv_sec * 1000000) * 1000);
   }
   return result;
 }
@@ -144,11 +128,11 @@ gpr_timespec gpr_time_from_millis(long ms, gpr_clock_type type) {
     result = gpr_inf_past(type);
   } else if (ms >= 0) {
     result.tv_sec = ms / 1000;
-    result.tv_nsec = (int)((ms - result.tv_sec * 1000) * 1000000);
+    result.tv_nsec = (gpr_int32)((ms - result.tv_sec * 1000) * 1000000);
   } else {
     /* Calculation carefully formulated to avoid any possible under/overflow. */
     result.tv_sec = (-(999 - (ms + 1000)) / 1000) - 1;
-    result.tv_nsec = (int)((ms - result.tv_sec * 1000) * 1000000);
+    result.tv_nsec = (gpr_int32)((ms - result.tv_sec * 1000) * 1000000);
   }
   return result;
 }
@@ -197,7 +181,7 @@ gpr_timespec gpr_time_from_hours(long h, gpr_clock_type type) {
 
 gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) {
   gpr_timespec sum;
-  int inc = 0;
+  gpr_int64 inc = 0;
   GPR_ASSERT(b.clock_type == GPR_TIMESPAN);
   sum.clock_type = a.clock_type;
   sum.tv_nsec = a.tv_nsec + b.tv_nsec;
@@ -205,17 +189,17 @@ gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) {
     sum.tv_nsec -= GPR_NS_PER_SEC;
     inc++;
   }
-  if (a.tv_sec == TYPE_MAX(time_t) || a.tv_sec == TYPE_MIN(time_t)) {
+  if (a.tv_sec == INT64_MAX || a.tv_sec == INT64_MIN) {
     sum = a;
-  } else if (b.tv_sec == TYPE_MAX(time_t) ||
-             (b.tv_sec >= 0 && a.tv_sec >= TYPE_MAX(time_t) - b.tv_sec)) {
+  } else if (b.tv_sec == INT64_MAX ||
+             (b.tv_sec >= 0 && a.tv_sec >= INT64_MAX - b.tv_sec)) {
     sum = gpr_inf_future(sum.clock_type);
-  } else if (b.tv_sec == TYPE_MIN(time_t) ||
-             (b.tv_sec <= 0 && a.tv_sec <= TYPE_MIN(time_t) - b.tv_sec)) {
+  } else if (b.tv_sec == INT64_MIN ||
+             (b.tv_sec <= 0 && a.tv_sec <= INT64_MIN - b.tv_sec)) {
     sum = gpr_inf_past(sum.clock_type);
   } else {
     sum.tv_sec = a.tv_sec + b.tv_sec;
-    if (inc != 0 && sum.tv_sec == TYPE_MAX(time_t) - 1) {
+    if (inc != 0 && sum.tv_sec == INT64_MAX - 1) {
       sum = gpr_inf_future(sum.clock_type);
     } else {
       sum.tv_sec += inc;
@@ -226,7 +210,7 @@ gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) {
 
 gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b) {
   gpr_timespec diff;
-  int dec = 0;
+  gpr_int64 dec = 0;
   if (b.clock_type == GPR_TIMESPAN) {
     diff.clock_type = a.clock_type;
   } else {
@@ -238,17 +222,17 @@ gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b) {
     diff.tv_nsec += GPR_NS_PER_SEC;
     dec++;
   }
-  if (a.tv_sec == TYPE_MAX(time_t) || a.tv_sec == TYPE_MIN(time_t)) {
+  if (a.tv_sec == INT64_MAX || a.tv_sec == INT64_MIN) {
     diff = a;
-  } else if (b.tv_sec == TYPE_MIN(time_t) ||
-             (b.tv_sec <= 0 && a.tv_sec >= TYPE_MAX(time_t) + b.tv_sec)) {
+  } else if (b.tv_sec == INT64_MIN ||
+             (b.tv_sec <= 0 && a.tv_sec >= INT64_MAX + b.tv_sec)) {
     diff = gpr_inf_future(GPR_CLOCK_REALTIME);
-  } else if (b.tv_sec == TYPE_MAX(time_t) ||
-             (b.tv_sec >= 0 && a.tv_sec <= TYPE_MIN(time_t) + b.tv_sec)) {
+  } else if (b.tv_sec == INT64_MAX ||
+             (b.tv_sec >= 0 && a.tv_sec <= INT64_MIN + b.tv_sec)) {
     diff = gpr_inf_past(GPR_CLOCK_REALTIME);
   } else {
     diff.tv_sec = a.tv_sec - b.tv_sec;
-    if (dec != 0 && diff.tv_sec == TYPE_MIN(time_t) + 1) {
+    if (dec != 0 && diff.tv_sec == INT64_MIN + 1) {
       diff = gpr_inf_past(GPR_CLOCK_REALTIME);
     } else {
       diff.tv_sec -= dec;
@@ -297,11 +281,11 @@ gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type clock_type) {
   }
 
   if (t.tv_nsec == 0) {
-    if (t.tv_sec == TYPE_MAX(time_t)) {
+    if (t.tv_sec == INT64_MAX) {
       t.clock_type = clock_type;
       return t;
     }
-    if (t.tv_sec == TYPE_MIN(time_t)) {
+    if (t.tv_sec == INT64_MIN) {
       t.clock_type = clock_type;
       return t;
     }
diff --git a/src/core/support/time_posix.c b/src/core/support/time_posix.c
index 02cfca8555..05d6cc0ca8 100644
--- a/src/core/support/time_posix.c
+++ b/src/core/support/time_posix.c
@@ -45,7 +45,11 @@
 
 static struct timespec timespec_from_gpr(gpr_timespec gts) {
   struct timespec rv;
-  rv.tv_sec = gts.tv_sec;
+  if (sizeof(time_t) < sizeof(gpr_int64)) {
+    /* fine to assert, as this is only used in gpr_sleep_until */
+     GPR_ASSERT(gts.tv_sec <= INT32_MAX && gts.tv_sec >= INT32_MIN);
+  }
+  rv.tv_sec = (time_t)gts.tv_sec;
   rv.tv_nsec = gts.tv_nsec;
   return rv;
 }
@@ -53,9 +57,14 @@ static struct timespec timespec_from_gpr(gpr_timespec gts) {
 #if _POSIX_TIMERS > 0
 static gpr_timespec gpr_from_timespec(struct timespec ts,
                                       gpr_clock_type clock_type) {
+  /*
+   * timespec.tv_sec can have smaller size than gpr_timespec.tv_sec,
+   * but we are only using this function to implement gpr_now
+   * so there's no need to handle "infinity" values.
+   */
   gpr_timespec rv;
   rv.tv_sec = ts.tv_sec;
-  rv.tv_nsec = (int)ts.tv_nsec;
+  rv.tv_nsec = (gpr_int32)ts.tv_nsec;
   rv.clock_type = clock_type;
   return rv;
 }
@@ -110,8 +119,8 @@ gpr_timespec gpr_now(gpr_clock_type clock) {
       break;
     case GPR_CLOCK_MONOTONIC:
       now_dbl = (mach_absolute_time() - g_time_start) * g_time_scale;
-      now.tv_sec = (time_t)(now_dbl * 1e-9);
-      now.tv_nsec = (int)(now_dbl - ((double)now.tv_sec) * 1e9);
+      now.tv_sec = (gpr_int64)(now_dbl * 1e-9);
+      now.tv_nsec = (gpr_int32)(now_dbl - ((double)now.tv_sec) * 1e9);
       break;
     case GPR_CLOCK_PRECISE:
       gpr_precise_clock_now(&now);
diff --git a/src/core/support/time_precise.c b/src/core/support/time_precise.c
index b37517e639..4de1d9b071 100644
--- a/src/core/support/time_precise.c
+++ b/src/core/support/time_precise.c
@@ -75,8 +75,8 @@ void gpr_precise_clock_now(gpr_timespec *clk) {
   gpr_get_cycle_counter(&counter);
   secs = (double)(counter - start_cycle) / cycles_per_second;
   clk->clock_type = GPR_CLOCK_PRECISE;
-  clk->tv_sec = (time_t)secs;
-  clk->tv_nsec = (int)(1e9 * (secs - (double)clk->tv_sec));
+  clk->tv_sec = (gpr_int64)secs;
+  clk->tv_nsec = (gpr_int32)(1e9 * (secs - (double)clk->tv_sec));
 }
 
 #else  /* GRPC_TIMERS_RDTSC */
diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c
index 623a8d9233..7ccaaa248d 100644
--- a/src/core/support/time_win32.c
+++ b/src/core/support/time_win32.c
@@ -62,15 +62,15 @@ gpr_timespec gpr_now(gpr_clock_type clock) {
   switch (clock) {
     case GPR_CLOCK_REALTIME:
       _ftime_s(&now_tb);
-      now_tv.tv_sec = now_tb.time;
+      now_tv.tv_sec = (gpr_int64)now_tb.time;
       now_tv.tv_nsec = now_tb.millitm * 1000000;
       break;
     case GPR_CLOCK_MONOTONIC:
     case GPR_CLOCK_PRECISE:
       QueryPerformanceCounter(&timestamp);
       now_dbl = (timestamp.QuadPart - g_start_time.QuadPart) * g_time_scale;
-      now_tv.tv_sec = (time_t)now_dbl;
-      now_tv.tv_nsec = (int)((now_dbl - (double)now_tv.tv_sec) * 1e9);
+      now_tv.tv_sec = (gpr_int64)now_dbl;
+      now_tv.tv_nsec = (gpr_int32)((now_dbl - (double)now_tv.tv_sec) * 1e9);
       break;
   }
   return now_tv;
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index 14fe97c30d..cff8313eef 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -194,10 +194,10 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel,
       "grpc_channel_create_call("
       "channel=%p, parent_call=%p, propagation_mask=%x, cq=%p, method=%s, "
       "host=%s, "
-      "deadline=gpr_timespec { tv_sec: %ld, tv_nsec: %d, clock_type: %d }, "
+      "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
       "reserved=%p)",
       10, (channel, parent_call, (unsigned)propagation_mask, cq, method, host,
-           (long)deadline.tv_sec, deadline.tv_nsec, (int)deadline.clock_type,
+           (long long)deadline.tv_sec, (int)deadline.tv_nsec, (int)deadline.clock_type,
            reserved));
   GPR_ASSERT(!reserved);
   return grpc_channel_create_call_internal(
@@ -238,10 +238,10 @@ grpc_call *grpc_channel_create_registered_call(
       "grpc_channel_create_registered_call("
       "channel=%p, parent_call=%p, propagation_mask=%x, completion_queue=%p, "
       "registered_call_handle=%p, "
-      "deadline=gpr_timespec { tv_sec: %ld, tv_nsec: %d, clock_type: %d }, "
+      "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
       "reserved=%p)",
       9, (channel, parent_call, (unsigned)propagation_mask, completion_queue,
-          registered_call_handle, (long)deadline.tv_sec, deadline.tv_nsec,
+          registered_call_handle, (long long)deadline.tv_sec, (int)deadline.tv_nsec,
           (int)deadline.clock_type, reserved));
   GPR_ASSERT(!reserved);
   return grpc_channel_create_call_internal(
diff --git a/src/core/surface/channel_connectivity.c b/src/core/surface/channel_connectivity.c
index df2774b527..cee1ddb8b9 100644
--- a/src/core/surface/channel_connectivity.c
+++ b/src/core/surface/channel_connectivity.c
@@ -200,10 +200,10 @@ void grpc_channel_watch_connectivity_state(
   GRPC_API_TRACE(
       "grpc_channel_watch_connectivity_state("
       "channel=%p, last_observed_state=%d, "
-      "deadline=gpr_timespec { tv_sec: %ld, tv_nsec: %d, clock_type: %d }, "
+      "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
       "cq=%p, tag=%p)",
-      7, (channel, (int)last_observed_state, (long)deadline.tv_sec,
-          deadline.tv_nsec, (int)deadline.clock_type, cq, tag));
+      7, (channel, (int)last_observed_state, (long long)deadline.tv_sec,
+          (int)deadline.tv_nsec, (int)deadline.clock_type, cq, tag));
 
   grpc_cq_begin_op(cq);
 
diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c
index d56e5cbe84..c71b9b02b0 100644
--- a/src/core/surface/completion_queue.c
+++ b/src/core/surface/completion_queue.c
@@ -247,9 +247,9 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
   GRPC_API_TRACE(
       "grpc_completion_queue_next("
       "cc=%p, "
-      "deadline=gpr_timespec { tv_sec: %ld, tv_nsec: %d, clock_type: %d }, "
+      "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
       "reserved=%p)",
-      5, (cc, (long)deadline.tv_sec, deadline.tv_nsec, (int)deadline.clock_type,
+      5, (cc, (long long)deadline.tv_sec, (int)deadline.tv_nsec, (int)deadline.clock_type,
           reserved));
   GPR_ASSERT(!reserved);
 
@@ -335,9 +335,9 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
   GRPC_API_TRACE(
       "grpc_completion_queue_pluck("
       "cc=%p, tag=%p, "
-      "deadline=gpr_timespec { tv_sec: %ld, tv_nsec: %d, clock_type: %d }, "
+      "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
       "reserved=%p)",
-      6, (cc, tag, (long)deadline.tv_sec, deadline.tv_nsec,
+      6, (cc, tag, (long long)deadline.tv_sec, (int)deadline.tv_nsec,
           (int)deadline.clock_type, reserved));
   GPR_ASSERT(!reserved);
 
diff --git a/src/core/transport/chttp2/timeout_encoding.c b/src/core/transport/chttp2/timeout_encoding.c
index cf81c18a20..7ec8b4e8bf 100644
--- a/src/core/transport/chttp2/timeout_encoding.c
+++ b/src/core/transport/chttp2/timeout_encoding.c
@@ -39,12 +39,12 @@
 #include <grpc/support/port_platform.h>
 #include "src/core/support/string.h"
 
-static int round_up(int x, int divisor) {
+static gpr_int64 round_up(gpr_int64 x, gpr_int64 divisor) {
   return (x / divisor + (x % divisor != 0)) * divisor;
 }
 
 /* round an integer up to the next value with three significant figures */
-static int round_up_to_three_sig_figs(int x) {
+static gpr_int64 round_up_to_three_sig_figs(gpr_int64 x) {
   if (x < 1000) return x;
   if (x < 10000) return round_up(x, 10);
   if (x < 100000) return round_up(x, 100);
@@ -74,7 +74,7 @@ static void enc_seconds(char *buffer, gpr_int64 sec) {
   }
 }
 
-static void enc_nanos(char *buffer, int x) {
+static void enc_nanos(char *buffer, gpr_int64 x) {
   x = round_up_to_three_sig_figs(x);
   if (x < 100000) {
     if (x % 1000 == 0) {
@@ -98,7 +98,7 @@ static void enc_nanos(char *buffer, int x) {
   }
 }
 
-static void enc_micros(char *buffer, int x) {
+static void enc_micros(char *buffer, gpr_int64 x) {
   x = round_up_to_three_sig_figs(x);
   if (x < 100000) {
     if (x % 1000 == 0) {
@@ -124,7 +124,7 @@ void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer) {
     enc_nanos(buffer, timeout.tv_nsec);
   } else if (timeout.tv_sec < 1000 && timeout.tv_nsec != 0) {
     enc_micros(buffer,
-               (int)(timeout.tv_sec * 1000000) +
+               (gpr_int64)(timeout.tv_sec * 1000000) +
                    (timeout.tv_nsec / 1000 + (timeout.tv_nsec % 1000 != 0)));
   } else {
     enc_seconds(buffer, timeout.tv_sec + (timeout.tv_nsec != 0));
diff --git a/src/core/transport/transport_op_string.c b/src/core/transport/transport_op_string.c
index f3b6db29d6..98b51afc88 100644
--- a/src/core/transport/transport_op_string.c
+++ b/src/core/transport/transport_op_string.c
@@ -63,8 +63,8 @@ static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) {
   }
   if (gpr_time_cmp(md.deadline, gpr_inf_future(md.deadline.clock_type)) != 0) {
     char *tmp;
-    gpr_asprintf(&tmp, " deadline=%d.%09d", md.deadline.tv_sec,
-                 md.deadline.tv_nsec);
+    gpr_asprintf(&tmp, " deadline=%lld.%09d", (long long)md.deadline.tv_sec,
+                 (int)md.deadline.tv_nsec);
     gpr_strvec_add(b, tmp);
   }
 }
diff --git a/src/cpp/util/time.cc b/src/cpp/util/time.cc
index 6157a37745..9c38b34879 100644
--- a/src/cpp/util/time.cc
+++ b/src/cpp/util/time.cc
@@ -57,8 +57,8 @@ void Timepoint2Timespec(const system_clock::time_point& from,
     return;
   }
   nanoseconds nsecs = duration_cast<nanoseconds>(deadline - secs);
-  to->tv_sec = (time_t)secs.count();
-  to->tv_nsec = (int)nsecs.count();
+  to->tv_sec = (gpr_int64)secs.count();
+  to->tv_nsec = (gpr_int32)nsecs.count();
   to->clock_type = GPR_CLOCK_REALTIME;
 }
 
@@ -73,8 +73,8 @@ void TimepointHR2Timespec(const high_resolution_clock::time_point& from,
     return;
   }
   nanoseconds nsecs = duration_cast<nanoseconds>(deadline - secs);
-  to->tv_sec = (time_t)secs.count();
-  to->tv_nsec = (int)nsecs.count();
+  to->tv_sec = (gpr_int64)secs.count();
+  to->tv_nsec = (gpr_int32)nsecs.count();
   to->clock_type = GPR_CLOCK_REALTIME;
 }
 
diff --git a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs
index 9be5450d81..48b5d78ca9 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs
@@ -82,17 +82,17 @@ namespace Grpc.Core.Internal.Tests
         public void ToDateTime()
         {
             Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
-                new Timespec(IntPtr.Zero, 0).ToDateTime());
+                new Timespec(0, 0).ToDateTime());
 
             Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 10, DateTimeKind.Utc).AddTicks(50),
-                new Timespec(new IntPtr(10), 5000).ToDateTime());
+                new Timespec(10, 5000).ToDateTime());
 
             Assert.AreEqual(new DateTime(2015, 7, 21, 4, 21, 48, DateTimeKind.Utc),
-                new Timespec(new IntPtr(1437452508), 0).ToDateTime());
+                new Timespec(1437452508, 0).ToDateTime());
 
             // before epoch
             Assert.AreEqual(new DateTime(1969, 12, 31, 23, 59, 55, DateTimeKind.Utc).AddTicks(10),
-                new Timespec(new IntPtr(-5), 1000).ToDateTime());
+                new Timespec(-5, 1000).ToDateTime());
 
             // infinity
             Assert.AreEqual(DateTime.MaxValue, Timespec.InfFuture.ToDateTime());
@@ -100,80 +100,62 @@ namespace Grpc.Core.Internal.Tests
 
             // nanos are rounded to ticks are rounded up
             Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddTicks(1),
-                new Timespec(IntPtr.Zero, 99).ToDateTime());
+                new Timespec(0, 99).ToDateTime());
 
             // Illegal inputs
             Assert.Throws(typeof(InvalidOperationException),
-                () => new Timespec(new IntPtr(0), -2).ToDateTime());
+                () => new Timespec(0, -2).ToDateTime());
             Assert.Throws(typeof(InvalidOperationException),
-                () => new Timespec(new IntPtr(0), 1000 * 1000 * 1000).ToDateTime());
+                () => new Timespec(0, 1000 * 1000 * 1000).ToDateTime());
             Assert.Throws(typeof(InvalidOperationException),
-                () => new Timespec(new IntPtr(0), 0, GPRClockType.Monotonic).ToDateTime());
+                () => new Timespec(0, 0, GPRClockType.Monotonic).ToDateTime());
         }
 
         [Test]
         public void ToDateTime_ReturnsUtc()
         {
-            Assert.AreEqual(DateTimeKind.Utc, new Timespec(new IntPtr(1437452508), 0).ToDateTime().Kind);
-            Assert.AreNotEqual(DateTimeKind.Unspecified, new Timespec(new IntPtr(1437452508), 0).ToDateTime().Kind);
+            Assert.AreEqual(DateTimeKind.Utc, new Timespec(1437452508, 0).ToDateTime().Kind);
+            Assert.AreNotEqual(DateTimeKind.Unspecified, new Timespec(1437452508, 0).ToDateTime().Kind);
         }
 
         [Test]
         public void ToDateTime_Overflow()
-        {
-            // we can only get overflow in ticks arithmetic on 64-bit
-            if (IntPtr.Size == 8)
-            {
-                var timespec = new Timespec(new IntPtr(long.MaxValue - 100), 0);
-                Assert.AreNotEqual(Timespec.InfFuture, timespec);
-                Assert.AreEqual(DateTime.MaxValue, timespec.ToDateTime());
-
-                Assert.AreEqual(DateTime.MinValue, new Timespec(new IntPtr(long.MinValue + 100), 0).ToDateTime());
-            }
-            else
-            {
-                Console.WriteLine("Test cannot be run on this platform, skipping the test.");
-            }
+        {     
+            var timespec = new Timespec(long.MaxValue - 100, 0);
+            Assert.AreNotEqual(Timespec.InfFuture, timespec);
+            Assert.AreEqual(DateTime.MaxValue, timespec.ToDateTime());
+
+            Assert.AreEqual(DateTime.MinValue, new Timespec(long.MinValue + 100, 0).ToDateTime());
         }
 
         [Test]
         public void ToDateTime_OutOfDateTimeRange()
         {
-            // we can only get out of range on 64-bit, on 32 bit the max 
-            // timestamp is ~ Jan 19 2038, which is far within range of DateTime
-            // same case for min value.
-            if (IntPtr.Size == 8)
-            {
-                // DateTime range goes up to year 9999, 20000 years from now should
-                // be out of range.
-                long seconds = 20000L * 365L * 24L * 3600L; 
-
-                var timespec = new Timespec(new IntPtr(seconds), 0);
-                Assert.AreNotEqual(Timespec.InfFuture, timespec);
-                Assert.AreEqual(DateTime.MaxValue, timespec.ToDateTime());
-
-                Assert.AreEqual(DateTime.MinValue, new Timespec(new IntPtr(-seconds), 0).ToDateTime());
-            }
-            else
-            {
-                Console.WriteLine("Test cannot be run on this platform, skipping the test");
-            }
+            // DateTime range goes up to year 9999, 20000 years from now should
+            // be out of range.
+            long seconds = 20000L * 365L * 24L * 3600L; 
+
+            var timespec = new Timespec(seconds, 0);
+            Assert.AreNotEqual(Timespec.InfFuture, timespec);
+            Assert.AreEqual(DateTime.MaxValue, timespec.ToDateTime());
+
+            Assert.AreEqual(DateTime.MinValue, new Timespec(-seconds, 0).ToDateTime());
         }
 
         [Test]
         public void FromDateTime()
         {
-            Assert.AreEqual(new Timespec(IntPtr.Zero, 0),
+            Assert.AreEqual(new Timespec(0, 0),
                 Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)));
 
-            Assert.AreEqual(new Timespec(new IntPtr(10), 5000),
+            Assert.AreEqual(new Timespec(10, 5000),
                 Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 10, DateTimeKind.Utc).AddTicks(50)));
 
-            Assert.AreEqual(new Timespec(new IntPtr(1437452508), 0),
+            Assert.AreEqual(new Timespec(1437452508, 0),
                 Timespec.FromDateTime(new DateTime(2015, 7, 21, 4, 21, 48, DateTimeKind.Utc)));
 
             // before epoch
-            Assert.AreEqual(new Timespec(new IntPtr(-5), 1000),
+            Assert.AreEqual(new Timespec(-5, 1000),
                 Timespec.FromDateTime(new DateTime(1969, 12, 31, 23, 59, 55, DateTimeKind.Utc).AddTicks(10)));
 
             // infinity
@@ -184,21 +166,6 @@ namespace Grpc.Core.Internal.Tests
             Assert.Throws(typeof(ArgumentException),
                 () => Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Unspecified)));
         }
-
-        [Test]
-        public void FromDateTime_OutOfTimespecRange()
-        {
-            // we can only get overflow in Timespec on 32-bit
-            if (IntPtr.Size == 4)
-            {
-                Assert.AreEqual(Timespec.InfFuture, Timespec.FromDateTime(new DateTime(2040, 1, 1, 0, 0, 0, DateTimeKind.Utc)));
-                Assert.AreEqual(Timespec.InfPast, Timespec.FromDateTime(new DateTime(1800, 1, 1, 0, 0, 0, DateTimeKind.Utc)));
-            }
-            else
-            {
-                Console.WriteLine("Test cannot be run on this platform, skipping the test.");
-            }
-        }
             
         // Test attribute commented out to prevent running as part of the default test suite.
         // [Test]
diff --git a/src/csharp/Grpc.Core/Internal/Timespec.cs b/src/csharp/Grpc.Core/Internal/Timespec.cs
index 38fc067d9f..3031175c8a 100644
--- a/src/csharp/Grpc.Core/Internal/Timespec.cs
+++ b/src/csharp/Grpc.Core/Internal/Timespec.cs
@@ -63,20 +63,18 @@ namespace Grpc.Core.Internal
         [DllImport("grpc_csharp_ext.dll")]
         static extern int gprsharp_sizeof_timespec();
 
-        public Timespec(IntPtr tv_sec, int tv_nsec) : this(tv_sec, tv_nsec, GPRClockType.Realtime)
+        public Timespec(long tv_sec, int tv_nsec) : this(tv_sec, tv_nsec, GPRClockType.Realtime)
         {
         }
 
-        public Timespec(IntPtr tv_sec, int tv_nsec, GPRClockType clock_type)
+        public Timespec(long tv_sec, int tv_nsec, GPRClockType clock_type)
         {
             this.tv_sec = tv_sec;
             this.tv_nsec = tv_nsec;
             this.clock_type = clock_type;
         }
 
-        // NOTE: on linux 64bit  sizeof(gpr_timespec) = 16, on windows 32bit sizeof(gpr_timespec) = 8
-        // so IntPtr seems to have the right size to work on both.
-        private System.IntPtr tv_sec;
+        private long tv_sec;
         private int tv_nsec;
         private GPRClockType clock_type;
 
@@ -116,7 +114,7 @@ namespace Grpc.Core.Internal
         /// <summary>
         /// Seconds since unix epoch.
         /// </summary>
-        public IntPtr TimevalSeconds
+        public long TimevalSeconds
         {
             get
             {
@@ -176,18 +174,18 @@ namespace Grpc.Core.Internal
             {
                 // convert nanos to ticks, round up to the nearest tick
                 long ticksFromNanos = tv_nsec / NanosPerTick + ((tv_nsec % NanosPerTick != 0) ? 1 : 0);
-                long ticksTotal = checked(tv_sec.ToInt64() * TicksPerSecond + ticksFromNanos);
+                long ticksTotal = checked(tv_sec * TicksPerSecond + ticksFromNanos);
                 return UnixEpoch.AddTicks(ticksTotal);
             }
             catch (OverflowException)
             {
                 // ticks out of long range
-                return tv_sec.ToInt64() > 0 ? DateTime.MaxValue : DateTime.MinValue;
+                return tv_sec > 0 ? DateTime.MaxValue : DateTime.MinValue;
             }
             catch (ArgumentOutOfRangeException)
             {
                 // resulting date time would be larger than MaxValue
-                return tv_sec.ToInt64() > 0 ? DateTime.MaxValue : DateTime.MinValue;
+                return tv_sec > 0 ? DateTime.MaxValue : DateTime.MinValue;
             }
         }
             
@@ -226,12 +224,7 @@ namespace Grpc.Core.Internal
                     seconds--;
                     nanos += (int)NanosPerSecond;
                 }
-                // new IntPtr possibly throws OverflowException
-                return new Timespec(new IntPtr(seconds), nanos);
-            }
-            catch (OverflowException)
-            {
-                return dateTime > UnixEpoch ? Timespec.InfFuture : Timespec.InfPast;
+                return new Timespec(seconds, nanos);
             }
             catch (ArgumentOutOfRangeException)
             {
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
index 10c948cd0a..643cdc9e3d 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
@@ -60,6 +60,8 @@ cdef extern from "grpc/support/port_platform.h":
   # type exactly; just close enough that the operations will be supported in the
   # underlying C layers.
   ctypedef unsigned int gpr_uint32
+  ctypedef int gpr_int32
+  ctypedef long int gpr_int64
 
 
 cdef extern from "grpc/support/time.h":
@@ -71,8 +73,8 @@ cdef extern from "grpc/support/time.h":
     GPR_TIMESPAN
 
   ctypedef struct gpr_timespec:
-    libc.time.time_t seconds "tv_sec"
-    int nanoseconds "tv_nsec"
+    gpr_int64 seconds "tv_sec"
+    gpr_int32 nanoseconds "tv_nsec"
     gpr_clock_type clock_type
 
   gpr_timespec gpr_time_0(gpr_clock_type type)
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index 7c7c2d3440..8318e12795 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -91,7 +91,7 @@ static ID id_tv_sec;
 static ID id_tv_nsec;
 
 /**
- * grpc_rb_time_timeval creates a time_eval from a ruby time object.
+ * grpc_rb_time_timeval creates a timeval from a ruby time object.
  *
  * This func is copied from ruby source, MRI/source/time.c, which is published
  * under the same license as the ruby.h, on which the entire extensions is
@@ -137,7 +137,7 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
           d += 1;
           f -= 1;
         }
-        t.tv_sec = (time_t)f;
+        t.tv_sec = (gpr_int64)f;
         if (f != t.tv_sec) {
           rb_raise(rb_eRangeError, "%f out of Time range",
                    RFLOAT_VALUE(time));
diff --git a/test/core/iomgr/tcp_client_posix_test.c b/test/core/iomgr/tcp_client_posix_test.c
index a61cccdb02..833ceace54 100644
--- a/test/core/iomgr/tcp_client_posix_test.c
+++ b/test/core/iomgr/tcp_client_posix_test.c
@@ -234,8 +234,9 @@ void test_times_out(void) {
     if (gpr_time_cmp(now, finish_time) > 0) {
       break;
     }
-    gpr_log(GPR_DEBUG, "now=%d.%09d connect_deadline=%d.%09d", now.tv_sec,
-            now.tv_nsec, connect_deadline.tv_sec, connect_deadline.tv_nsec);
+    gpr_log(GPR_DEBUG, "now=%lld.%09d connect_deadline=%lld.%09d",
+            (long long)now.tv_sec, (int)now.tv_nsec,
+            (long long)connect_deadline.tv_sec, (int)connect_deadline.tv_nsec);
     if (is_after_deadline && gpr_time_cmp(now, restart_verifying_time) <= 0) {
       /* allow some slack before insisting that things be done */
     } else {
diff --git a/test/core/support/sync_test.c b/test/core/support/sync_test.c
index 6bc5f792e5..e538af93f2 100644
--- a/test/core/support/sync_test.c
+++ b/test/core/support/sync_test.c
@@ -272,7 +272,7 @@ static void test(const char *name, void (*body)(void *m),
     test_destroy(m);
   }
   time_taken = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), start);
-  fprintf(stderr, " done %ld.%09d s\n", (long)time_taken.tv_sec,
+  fprintf(stderr, " done %lld.%09d s\n", (long long)time_taken.tv_sec,
           (int)time_taken.tv_nsec);
 }
 
diff --git a/test/core/support/time_test.c b/test/core/support/time_test.c
index ce35edd83c..b921052e7b 100644
--- a/test/core/support/time_test.c
+++ b/test/core/support/time_test.c
@@ -98,7 +98,7 @@ static void test_values(void) {
   fprintf(stderr, "far future ");
   i_to_s(x.tv_sec, 16, 16, &to_fp, stderr);
   fprintf(stderr, "\n");
-  GPR_ASSERT(x.tv_sec >= INT_MAX);
+  GPR_ASSERT(x.tv_sec == INT64_MAX);
   fprintf(stderr, "far future ");
   ts_to_s(x, &to_fp, stderr);
   fprintf(stderr, "\n");
@@ -107,7 +107,7 @@ static void test_values(void) {
   fprintf(stderr, "far past   ");
   i_to_s(x.tv_sec, 16, 16, &to_fp, stderr);
   fprintf(stderr, "\n");
-  GPR_ASSERT(x.tv_sec <= INT_MIN);
+  GPR_ASSERT(x.tv_sec == INT64_MIN);
   fprintf(stderr, "far past   ");
   ts_to_s(x, &to_fp, stderr);
   fprintf(stderr, "\n");
-- 
GitLab