Subject: | "usleep( 1000000 )" does not sleep on NetBSD (while 999999 and 1000001 do) |
(copied more or less from NetBSD's issue 'pkg/46673'
(http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=46673):
ENVIRONMENT DETAILS:
- uname -a: NetBSD main.LAN 6.0_BETA2 NetBSD 6.0_BETA2 (GENERIC) amd64
- perl version: This is perl 5, version 14, subversion 2 (v5.14.2) built
for x86_64-netbsd-thread-multi
- module version: 1.972101 (1.9721p1 ?)
TESTED ON:
tested on NetBSD 6.0 BETA2 amd64 with Time::HiRes 1.972101, NetBSD 5.1
i386 with Time::HiRes 1.9719, and unknown NetBSD with Time::HiRes
1.9724; all expose this symptom.
Tested on unknown Linux with Time::HiRes 1.9711, which passes (see
'ANALYSIS').
TO REPRODUCE:
execute from shell:
perl -MTime::HiRes -e 'print Time::HiRes::usleep( 1000000 ) . "\n"'
Call seems to return immediately, sleeping around 3 us (as per
return-value).
Changing the argument to either 999999 or 1000001 correctly sleeps
around 1 second
ANALYSIS:
(sorry; sources from HiRes 1.9724, since sources for 1.972101 were
unavailable; I confirmed HiRes 1.9725 contains similar code-snippet.
However, tested and failed on NetBSD + HiRes 1.9724 on another system -
not mine - as listed in 'TESTED ON', above.)
From Time::HiRes 1.9724 (same version as in NetBSD's pkgsrc-2012Q1)
'HiRes.xs':
785 #if defined(HAS_USLEEP) && defined(HAS_GETTIMEOFDAY)
786
787 NV
788 usleep(useconds)
789 NV useconds
790 PREINIT:
791 struct timeval Ta, Tb;
792 CODE:
793 gettimeofday(&Ta, NULL);
794 if (items > 0) {
795 if (useconds > 1E6) {
796 IV seconds = (IV) (useconds / 1E6);
797 /* If usleep() has been implemented using setitimer()
798 * then this contortion is unnecessary-- but usleep()
799 * may be implemented in some other way, so let's contort. */
800 if (seconds) {
801 sleep(seconds);
802 useconds -= 1E6 * seconds;
803 }
804 } else if (useconds < 0.0)
805 croak("Time::HiRes::usleep(%"NVgf"): negative time not
invented yet", useconds);
806 usleep((U32)useconds);
807 } else
808 PerlProc_pause();
809 gettimeofday(&Tb, NULL);
810 #if 0
811 printf("[%ld %ld] [%ld %ld]\n", Tb.tv_sec, Tb.tv_usec, Ta.tv_sec,
Ta.tv_usec);
812 #endif
813 RETVAL =
1E6*(Tb.tv_sec-Ta.tv_sec)+(NV)((IV)Tb.tv_usec-(IV)Ta.tv_usec);
814
815 OUTPUT:
816 RETVAL
817
818 #if defined(TIME_HIRES_NANOSLEEP)
...it seems to me there is an off-by-one error in the check at line 795
for systems that provide usleep(); the check should be for
greater-or-equal than, instead of greater-than.
The usleep(3) on the 6.0 BETA2 system does not support sleep-times of 1M
us and more, as per manual, and returns an error when called with 1M as
argument.
Tested on a Linux system with Time::HiRes 1.9711 and an usleep(3) that
accepts arguments including and beyond 1M us (verified using C-program)
showed the desired behaviour for sleeping around 1 second when argument
to Time::HiRes::usleep is around 1M. I did not look at code of
Time::HiRes 1.9711.