Time Functions

Every now and then, you'll find that in the midst of an application, you really need to know the time from the system clock. Even more likely, you need to have your application wait for a specific amount of time. Linux's timing functions are relatively straightforward; however, most people overlook them until they need to use one in an application.

Every now and then, you’ll find that in the midst of an application, you really need to know the time from the system clock. Even more likely, you need to have your application wait for a specific amount of time. Linux’s timing functions are relatively straightforward; however, most people overlook them until they need to use one in an application.

Since chance favors the prepared mind, we’re going to spend this month exploring the time functions provided by Linux and how to use them effectively. In next month’s column, we will delve more deeply into the Linux mechanism for keeping time and explore how each of these functions works.

Getting the Time

Linux provides three main system calls for obtaining the current time from the system: time(), ftime(), and gettimeofday(). Each provides essentially the same information but in varying degrees of accuracy and usability. The prototype for the time() function is as follows (as found in <time.h>):

time_t time (time_t *t);

This function takes in a pointer to a time_t and returns the time as type time_t. Taking a closer look at <time.h>, we see that a time_t is simply defined as the following:

typedef __time_t time_t;

Following the chain of typedefs (to discover the true type of time_t), we see that __time_t is simply defined (in <bits/types.h>) as:

typedef long int __time_t;

So, the time() function simply takes a pointer to a longint and returns a pointer to a longint. The value returned is the number of seconds elapsed since midnight, Greenwich Mean Time, on January 1st, 1970. This is the canonical “beginning of time” for most Unix systems today.

As a simple illustration, the program shown in Figure One will print out the number of seconds since January 1, 1970. Right now, this value is 988597918 on my machine, but by the time you read this, we will be very close to the 1 billion second mark. If my calculations are correct, we should hit that number on September 9, 2001 GMT. (Of course, where I live, this will actually be on September 8, but who’s counting?)

Figure One: Number of Seconds Since January 1, 1970

#include <time.h>

int main ()
printf (“%d\n”, time (NULL));

Notice in Figure One that we pass NULL to the time() function. You may pass a pointer to a time_t, and the time will not only be returned from the function, but it is also placed at that address.

For example, in Figure Two, we simply modify the code slightly to demonstrate this. The end result, of course, is exactly the same.

Figure Two: Number of Seconds Since January 1, 1970, Method Two

#include <time.h>

int main ()
time_t the_time;
time (&the_time);
printf (“%d\n”, the_time);

The ftime() function is slightly more sophisticated than the time() function. It allows you to retrieve information such as the current time zone, daylight savings information, as well as more precise time information (milliseconds instead of the somewhat coarsely grained seconds provided by the time() function.).

The prototype of the ftime() function as found in <sys/timeb.h> is:

int ftime (struct timeb *tp);

Although declared with a return value, this function always returns 0. To obtain information from it, you pass it a pointer to a structtimeb. The struct is defined in <sys/ timeb.h> as shown in Figure Three.

Figure Three: The timeb Struct

struct timeb
time_t time;
unsigned short int millitm;
short int timezone;
short int dstflag;

The first field, time, gives the time in seconds since January 1, 1970 just as the time() function returns. The second field, millitm, provides more accuracy in the timing mechanism by giving the milliseconds as well as seconds. The third field, timezone, gives you the timezone in which the current machine resides. This value is in minutes west of Greenwich Mean Time. The final field, dstflag, tells you whether or not the system has daylight savings time enabled. Its value is 1 if the system is using daylight savings time, 0 otherwise.

Figure Four gives an example program that uses the ftime function and prints out the information returned. It prints out the following information when run on my machine:

Figure Four: Using the ftime() Function

#include <sys/timeb.h>

int main ()
struct timeb the_time;
ftime (&the_time);
printf (“Number of seconds: %d\n”, the_time.time);
printf (“Number of milliseconds: %d\n”, the_time.millitm);
printf (“Time zone: %d\n”, the_time.timezone);
printf (“Daylight savings time: %d\n”, the_time.dstflag);

machine:~/> ./a.out
Number of seconds: 988600842
Number of milliseconds: 479
Time zone: 420
Daylight savings time: 0

This information gives me the time and the timezone (420 minutes, 7 hours, west of Greenwich Mean Time), and it states that this system is currently not using daylight savings time.

The final function that we will discuss regarding getting the time from the system is the gettimeofday() function. This function is very similar to the ftime() function except it provides even more precise time information. The prototype, as listed in <sys/time.h>, is as follows:

int gettimeofday (struct timeval *tv, structtimezone*tz);

Rather than providing one struct that contains the time, timezone, and daylight savings time, gettimeofday() takes two. The first struct (of type struct timeval) provides the time in seconds and microseconds. The second struct (of type struct timezone) provides the timezone and daylight savings time information. Figure Five shows a sample program that prints out similar information to the previous example with ftime().

Figure Five: Using the gettimeofday () Function

#include <sys/time.h>

int main ()
struct timeval the_time;
struct timezone the_zone;
gettimeofday (&the_time, &the_zone);
printf (“Number of seconds: %d\n”, the_time.tv_sec);
printf (“Number of microseconds: %d\n”, the_time.tv_usec);
printf (“Time zone: %d\n”, the_zone.tz_minuteswest);
printf (“Daylight savings time: %d\n”, the_zone.tz_dsttime);

Using the Time

Now that we’ve discussed the simple functions to get the system time in various forms, let’s take a quick look at an example of how to use one of these functions to cause a program to wait for a specified number of seconds. Figure Six shows a function that does just this.

Figure Six: A Function to Wait for Approximately num_seconds

void wait (int num_seconds)
time_t the_time = time (0);
while ((time (0) – the_time) < num_seconds + 1);

Notice that it simply gets the current time and then sits in a while loop, waiting until the difference in the original time and the current time is greater than one more than the number of seconds specified to the function. If you run a program that uses this function, you’ll notice that it actually waits for a random amount of time between the time you specify and one more second than that. This is due to the imprecise nature of the time() function. If you want to gain additional precision, the gettimeofday() function can be used.

A Better Way to Wait

Although it is possible to use the wait() function as shown above, this is not the most efficient method of waiting. This is because, while waiting, the program is performing needless operations. Fortunately, Linux provides some functions that allow you to wait for a specified amount of time without performing any operations.

The sleep() function in Linux makes the current process sleep for a given number of seconds, just as the wait() function we defined did. However, this function causes the program to wait without executing any instructions as our function does.

The prototype for the sleep() function as defined in <unistd.h> is as follows:

unsigned int sleep (unsigned int seconds);

As imprecise as the wait() function below, the sleep() function only guarantees that you will sleep for at least the number of seconds specified. For a more precise sleep function, see the man page for the function nanosleep().

You may be wondering how the sleep() function implements sleeping without performing needless operations, as our wait() function does. Let’s take a look at the source for the sleep function. It is found in the glibc source in the file, sysdeps/posix/sleep.c and shown in Figure Seven.

Figure Seven: Implementation of the sleep() Function in glibc

unsigned int
__sleep (unsigned int seconds)
unsigned int remaining, slept;
time_t before, after;
sigset_t set, oset;
struct sigaction act, oact;
int save = errno;

if (seconds == 0)
return 0;

/* Block SIGALRM signals while frobbing the handler. */
if (sigemptyset (&set) < 0 ||
sigaddset (&set, SIGALRM) < 0 ||
sigprocmask (SIG_BLOCK, &set, &oset))
return seconds;

act.sa_handler = sleep_handler;
act.sa_flags = 0;
act.sa_mask = oset; /* execute handler with original mask */
if (sigaction (SIGALRM, &act, &oact) < 0)
return seconds;

before = time ((time_t *) NULL);
remaining = alarm (seconds);

if (remaining > 0 && remaining < seconds)
/* The user’s alarm will expire before our own would.
Restore the user’s signal action state and let his alarm happen. */
(void) sigaction (SIGALRM, &oact, (struct sigaction *) NULL);
alarm (remaining); /* Restore sooner alarm. */
sigsuspend (&oset); /* Wait for it to go off. */
after = time ((time_t *) NULL);
/* Atomically restore the old signal mask
(which had better not block SIGALRM),
and wait for a signal to arrive. */
sigsuspend (&oset);

after = time ((time_t *) NULL);

/* Restore the old signal action state. */
(void) sigaction (SIGALRM, &oact, (struct sigaction *) NULL);

/* Notice how long we actually slept. */
slept = after – before;

/* Restore the user’s alarm if we have not already past it.
If we have, be sure to turn off the alarm in case a signal
other than SIGALRM was what woke us up. */
(void) alarm (remaining > slept ? remaining – slept : 0);

/* Restore the original signal mask. */
(void) sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);

/* Restore the ‘errno’ value we started with.
Some of the calls we made might have failed, but we didn’t care. */
__set_errno (save);

return slept > seconds ? 0 : seconds – slept;

The two calls of interest in this code are alarm() and sigsuspend(). The alarm() function simply tells the system to send a signal, SIGALRM, to the program after a given number of seconds. It’s prototype, as defined in <unistd.h>, is:

unsigned int alarm (unsigned int seconds);

The function returns immediately. Then, after the given number of seconds has elapsed, the system sends the SIGALRM signal to the application. (For a good review of signals, you can check out the Linux Magazine article from February 2000, http://www.linux-mag.com/2000-02/compile_01.html.) The sleep() function takes advantage of this by setting up a signal handler to catch the signal.

Once this is set up, the sleep()function will call the sigsuspend() function to suspend the current process until it receives a signal. The kernel manages the suspended processes and thus allows the sleep function to work without “busy-waiting” as our wait() function did. Since the sleep() function makes use of the alarm() function, it is unwise to use both of them simultaneously in your programs.

Aside from the ones mentioned above, there are other functions associated with keeping time in your applications. The getitimer() and setitimer() functions (found in <sys/time.h>) can be used to monitor time in more specific ways. For example, using these functions, you can track how long your process has been executing. (Note that all of the timing functions discussed above only address the actual time of the system.) Also, these functions allow you to set up repeating signals that automatically signal your program at regular intervals. For more information about these functions, see their man pages.

Looking Ahead

The functions we have discussed in this issue are relatively simple to understand; however, they leave many open questions. For example, how does the operating system keep track of the time (even when the machine is off)? What hardware is involved, and how specifically does Linux communicate with that hardware? How exactly does Linux manage to send signals between multiple processes?

We will be sure to address these “under the hood” questions in next month’s column, as we continue our discussion on time functions in Linux. In the interim, happy hacking…

Benjamin Chelf is an author and engineer at CodeSourcery, LLC. He can be reached at chelf@codesourcery.com.

Comments are closed.