Reputation: 5823
I have a program (mixed C and Fortran, although that doesn't seem to be relevant) that uses nanosleep
. However, if my timespec
has a tv_sec
value of 0, it simply doesn't sleep. The tv_nsec
value can be microseconds shy of a full second, but it does not sleep. (If tv_sec
is 1
, it has no problem sleeping for a second.) Why would this be?
To make things more confusing, usleep
with an appropriate value (i.e. 995000
usec) sleeps for just about a second as expected.
I'm seeing this problem with a RHEL 5.8 and a RHEL 6.4 box. Both are using gcc
.
Here's the function that calls nanosleep:
void msleep(int *milliseconds)
{
long usec;
struct timespec sleep;
usec = (*milliseconds) % 1000;
sleep.tv_sec = (*milliseconds) / 1000;
sleep.tv_nsec = 1000*usec;
nanosleep(&sleep, NULL);
}
Obviously, I don't actually need nanosecond precision!
I've also tested a version in which I did check the return value; it was always 0
(success), and thus the rem
output parameter (remaining time if interrupted) never got set.
Upvotes: 3
Views: 9412
Reputation: 70951
You are missing a factor of 1000.
Try this:
#define _POSIX_C_SOURCE 199309L /* shall be >= 199309L */
#include <time.h>
void msleep(int *milliseconds)
{
int ms_remaining = (*milliseconds) % 1000;
long usec = ms_remaining * 1000;
struct timespec ts_sleep;
ts_sleep.tv_sec = (*milliseconds) / 1000;
ts_sleep.tv_nsec = 1000*usec;
nanosleep(&ts_sleep, NULL);
}
More compact:
#define _POSIX_C_SOURCE 199309L /* shall be >= 199309L */
#include <time.h>
void msleep(int * pmilliseconds)
{
struct timespec ts_sleep =
{
*pmilliseconds / 1000,
(*pmilliseconds % 1000) * 1000000L
};
nanosleep(&ts_sleep, NULL);
}
Finally a complete implementation including error handling and the case of nanosleep()
being interrupted early:
#define _POSIX_C_SOURCE 199309L
#include <time.h>
#include <errno.h>
#include <stdio.h>
int ms_sleep(unsigned int ms)
{
int result = 0;
{
struct timespec ts_remaining =
{
ms / 1000,
(ms % 1000) * 1000000L
};
do
{
struct timespec ts_sleep = ts_remaining;
result = nanosleep(&ts_sleep, &ts_remaining);
}
while ((EINTR == errno) && (-1 == result));
}
if (-1 == result)
{
perror("nanosleep() failed");
}
return result;
}
Following a wrapper to fulfil the OP's requirements:
#include <errno.h>
#include <stdio.h>
int ms_sleep(unsigned int);
void msleep(int * pms)
{
int result = 0;
if ((NULL == pms) || (0 > *pms)) /* Check for valid input. */
{
errno = EINVAL;
result = -1;
}
else
{
result = ms_sleep(*pms));
}
if (-1 == result)
{
perror("ms_sleep() failed");
/* Exit and/or log error here. */
}
}
Update (referring to chux's comment below):
Assuming at least C99, this part of the above code
struct timespec ts_sleep =
{
*pmilliseconds / 1000,
(*pmilliseconds % 1000) * 1000000L
};
might better be written like this
struct timespec ts_sleep =
{
.tv_sec = *pmilliseconds / 1000,
.tv_nsec = (*pmilliseconds % 1000) * 1000000L
};
to not rely on the order of struct timespec
's members.
Upvotes: 8
Reputation: 5297
Here is the method
static void Sleep(long lMs){
//Calculate the nanosecond
long lRemainingMilliSecond = (lMs) % 1000;
long lNanoSecond = lRemainingMilliSecond * 1000000;
struct timespec ts_sleep,ts_remaining;
ts_sleep.tv_sec = (lMs) / 1000;
ts_sleep.tv_nsec = lNanoSecond;
nanosleep(&ts_sleep, &ts_remaining);
}
The concept is explained better in the following page Convert milliseconds to timespec - GNU Porting
Upvotes: 0
Reputation: 565
I did it like below and it worked...
#include <stdio.h>
#include <time.h> /* Needed for struct timespec */
int nsleep(long miliseconds)
{
struct timespec req, rem;
if(miliseconds > 999)
{
req.tv_sec = (int)(miliseconds / 1000); /* Must be Non-Negative */
req.tv_nsec = (miliseconds - ((long)req.tv_sec * 1000)) * 1000000; /* Must be in range of 0 to 999999999 */
}
else
{
req.tv_sec = 0; /* Must be Non-Negative */
req.tv_nsec = miliseconds * 1000000; /* Must be in range of 0 to 999999999 */
}
return nanosleep(&req , &rem);
}
int main()
{
int ret = nsleep(2500);
printf("sleep result %d\n",ret);
return 0;
}
Upvotes: 0