This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Fix clock_nanosleep when interrupted by a signal



On 11/11/2019 14:30, Alistair Francis wrote:
> On Mon, Nov 11, 2019 at 8:35 AM Adhemerval Zanella
> <adhemerval.zanella@linaro.org> wrote:
>>
>> This patch fixes the time64 support (added by 2e44b10b42d) where it
>> misses the remaining argument updated if __NR_clock_nanosleep
>> returns EINTR.
>>
>> Checked on i686-linux-gnu on 4.15 kernel (no time64 support) and
>> on 5.3 kernel (with time64 support).
>>
>> Change-Id: Ie2d3ffdcf52a9a4f1e49466fd6abece31a7c7e69
> 
> Thanks for the fix!
> 
>> ---
>>  sysdeps/unix/sysv/linux/clock_nanosleep.c | 16 +++++++---------
>>  1 file changed, 7 insertions(+), 9 deletions(-)
>>
>> diff --git a/sysdeps/unix/sysv/linux/clock_nanosleep.c b/sysdeps/unix/sysv/linux/clock_nanosleep.c
>> index 60c61ee277..fc47c58ee7 100644
>> --- a/sysdeps/unix/sysv/linux/clock_nanosleep.c
>> +++ b/sysdeps/unix/sysv/linux/clock_nanosleep.c
>> @@ -52,13 +52,10 @@ __clock_nanosleep_time64 (clockid_t clock_id, int flags, const struct __timespec
>>    r = INTERNAL_SYSCALL_CANCEL (clock_nanosleep_time64, err, clock_id,
>>                                 flags, req, rem);
>>
>> -  if (r == 0 || errno != ENOSYS)
>> -    {
>> -      return (INTERNAL_SYSCALL_ERROR_P (r, err)
>> -              ? INTERNAL_SYSCALL_ERRNO (r, err) : 0);
>> -    }
>> +  if (r != -ENOSYS)
>> +    return (INTERNAL_SYSCALL_ERROR_P (r, err)
>> +            ? INTERNAL_SYSCALL_ERRNO (r, err) : 0);
>>  # endif /* __NR_clock_nanosleep_time64 */
> 
> Ok
> 
>> -  struct timespec ts32, tr32;
>>
>>    if (! in_time_t_range (req->tv_sec))
>>      {
>> @@ -66,11 +63,12 @@ __clock_nanosleep_time64 (clockid_t clock_id, int flags, const struct __timespec
>>        return -1;
>>      }
>>
>> -  ts32 = valid_timespec64_to_timespec (*req);
>> +  struct timespec tr32;
>> +  struct timespec ts32 = valid_timespec64_to_timespec (*req);
>>    r =  INTERNAL_SYSCALL_CANCEL (clock_nanosleep, err, clock_id, flags,
>>                                  &ts32, &tr32);
>>
>> -  if (r == 0 && rem != NULL)
>> +  if (r == -EINTR && rem != NULL && (flags & TIMER_ABSTIME) == 0)
>>      *rem = valid_timespec_to_timespec64 (tr32);
> 
> Don't we also need to set this if the call succeeded?

If the syscall succeeds it is implicit that sleep with input timeout argument
has happened and there is no remaining time.  And if I am reading the kernel
code correctly, this is what the syscall does:

*kernel/time/posix-timers.c

1208 SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
1209                 const struct __kernel_timespec __user *, rqtp,
1210                 struct __kernel_timespec __user *, rmtp)
1211 {
[...]
1227         current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
1228         current->restart_block.nanosleep.rmtp = rmtp;
1229 
1230         return kc->nsleep(which_clock, flags, &t);
1231 }
[...]

The RMTP output timespec is set on the current taks restart_block.

1197 /*
1198  * nanosleep for monotonic and realtime clocks
1199  */
1200 static int common_nsleep(const clockid_t which_clock, int flags,
1201                          const struct timespec64 *rqtp)
1202 {
1203         return hrtimer_nanosleep(rqtp, flags & TIMER_ABSTIME ?
1204                                  HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
1205                                  which_clock);
1206 }
[...]

* kernel/time/hrtimer.c

1862 static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode)           
1863 {  
1864         struct restart_block *restart;                                                       
1865    
1866         do {
1867                 set_current_state(TASK_INTERRUPTIBLE);
1868                 hrtimer_sleeper_start_expires(t, mode);                                      
1869            
1870                 if (likely(t->task))
1871                         freezable_schedule();                                                
1872            
1873                 hrtimer_cancel(&t->timer);                                                   
1874                 mode = HRTIMER_MODE_ABS;                                                     
1875    
1876         } while (t->task && !signal_pending(current));                                       
1877    
1878         __set_current_state(TASK_RUNNING);                                                   
1879    
1880         if (!t->task)
1881                 return 0;                                                                    
1882    
1883         restart = &current->restart_block;
1884         if (restart->nanosleep.type != TT_NONE) {
1885                 ktime_t rem = hrtimer_expires_remaining(&t->timer);                          
1886                 struct timespec64 rmt;                                                       
1887            
1888                 if (rem <= 0)
1889                         return 0;
1890                 rmt = ktime_to_timespec64(rem);                                              
1891            
1892                 return nanosleep_copyout(restart, &rmt);                                     
1893         }
1894         return -ERESTART_RESTARTBLOCK;                                                       
1895 }  
 
So the remaining timeout will be set iff the syscall has been interrupted
(rem > 0) and then nanosleep_copyout will copy out to userspace the remaining
time value.

So to mimic kernel behaviour we should update it only if it has been
interrupted.

> 
>>  #endif /* __ASSUME_TIME64_SYSCALLS */
>>
>> @@ -89,7 +87,7 @@ __clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req,
>>    treq64 = valid_timespec_to_timespec64 (*req);
>>    r = __clock_nanosleep_time64 (clock_id, flags, &treq64, &trem64);
>>
>> -  if (r == 0 && rem != NULL)
>> +  if (r == EINTR && rem != NULL && (flags & TIMER_ABSTIME) == 0)
>>      *rem = valid_timespec64_to_timespec (trem64);
> 
> Same with this one.
> 
> Alistair
> 
>>
>>    return r;
>> --
>> 2.17.1
>>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]