Incorrect time_t value from time() in signal handler

S

Sven

Hi,

I found a strange behaviour when using the time() function from time.h.
Sometimes when it is called, it does not show the correct time in
seconds, but an initial value. This time seem to be the time when the
program was started the first time.

My platform is a DEC machine with Tru64 onboard.

A possible explanation could be, that the time() function is called
within a signal handler. The program uses a SIGTIME to run regularly
through a procedure. There some log entries with time stamp are done.
These time stamps are sometimes wrong.

My question is, if someone knows, under which circumstances the time()
function can produce incorrect values and if there are some side
effects.

Thanks in advance,
Sven Bauhan
 
A

Ancient_Hacker

Sven said:
Hi,

I found a strange behaviour when using the time() function from time.h.
Sometimes when it is called, it does not show the correct time in
seconds, but an initial value. This time seem to be the time when the
program was started the first time.

My platform is a DEC machine with Tru64 onboard.

A possible explanation could be, that the time() function is called
within a signal handler. The program uses a SIGTIME to run regularly
through a procedure. There some log entries with time stamp are done.
These time stamps are sometimes wrong.

My question is, if someone knows, under which circumstances the time()
function can produce incorrect values and if there are some side
effects.

Thanks in advance,
Sven Bauhan


not a C question per se, but :

Are you linking this with the thread-safe library? Anytime you have
asynchronous signals going off, you need a thread-safe (or actually,
reentrant-safe) program and library.

Also note that time() returns its value in a static location. If
you're doing this inside the timer signal function, you may be
overwriting the time value you got in other places.


Also are you checking the return value to see if it is returning an
error code ((time_t)-1) ??

Sometimes when you have signals going off, library routines and system
calls return INTERRUPTED_SYSTEM_CALL at random times. You have to
assume every call might fail, and check for failure. Many library and
system calls that don't fail normally can fail if you have timers going
off. Try disabling your timers and see if the time() problem goes
away. That would point you to this being a timer signal related
problem.
 
X

XSPD

I have some problems with signal handling too.

Using a fprintf() call for tracing (of course with getting an
additional time information), the system (Fedora FC3) will get into a
deadlock situation, because the fprintf() will call an internal mutual
exclusion locking (mutex-operation). We got quite a similar situation
at SUN/solaris.

A good proposal is, never call any system function out of a signal
handler. Set a global flag or counter instead, and check the global
flag/counter at a main loop (if you have any).

I don't know, if the thread-safe functions can solve this problem.
 
S

Sven

Ancient_Hacker said:
Are you linking this with the thread-safe library? Anytime you have
asynchronous signals going off, you need a thread-safe (or actually,
reentrant-safe) program and library.
How do I have to do this? Is this just a linker option?
Also note that time() returns its value in a static location. If
you're doing this inside the timer signal function, you may be
overwriting the time value you got in other places.
That is no problem, I call:
time_t tVal;
time( &tVal );
Also are you checking the return value to see if it is returning an
error code ((time_t)-1) ??
I saw this, but what does ((time_t)-1) mean?
Is this the value given in the parameter decreased by one?
time_t tVal = 1;
if ( ! time( &tVal ) ) { /* error */ }

I cannot leave the timer away, because without the timer the program
would make no more sense.

Sven
 
A

Ancient_Hacker

Sven said:
How do I have to do this? Is this just a linker option?

it's often a compiler option, so it generates thread-sfe code and it
often passes on the name of the thread-safe library to the linker.
Look in your compiler and linker options for "thread safe"


I saw this, but what does ((time_t)-1) mean?

No, it's (-1) coerced into type size_t. A hobibble klooge, but it
works.

you want to write:
if( time( &val ) == ( (size_t) -1 ) ) { printf("time() failed!!, err
= %d\n", errno );

I cannot leave the timer away, because without the timer the program
would make no more sense.


well, you could call the timer function yourself from the main program,
in a loop. That would simulate everyting except the asynchronous
nature of the timer signals, which is what we want to try eliminating
as a suspect.
 
?

=?ISO-8859-1?Q?=22Nils_O=2E_Sel=E5sdal=22?=

XSPD said:
I have some problems with signal handling too.

Using a fprintf() call for tracing (of course with getting an
additional time information), the system (Fedora FC3) will get into a
deadlock situation, because the fprintf() will call an internal mutual
exclusion locking (mutex-operation). We got quite a similar situation
at SUN/solaris.
A good proposal is, never call any system function out of a signal
handler. Set a global flag or counter instead, and check the global
flag/counter at a main loop (if you have any).

I don't know, if the thread-safe functions can solve this problem.
No. You can only call asynch-signal safe functions from within
a signal handler on posix platforms (which is offtopic here though, sorry).

http://www.opengroup.org/onlinepubs/000095399/functions/xsh_chap02_04.html#tag_02_04_03
lists the safe functions to call from a signal handler.
 
R

Rudolf

"Ancient_Hacker said:
Sven wrote:

No, it's (-1) coerced into type size_t. A hobibble klooge, but it
works.


Are time_t and size_t the same thing? Will casting -1 to size_t give
the same result as casting -1 to time_t?
 
W

Walter Roberson

Rudolf said:
Are time_t and size_t the same thing?
No.

Will casting -1 to size_t give
the same result as casting -1 to time_t?

That's platform dependant, but the answer is usually NO.

time_t is often a signed integral type, whereas size_t is always
unsigned.

time_t is often a 32 bit number, whereas there are several important
platforms where size_t is 64 bits.
 
K

Keith Thompson

Ancient_Hacker said:
Also note that time() returns its value in a static location. If
you're doing this inside the timer signal function, you may be
overwriting the time value you got in other places.

No it doesn't. time() returns a value of time time_t, which is an
arithmetic type. You can optionally pass it a non-null pointer to a
time_t object, to which it will store the same value.

If you're careless about the pointer value you pass to time(), you
could run into problems, but if you just call it as time(NULL) there's
no problem.

OP: You have a "#include <time.h>", right?

I've never heard of the time() function working incorrectly (unless
the system clock is set incorrectly). Could it be a bug in your
program?
 
K

Keith Thompson

Sven said:
Ancient_Hacker wrote: [...]
Also note that time() returns its value in a static location. If
you're doing this inside the timer signal function, you may be
overwriting the time value you got in other places.
That is no problem, I call:
time_t tVal;
time( &tVal );

The pointer argument to time() is a relic of ancient implementations.
It's simpler IMHO just to do:
tVal = time(NULL);
but either method will work.
I saw this, but what does ((time_t)-1) mean?
Is this the value given in the parameter decreased by one?
time_t tVal = 1;
if ( ! time( &tVal ) ) { /* error */ }

No, it's the numeric value -1 converted to time_t. The "(time_t)" is
a cast operator, specifying the conversion.
I cannot leave the timer away, because without the timer the program
would make no more sense.

Calling time() is not one of the things that the C standard says you
can safely do from a signal handler. <OT>Your implementation may make
additional guarantees.</OT>

C99 7.14.1.1p5:

If the signal occurs other than as the result of calling the abort
or raise function, the behavior is undefined if the signal handler
refers to any object with static storage duration other than by
assigning a value to an object declared as volatile sig_atomic_t,
or the signal handler calls any function in the standard library
other than the abort function, the _Exit function, or the signal
function with the first argument equal to the signal number
corresponding to the signal that caused the invocation of the
handler. Furthermore, if such a call to the signal function
results in a SIG_ERR return, the value of errno is indeterminate.

The behavior you're apparently seeing, of time() returning an
incorrect value, is odd but permitted. If possible, set a flag in
your signal hanlder by assigning a value to a static object of type
volatile sig_atomic_t, and do all the other processing outside the
signal handler.
 
K

Keith Thompson

Ancient_Hacker said:
Sven wrote: [...]
I saw this, but what does ((time_t)-1) mean?

No, it's (-1) coerced into type size_t. A hobibble klooge, but it
works.

you want to write:
if( time( &val ) == ( (size_t) -1 ) ) { printf("time() failed!!, err
= %d\n", errno );

The cast should be to time_t, not size_t.

For that matter, I don't think the cast is necessary (unless I'm
missing some subtle effect of type promotion).
 
W

Walter Roberson

I found a strange behaviour when using the time() function from time.h.
Sometimes when it is called, it does not show the correct time in
seconds, but an initial value.
A possible explanation could be, that the time() function is called
within a signal handler. The program uses a SIGTIME to run regularly
through a procedure. There some log entries with time stamp are done.
These time stamps are sometimes wrong.

Your posting could be interpreted as indicating that the log entries
with time stamp are being generated by a system or library call
within the signal handler. If that is the case, then the results
are very much undefined according to the C standards, and the
calls are unsafe according to POSIX.1 .

According to the C standards, the only safe write operation inside a
signal handler is to change a variable of type volatile sig_atomic_t .
Also, according to the C standard, the only library call that is
certain to be safe within a signal handler is signal() itself.
In particular, the C standard offers no exemption for time() --
calling time() within a signal handler is undefined behaviour
according to the C standard.

POSIX.1 extends C to offer several other safe library calls within
signal handlers, specifically including time(). However, none
of the safe calls include any I/O at all.
 
K

Keith Thompson

Rudolf said:
Are time_t and size_t the same thing? Will casting -1 to size_t give
the same result as casting -1 to time_t?

They can be the same type, but there's no reason to assume that they
will be. I'm sure "size_t" was just a typo for "time_t".
 
A

Ancient_Hacker

Keith said:
Ancient_Hacker said:
Sven wrote: [...]
I saw this, but what does ((time_t)-1) mean?

No, it's (-1) coerced into type size_t. A hobibble klooge, but it
works.

you want to write:
if( time( &val ) == ( (size_t) -1 ) ) { printf("time() failed!!, err
= %d\n", errno );

The cast should be to time_t, not size_t.

For that matter, I don't think the cast is necessary (unless I'm
missing some subtle effect of type promotion).


Won't many compilers complain with a warning about "comparing signed
and unsigned types"? It's just a warning as at run-time the
bit-patterns are probably identical, but as you suggest, maybe in some
cases 16 bits of -1 get sometimes promoted to 65535 and doesnt compare
with a true -1. Been bitten by that many times.
 
P

Philip Guenther

Walter Roberson wrote:
....
POSIX.1 extends C to offer several other safe library calls within
signal handlers, specifically including time(). However, none
of the safe calls include any I/O at all.

Umm, the core POSIX file-descriptor-based I/O functions are
async-signal-safe, including open(), write(), read(), lseek(), and
close().

I don't have a link for the original POSIX.1 spec, but here's the list
for IEEE Std 1003.1, 2004:

http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html

Philip Guenther
 
J

Jack Klein

Walter Roberson wrote:
...

Umm, the core POSIX file-descriptor-based I/O functions are
async-signal-safe, including open(), write(), read(), lseek(), and
close().

The core POSIX file descriptor based functions are not part of the C
language or library and are 100% off-topic here.
 
M

Mikhail Teterin

Keith said:
The behavior you're apparently seeing, of time() returning an
incorrect value, is odd but permitted. šIf possible, set a flag in
your signal hanlder by assigning a value to a static object of type
volatile sig_atomic_t, and do all the other processing outside the
signal handler.

I would think, that for a program (potentially) logging tons of lines per
second (such as a busy web-proxy or server), it is more efficient to set
the SIGALRM-handler to a function, that would update the static time_t
variable once per second.

That static variable could then be used by the logging function instead of
calling time() for every line logged many times per second (unless, of
course, the precision of the timestamp must be finer than a second).

Now, assuming that sig_atomic_t is as wide (or wider) as time_t, this can be
achieved by simply incrementing the variable once per second.

However, unless working on a RealTime OS, the signal may not, actually,
arrive at the exact time specified, and may, in fact, be delayed by many
seconds. So time() will need to be called at least occasionally to
readjust/catch up, if not every second -- as, I suspect, the original
poster is doing.

Syscalls are relatively expensive and software like web-proxies and
web-servers are frequently benchmarked -- even a small gain can make a
winner...

How can this be done (semi-)portably?

-mi
 
K

Keith Thompson

Mikhail Teterin said:
I would think, that for a program (potentially) logging tons of lines per
second (such as a busy web-proxy or server), it is more efficient to set
the SIGALRM-handler to a function, that would update the static time_t
variable once per second.

Possibly, but SIGALRM isn't one of the signals guaranteed by the C
standard. (The ones guaranteed to exist are SIGABRT, SIGFPE, SIGILL,
SIGINT, SIGSEGV, and SIGTERM.)
That static variable could then be used by the logging function instead of
calling time() for every line logged many times per second (unless, of
course, the precision of the timestamp must be finer than a second).

Now, assuming that sig_atomic_t is as wide (or wider) as time_t, this can be
achieved by simply incrementing the variable once per second.

That's not guaranteed either. C99 7.18.3p3:

If sig_atomic_t (see 7.14) is defined as a signed integer type,
the value of SIG_ATOMIC_MIN shall be no greater than -127 and the
value of SIG_ATOMIC_MAX shall be no less than 127; otherwise,
sig_atomic_t is defined as an unsigned integer type, and the value
of SIG_ATOMIC_MIN shall be 0 and the value of SIG_ATOMIC_MAX shall
be no less than 255.

[...]
How can this be done (semi-)portably?

It probably can't, but I'm sure there are plenty of non-portable
solutions.
 
C

Chris Torek

The cast should be to time_t, not size_t.

[thus giving

time(&val) == (time_t)-1

for the test for failure.]
For that matter, I don't think the cast is necessary (unless I'm
missing some subtle effect of type promotion).

In any "real" system, probably not. But suppose time_t is defined
"unsigned short", with USHRT_MAX being 4294967295, while INT_MAX
is 9223372036854775807. Then:

(USHRT_MAX)-1 == (time_t)-1

means:

(int)4294967295 == (int)4294967295

while:

(USHRT_MAX)-1 == -1

means:

(int)4294967295 == (int)-1

which is of course always false.

(Personally, I find the ANSI/ISO "value preserving" rules really
nasty, since they require a lot more case-by-case reasoning with
both Uxxx_MAX <= INT_MAX and Uxxx_MAX > INT_MAX. In this case, I
think it works out the same anyway, though: with the "sensible"
rule -- in which unsigned-ness overrides -- instead of the Standard's
rule ("signed, unsigned, who can tell?") -- the last comparison
would be 4294967295U == 18446744073709551615U.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top