Bug 14484 - sem_timedwait always return -1 with errno 110 (ETIMEDOUT).
Summary: sem_timedwait always return -1 with errno 110 (ETIMEDOUT).
Status: RESOLVED INVALID
Alias: None
Product: glibc
Classification: Unclassified
Component: nptl (show other bugs)
Version: 2.11
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-08-17 05:19 UTC by tingweiliu
Modified: 2014-06-17 18:56 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments
C source code to test sem_timedwait function! (755 bytes, application/octet-stream)
2012-08-17 05:19 UTC, tingweiliu
Details

Note You need to log in before you can comment on or make changes to this bug.
Description tingweiliu 2012-08-17 05:19:46 UTC
Created attachment 6584 [details]
C source code to test sem_timedwait function!

gcc sem_timedwait.c -lrt -o sem_timedwait

./sem_timedwait

sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=5us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=3us
Comment 1 Rich Felker 2012-08-17 06:08:04 UTC
What output do you expect? Your test program is never posting the semaphore, so of course it's going to timeout. Actually when running it I get EINTR rather than ETIMEDOUT; I'm using a fairly old kernel so perhaps they fixed the kernel bug where timed semaphores error out with EINTR when receiving a signal instead of properly restarting the syscall.
Comment 2 tingweiliu 2012-08-17 06:21:19 UTC
(In reply to comment #1)
> What output do you expect? Your test program is never posting the semaphore, so
> of course it's going to timeout. Actually when running it I get EINTR rather
> than ETIMEDOUT; I'm using a fairly old kernel so perhaps they fixed the kernel
> bug where timed semaphores error out with EINTR when receiving a signal instead
> of properly restarting the syscall.
Function return with errno 4 not 110. The expected output should like:
sem_timedwait ret=-1 failed.errno=4 Real timeout=3948us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3929us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3958us
sem_timedwait ret=-1 failed.errno=4 Real timeout=4149us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3967us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3818us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3978us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3965us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3994us
sem_timedwait ret=-1 failed.errno=4 Real timeout=4035us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3910us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3982us
sem_timedwait ret=-1 failed.errno=4 Real timeout=4045us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3892us

Thanks!
Comment 3 tingweiliu 2012-08-17 06:25:45 UTC
(In reply to comment #1)
> What output do you expect? Your test program is never posting the semaphore, so
> of course it's going to timeout. Actually when running it I get EINTR rather
> than ETIMEDOUT; I'm using a fairly old kernel so perhaps they fixed the kernel
> bug where timed semaphores error out with EINTR when receiving a signal instead
> of properly restarting the syscall.

The abstimeout is correct (not earlier than now), so it should not return errno 110 (ETIMEDOUT).

Thanks!
Comment 4 tingweiliu 2012-08-17 06:31:09 UTC
(In reply to comment #1)
> What output do you expect? Your test program is never posting the semaphore, so
> of course it's going to timeout. Actually when running it I get EINTR rather
> than ETIMEDOUT; I'm using a fairly old kernel so perhaps they fixed the kernel
> bug where timed semaphores error out with EINTR when receiving a signal instead
> of properly restarting the syscall.
Can you tell me which reason will result in errno 110 ? 

My abstimeout really greater than now.

Thanks a lot!
Comment 5 Rich Felker 2012-08-20 01:41:02 UTC
As far as I can tell this report is invalid and is just a case of the reporter not understanding the interface. In particular, assuming the semaphore value is initially zero and it's never posted:

1. sem_timedwait should fail with ETIMEDOUT if the given time has already passed when it's called.

2. sem_timedwait should sleep until the given time, then fail with ETIMEDOUT, if the given time is in the future.

3. Signals that arrive during the wait should have no effect on sem_timedwait unless the handler was installed without the SA_RESTART option.

Note that point 3 is not honored on most (all?) Linux versions; syscalls with timeouts get interrupted with EINTR even if the signal handler was installed with SA_RESTART. This is a bug in Linux, not glibc, and is impossible to fix at the libc level.

If you still believe there's a glibc bug here, please explain what you expect the behavior to be in terms of the specification of the sem_timedwait function. As I've said, I can't see any bug...
Comment 6 tingweiliu 2012-08-21 06:06:58 UTC
(In reply to comment #5)
> As far as I can tell this report is invalid and is just a case of the reporter
> not understanding the interface. In particular, assuming the semaphore value is
> initially zero and it's never posted:
> 1. sem_timedwait should fail with ETIMEDOUT if the given time has already
> passed when it's called.
> 2. sem_timedwait should sleep until the given time, then fail with ETIMEDOUT,
> if the given time is in the future.
> 3. Signals that arrive during the wait should have no effect on sem_timedwait
> unless the handler was installed without the SA_RESTART option.
> Note that point 3 is not honored on most (all?) Linux versions; syscalls with
> timeouts get interrupted with EINTR even if the signal handler was installed
> with SA_RESTART. This is a bug in Linux, not glibc, and is impossible to fix at

   Maybe you should check the code in attachment.
   I have set a future time, and semaphore value is initially zero and it's never posted. So It should return with EINTR(errno=4).
   So anybody can tell me why it return with ETIMEOUT?




> the libc level.
> If you still believe there's a glibc bug here, please explain what you expect
> the behavior to be in terms of the specification of the sem_timedwait function.
> As I've said, I can't see any bug...
Comment 7 Rich Felker 2012-08-21 13:15:03 UTC
Your signal handler is not installed to be interrupting, so if sem_timedwait returns with EINTR (which it _DOES_ do on some/most Linux versions), that's a bug in the kernel. The expected result is ETIMEDOUT.

Perhaps you expect signal() to have the legacy sysv behavior of installing interrupting signal handlers. This is not the case on glibc. If you want interrupting behavior, you must use sigaction() and omit the SA_RESTART flag.

I still don't see any bug.
Comment 8 tingweiliu 2012-08-22 00:33:01 UTC
(In reply to comment #7)
> Your signal handler is not installed to be interrupting, so if sem_timedwait
> returns with EINTR (which it _DOES_ do on some/most Linux versions), that's a
> bug in the kernel. The expected result is ETIMEDOUT.
> Perhaps you expect signal() to have the legacy sysv behavior of installing
> interrupting signal handlers. This is not the case on glibc. If you want
> interrupting behavior, you must use sigaction() and omit the SA_RESTART flag.
> I still don't see any bug.

I have set the timeout = gettimeofday + 4000us , So if it return ETIMEDOUT, the real timeout should about 4000us.

But the output is:
#./sem_timedwait
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us

I think the Real timeout should about 4000us, but it's 4us. Why?

Thanks for your reply!
Comment 9 tingweiliu 2012-08-22 00:33:53 UTC
(In reply to comment #7)
> Your signal handler is not installed to be interrupting, so if sem_timedwait
> returns with EINTR (which it _DOES_ do on some/most Linux versions), that's a
> bug in the kernel. The expected result is ETIMEDOUT.
> Perhaps you expect signal() to have the legacy sysv behavior of installing
> interrupting signal handlers. This is not the case on glibc. If you want
> interrupting behavior, you must use sigaction() and omit the SA_RESTART flag.
> I still don't see any bug.

I have set the abstimeout = gettimeofday + 4000us , So if it return ETIMEDOUT, the real timeout should about 4000us.

But the output is:
#./sem_timedwait
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us

I think the Real timeout should about 4000us, but it's 4us. Why?

Thanks for your reply!
Comment 10 Rich Felker 2012-08-22 01:08:22 UTC
All your time calculation code is rather obfuscated and I haven't waded though it yet, but I suspect you're just confusing microseconds and nanoseconds. The fact that you're mixing interfaces that use timeval with ones that use timespec does not help. I would switch to using POSIX timespec interfaces for everything (timer_create for timers, clock_gettime for current time, etc.).

If it really is timing out early, this is probably due to the Linux kernel bug for signal handlers interrupting syscalls with timeouts.
Comment 11 tingweiliu 2012-08-22 05:20:34 UTC
(In reply to comment #10)
> All your time calculation code is rather obfuscated and I haven't waded though
> it yet, but I suspect you're just confusing microseconds and nanoseconds. The
> fact that you're mixing interfaces that use timeval with ones that use timespec
> does not help. I would switch to using POSIX timespec interfaces for everything
> (timer_create for timers, clock_gettime for current time, etc.).
> If it really is timing out early, this is probably due to the Linux kernel bug
> for signal handlers interrupting syscalls with timeouts.

OK...
Can you tell me why the output is different with the same system.(Linux 2.6.32)

gcc sem_timedwait.c -lrt -o sem_timedwait

One is like:
#./sem_timedwait
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us

Another is like:
#./sem_timedwait
sem_timedwait ret=-1 failed.errno=4 Real timeout=3948us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3929us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3958us
sem_timedwait ret=-1 failed.errno=4 Real timeout=4149us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3967us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3818us
Comment 12 tingweiliu 2012-08-22 05:23:46 UTC
(In reply to comment #10)
> All your time calculation code is rather obfuscated and I haven't waded though
> it yet, but I suspect you're just confusing microseconds and nanoseconds. The
> fact that you're mixing interfaces that use timeval with ones that use timespec
> does not help. I would switch to using POSIX timespec interfaces for everything
> (timer_create for timers, clock_gettime for current time, etc.).
> If it really is timing out early, this is probably due to the Linux kernel bug
> for signal handlers interrupting syscalls with timeouts.

OK...
Can you tell me why the output is different with the same system.(Linux 2.6.32)

gcc sem_timedwait.c -lrt -o sem_timedwait

One is like:
#./sem_timedwait
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us

Another is like:
#./sem_timedwait
sem_timedwait ret=-1 failed.errno=4 Real timeout=3948us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3929us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3958us
sem_timedwait ret=-1 failed.errno=4 Real timeout=4149us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3967us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3818us
Comment 13 tingweiliu 2012-08-22 05:28:44 UTC
(In reply to comment #10)
> All your time calculation code is rather obfuscated and I haven't waded though
> it yet, but I suspect you're just confusing microseconds and nanoseconds. The
> fact that you're mixing interfaces that use timeval with ones that use timespec
> does not help. I would switch to using POSIX timespec interfaces for everything
> (timer_create for timers, clock_gettime for current time, etc.).
> If it really is timing out early, this is probably due to the Linux kernel bug
> for signal handlers interrupting syscalls with timeouts.

OK...
Can you tell me why the output is different with the same system.(Linux 2.6.32)

gcc sem_timedwait.c -lrt -o sem_timedwait

One is like:
#./sem_timedwait
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us
sem_timedwait ret=-1 failed.errno=110 Real timeout=4us

Another is like:
#./sem_timedwait
sem_timedwait ret=-1 failed.errno=4 Real timeout=3948us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3929us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3958us
sem_timedwait ret=-1 failed.errno=4 Real timeout=4149us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3967us
sem_timedwait ret=-1 failed.errno=4 Real timeout=3818us
Comment 14 Andreas Schwab 2013-01-09 16:30:57 UTC
You define errno as a local variable in the delay function, thus your program has undefined behaviour.
Comment 15 tingweiliu 2013-01-10 05:03:01 UTC
(In reply to comment #14)
> You define errno as a local variable in the delay function, thus your program
> has undefined behaviour.

In my option, this is not the key reason!

Thanks for your reply!
Comment 16 tingweiliu 2013-01-10 05:03:31 UTC
(In reply to comment #14)
> You define errno as a local variable in the delay function, thus your program
> has undefined behaviour.

In my option, this is not the key reason!

Thanks for your reply!
Comment 17 Rich Felker 2014-06-17 18:56:25 UTC
Rereading the comments thread, I finally understand what the reporter's misunderstanding is. He seems to think ETIMEDOUT is ONLY for the case where the abstime passed to sem_timedwait is _already_ in the past at the time of the call, and that something else (EINTR?) should happen if sem_timedwait successfully begins waiting but then times out. This expectation is simply wrong. ETIMEDOUT is the correct error for both cases (and of course formally they are not demonstrably different since it's not observable whether a thread has actually entered the sem_timedwait or delayed prior to entry to the function due to scheduling).