99 lines
1.7 KiB
C
99 lines
1.7 KiB
C
#include <c_timespec.h>
|
|||
|
|
#include <limits.h>
|
||
|
|
|
||
|
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
||
|
|
/* */
|
||
|
|
|
||
|
|
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
|
||
|
|
|