OLD | NEW |
(Empty) | |
| 1 #region Copyright notice and license |
| 2 // Copyright 2015-2016, Google Inc. |
| 3 // All rights reserved. |
| 4 // |
| 5 // Redistribution and use in source and binary forms, with or without |
| 6 // modification, are permitted provided that the following conditions are |
| 7 // met: |
| 8 // |
| 9 // * Redistributions of source code must retain the above copyright |
| 10 // notice, this list of conditions and the following disclaimer. |
| 11 // * Redistributions in binary form must reproduce the above |
| 12 // copyright notice, this list of conditions and the following disclaimer |
| 13 // in the documentation and/or other materials provided with the |
| 14 // distribution. |
| 15 // * Neither the name of Google Inc. nor the names of its |
| 16 // contributors may be used to endorse or promote products derived from |
| 17 // this software without specific prior written permission. |
| 18 // |
| 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 #endregion |
| 31 using System; |
| 32 using System.Runtime.InteropServices; |
| 33 using System.Threading; |
| 34 |
| 35 using Grpc.Core.Utils; |
| 36 |
| 37 namespace Grpc.Core.Internal |
| 38 { |
| 39 /// <summary> |
| 40 /// gpr_timespec from grpc/support/time.h |
| 41 /// </summary> |
| 42 [StructLayout(LayoutKind.Sequential)] |
| 43 internal struct Timespec |
| 44 { |
| 45 const long NanosPerSecond = 1000 * 1000 * 1000; |
| 46 const long NanosPerTick = 100; |
| 47 const long TicksPerSecond = NanosPerSecond / NanosPerTick; |
| 48 |
| 49 static readonly NativeMethods Native = NativeMethods.Get(); |
| 50 static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0
, DateTimeKind.Utc); |
| 51 |
| 52 public Timespec(long tv_sec, int tv_nsec) : this(tv_sec, tv_nsec, GPRClo
ckType.Realtime) |
| 53 { |
| 54 } |
| 55 |
| 56 public Timespec(long tv_sec, int tv_nsec, GPRClockType clock_type) |
| 57 { |
| 58 this.tv_sec = tv_sec; |
| 59 this.tv_nsec = tv_nsec; |
| 60 this.clock_type = clock_type; |
| 61 } |
| 62 |
| 63 private long tv_sec; |
| 64 private int tv_nsec; |
| 65 private GPRClockType clock_type; |
| 66 |
| 67 /// <summary> |
| 68 /// Timespec a long time in the future. |
| 69 /// </summary> |
| 70 public static Timespec InfFuture |
| 71 { |
| 72 get |
| 73 { |
| 74 return Native.gprsharp_inf_future(GPRClockType.Realtime); |
| 75 } |
| 76 } |
| 77 |
| 78 /// <summary> |
| 79 /// Timespec a long time in the past. |
| 80 /// </summary> |
| 81 public static Timespec InfPast |
| 82 { |
| 83 get |
| 84 { |
| 85 return Native.gprsharp_inf_past(GPRClockType.Realtime); |
| 86 } |
| 87 } |
| 88 |
| 89 /// <summary> |
| 90 /// Return Timespec representing the current time. |
| 91 /// </summary> |
| 92 public static Timespec Now |
| 93 { |
| 94 get |
| 95 { |
| 96 return Native.gprsharp_now(GPRClockType.Realtime); |
| 97 } |
| 98 } |
| 99 |
| 100 /// <summary> |
| 101 /// Seconds since unix epoch. |
| 102 /// </summary> |
| 103 public long TimevalSeconds |
| 104 { |
| 105 get |
| 106 { |
| 107 return tv_sec; |
| 108 } |
| 109 } |
| 110 |
| 111 /// <summary> |
| 112 /// The nanoseconds part of timeval. |
| 113 /// </summary> |
| 114 public int TimevalNanos |
| 115 { |
| 116 get |
| 117 { |
| 118 return tv_nsec; |
| 119 } |
| 120 } |
| 121 |
| 122 /// <summary> |
| 123 /// Converts the timespec to desired clock type. |
| 124 /// </summary> |
| 125 public Timespec ToClockType(GPRClockType targetClock) |
| 126 { |
| 127 return Native.gprsharp_convert_clock_type(this, targetClock); |
| 128 } |
| 129 |
| 130 /// <summary> |
| 131 /// Converts Timespec to DateTime. |
| 132 /// Timespec needs to be of type GPRClockType.Realtime and needs to repr
esent a legal value. |
| 133 /// DateTime has lower resolution (100ns), so rounding can occurs. |
| 134 /// Value are always rounded up to the nearest DateTime value in the fut
ure. |
| 135 /// |
| 136 /// For Timespec.InfFuture or if timespec is after the largest represent
able DateTime, DateTime.MaxValue is returned. |
| 137 /// For Timespec.InfPast or if timespec is before the lowest representab
le DateTime, DateTime.MinValue is returned. |
| 138 /// |
| 139 /// Unless DateTime.MaxValue or DateTime.MinValue is returned, the resul
ting DateTime is always in UTC |
| 140 /// (DateTimeKind.Utc) |
| 141 /// </summary> |
| 142 public DateTime ToDateTime() |
| 143 { |
| 144 GrpcPreconditions.CheckState(tv_nsec >= 0 && tv_nsec < NanosPerSecon
d); |
| 145 GrpcPreconditions.CheckState(clock_type == GPRClockType.Realtime); |
| 146 |
| 147 // fast path for InfFuture |
| 148 if (this.Equals(InfFuture)) |
| 149 { |
| 150 return DateTime.MaxValue; |
| 151 } |
| 152 |
| 153 // fast path for InfPast |
| 154 if (this.Equals(InfPast)) |
| 155 { |
| 156 return DateTime.MinValue; |
| 157 } |
| 158 |
| 159 try |
| 160 { |
| 161 // convert nanos to ticks, round up to the nearest tick |
| 162 long ticksFromNanos = tv_nsec / NanosPerTick + ((tv_nsec % Nanos
PerTick != 0) ? 1 : 0); |
| 163 long ticksTotal = checked(tv_sec * TicksPerSecond + ticksFromNan
os); |
| 164 return UnixEpoch.AddTicks(ticksTotal); |
| 165 } |
| 166 catch (OverflowException) |
| 167 { |
| 168 // ticks out of long range |
| 169 return tv_sec > 0 ? DateTime.MaxValue : DateTime.MinValue; |
| 170 } |
| 171 catch (ArgumentOutOfRangeException) |
| 172 { |
| 173 // resulting date time would be larger than MaxValue |
| 174 return tv_sec > 0 ? DateTime.MaxValue : DateTime.MinValue; |
| 175 } |
| 176 } |
| 177 |
| 178 /// <summary> |
| 179 /// Creates DateTime to Timespec. |
| 180 /// DateTime has to be in UTC (DateTimeKind.Utc) unless it's DateTime.Ma
xValue or DateTime.MinValue. |
| 181 /// For DateTime.MaxValue of date time after the largest representable T
imespec, Timespec.InfFuture is returned. |
| 182 /// For DateTime.MinValue of date time before the lowest representable T
imespec, Timespec.InfPast is returned. |
| 183 /// </summary> |
| 184 /// <returns>The date time.</returns> |
| 185 /// <param name="dateTime">Date time.</param> |
| 186 public static Timespec FromDateTime(DateTime dateTime) |
| 187 { |
| 188 if (dateTime == DateTime.MaxValue) |
| 189 { |
| 190 return Timespec.InfFuture; |
| 191 } |
| 192 |
| 193 if (dateTime == DateTime.MinValue) |
| 194 { |
| 195 return Timespec.InfPast; |
| 196 } |
| 197 |
| 198 GrpcPreconditions.CheckArgument(dateTime.Kind == DateTimeKind.Utc, "
dateTime needs of kind DateTimeKind.Utc or be equal to DateTime.MaxValue or Date
Time.MinValue."); |
| 199 |
| 200 try |
| 201 { |
| 202 TimeSpan timeSpan = dateTime - UnixEpoch; |
| 203 long ticks = timeSpan.Ticks; |
| 204 |
| 205 long seconds = ticks / TicksPerSecond; |
| 206 int nanos = (int)((ticks % TicksPerSecond) * NanosPerTick); |
| 207 if (nanos < 0) |
| 208 { |
| 209 // correct the result based on C# modulo semantics for negat
ive dividend |
| 210 seconds--; |
| 211 nanos += (int)NanosPerSecond; |
| 212 } |
| 213 return new Timespec(seconds, nanos); |
| 214 } |
| 215 catch (ArgumentOutOfRangeException) |
| 216 { |
| 217 return dateTime > UnixEpoch ? Timespec.InfFuture : Timespec.InfP
ast; |
| 218 } |
| 219 } |
| 220 |
| 221 /// <summary> |
| 222 /// Gets current timestamp using <c>GPRClockType.Precise</c>. |
| 223 /// Only available internally because core needs to be compiled with |
| 224 /// GRPC_TIMERS_RDTSC support for this to use RDTSC. |
| 225 /// </summary> |
| 226 internal static Timespec PreciseNow |
| 227 { |
| 228 get |
| 229 { |
| 230 return Native.gprsharp_now(GPRClockType.Precise); |
| 231 } |
| 232 } |
| 233 |
| 234 internal static int NativeSize |
| 235 { |
| 236 get |
| 237 { |
| 238 return Native.gprsharp_sizeof_timespec(); |
| 239 } |
| 240 } |
| 241 } |
| 242 } |
OLD | NEW |