#include #include /* ------------------------------------------------------------------------------------------------------------------ */ /* */ struct timespec c_timespec_mod(struct timespec ts1, struct timespec ts2) { int i = 0; bool neg1 = false; bool neg2 = false; /* Normalise inputs to prevent tv_nsec rollover if whole-second values * are packed in it. */ ts1 = c_timespec_normalise(ts1); ts2 = c_timespec_normalise(ts2); /* If ts2 is zero, just return ts1 */ if (ts2.tv_sec == 0 && ts2.tv_nsec == 0) { return ts1; } /* If inputs are negative, flip and record sign */ if (ts1.tv_sec < 0 || ts1.tv_nsec < 0) { neg1 = true; ts1.tv_sec = -ts1.tv_sec; ts1.tv_nsec = -ts1.tv_nsec; } if (ts2.tv_sec < 0 || ts2.tv_nsec < 0) { neg2 = true; ts2.tv_sec = -ts2.tv_sec; ts2.tv_nsec = -ts2.tv_nsec; } /* Shift ts2 until it is larger than ts1 or is about to overflow */ while ((ts2.tv_sec < (LONG_MAX >> 1)) && c_timespec_ge(ts1, ts2)) { i++; ts2.tv_nsec <<= 1; ts2.tv_sec <<= 1; if (ts2.tv_nsec > C_NSEC_PER_SEC) { ts2.tv_nsec -= C_NSEC_PER_SEC; ts2.tv_sec++; } } /* Division by repeated subtraction */ while (i >= 0) { if (c_timespec_ge(ts1, ts2)) { ts1 = c_timespec_sub(ts1, ts2); } if (i == 0) { break; } i--; if (ts2.tv_sec & 1) { ts2.tv_nsec += C_NSEC_PER_SEC; } ts2.tv_nsec >>= 1; ts2.tv_sec >>= 1; } /* If signs differ and result is nonzero, subtract once more to cross zero */ if (neg1 ^ neg2 && (ts1.tv_sec != 0 || ts1.tv_nsec != 0)) { ts1 = c_timespec_sub(ts1, ts2); } /* Restore sign */ if (neg1) { ts1.tv_sec = -ts1.tv_sec; ts1.tv_nsec = -ts1.tv_nsec; } return ts1; }