Nanosleep does not work for values โ€‹โ€‹less than a second

I have a program (mixed C and Fortran, although that doesn't seem to be relevant) that uses nanosleep

. However, if mine timespec

is tv_sec

0, it just doesn't sleep. The value tv_nsec

can be microsecond shy of a full second, but it doesn't sleep. (If tv_sec

there is 1

, he has no problem sleeping for a second.) Why should it be?

To make things more confusing, usleep

with the appropriate value (i.e. 995000

usec) sleeps for about a second as expected.

I see this problem with RHEL 5.8 and RHEL 6.4. Both are using gcc

.

Here's the function that calls the drift:

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 really need nanosecond precision!

I also tested the version in which I checked the return value; it was always 0

(success) and therefore the output parameter rem

(time remaining if interrupted) was not set.

+3


source to share


3 answers


You are missing 1000.

Try the following:

#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, the full implementation, including error handling, and a case nanosleep()

that breaks first:

#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 == result);
  }

  if (result)
  {
    perror("nanosleep() failed");
    result = -1;
  }

  return result;
}

      

Following is a wrapper to fulfill 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("msleep() 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
  };

      

better to write like this:

  struct timespec ts_sleep = 
  {
    .tv_sec = *pmilliseconds / 1000,
    .tv_nsec = (*pmilliseconds % 1000) * 1000000L
  };

      

not to rely on the order of the members struct timespec

.

+7


source


I did it as shown 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;
}

      

0


source


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 better explained on the next page Convert milliseconds to timepec - GNU Port

0


source







All Articles