@@ -175,73 +175,6 @@ func Time(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallC
175175 return uintptr (r ), nil , nil
176176}
177177
178- // clockNanosleepRestartBlock encapsulates the state required to restart
179- // clock_nanosleep(2) via restart_syscall(2).
180- //
181- // +stateify savable
182- type clockNanosleepRestartBlock struct {
183- c ktime.Clock
184- end ktime.Time
185- rem hostarch.Addr
186- }
187-
188- // Restart implements kernel.SyscallRestartBlock.Restart.
189- func (n * clockNanosleepRestartBlock ) Restart (t * kernel.Task ) (uintptr , error ) {
190- return 0 , clockNanosleepUntil (t , n .c , n .end , n .rem , true )
191- }
192-
193- // clockNanosleepUntil blocks until a specified time.
194- //
195- // If blocking is interrupted, the syscall is restarted with the original
196- // arguments.
197- func clockNanosleepUntil (t * kernel.Task , c ktime.Clock , end ktime.Time , rem hostarch.Addr , needRestartBlock bool ) error {
198- notifier , tchan := ktime .NewChannelNotifier ()
199- timer := ktime .NewTimer (c , notifier )
200-
201- // Turn on the timer.
202- timer .Swap (ktime.Setting {
203- Period : 0 ,
204- Enabled : true ,
205- Next : end ,
206- })
207-
208- err := t .BlockWithTimer (nil , tchan )
209-
210- timer .Destroy ()
211-
212- switch {
213- case linuxerr .Equals (linuxerr .ETIMEDOUT , err ):
214- // Slept for entire timeout.
215- return nil
216- case err == linuxerr .ErrInterrupted :
217- // Interrupted.
218- remaining := end .Sub (c .Now ())
219- if remaining <= 0 {
220- return nil
221- }
222-
223- // Copy out remaining time.
224- if rem != 0 {
225- timeleft := linux .NsecToTimespec (remaining .Nanoseconds ())
226- if err := copyTimespecOut (t , rem , & timeleft ); err != nil {
227- return err
228- }
229- }
230- if needRestartBlock {
231- // Arrange for a restart with the remaining duration.
232- t .SetSyscallRestartBlock (& clockNanosleepRestartBlock {
233- c : c ,
234- end : end ,
235- rem : rem ,
236- })
237- return linuxerr .ERESTART_RESTARTBLOCK
238- }
239- return linuxerr .ERESTARTNOHAND
240- default :
241- panic (fmt .Sprintf ("Impossible BlockWithTimer error %v" , err ))
242- }
243- }
244-
245178// Nanosleep implements linux syscall Nanosleep(2).
246179func Nanosleep (t * kernel.Task , args arch.SyscallArguments ) (uintptr , * kernel.SyscallControl , error ) {
247180 addr := args [0 ].Pointer ()
@@ -279,10 +212,12 @@ func ClockNanosleep(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kerne
279212 return 0 , nil , linuxerr .EINVAL
280213 }
281214
282- // Only allow clock constants also allowed by Linux.
215+ // Only allow clock constants also allowed by Linux. (CLOCK_TAI is
216+ // unimplemented.)
283217 if clockID > 0 {
284218 if clockID != linux .CLOCK_REALTIME &&
285219 clockID != linux .CLOCK_MONOTONIC &&
220+ clockID != linux .CLOCK_BOOTTIME &&
286221 clockID != linux .CLOCK_PROCESS_CPUTIME_ID {
287222 return 0 , nil , linuxerr .EINVAL
288223 }
@@ -301,6 +236,74 @@ func ClockNanosleep(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kerne
301236 return 0 , nil , clockNanosleepUntil (t , c , c .Now ().Add (dur ), rem , true )
302237}
303238
239+ // clockNanosleepUntil blocks until a specified time.
240+ //
241+ // If blocking is interrupted, the syscall is restarted with the original
242+ // arguments.
243+ func clockNanosleepUntil (t * kernel.Task , c ktime.Clock , end ktime.Time , rem hostarch.Addr , needRestartBlock bool ) error {
244+ var err error
245+ if c == t .Kernel ().MonotonicClock () {
246+ err = t .BlockWithDeadline (nil , true , end )
247+ } else {
248+ notifier , tchan := ktime .NewChannelNotifier ()
249+ timer := ktime .NewTimer (c , notifier )
250+ timer .Swap (ktime.Setting {
251+ Period : 0 ,
252+ Enabled : true ,
253+ Next : end ,
254+ })
255+ err = t .BlockWithTimer (nil , tchan )
256+ timer .Destroy ()
257+ }
258+
259+ switch {
260+ case linuxerr .Equals (linuxerr .ETIMEDOUT , err ):
261+ // Slept for entire timeout.
262+ return nil
263+ case err == linuxerr .ErrInterrupted :
264+ // Interrupted.
265+ remaining := end .Sub (c .Now ())
266+ if remaining <= 0 {
267+ return nil
268+ }
269+
270+ // Copy out remaining time.
271+ if rem != 0 {
272+ timeleft := linux .NsecToTimespec (remaining .Nanoseconds ())
273+ if err := copyTimespecOut (t , rem , & timeleft ); err != nil {
274+ return err
275+ }
276+ }
277+ if needRestartBlock {
278+ // Arrange for a restart with the remaining duration.
279+ t .SetSyscallRestartBlock (& clockNanosleepRestartBlock {
280+ c : c ,
281+ end : end ,
282+ rem : rem ,
283+ })
284+ return linuxerr .ERESTART_RESTARTBLOCK
285+ }
286+ return linuxerr .ERESTARTNOHAND
287+ default :
288+ panic (fmt .Sprintf ("Impossible BlockWithTimer error %v" , err ))
289+ }
290+ }
291+
292+ // clockNanosleepRestartBlock encapsulates the state required to restart
293+ // clock_nanosleep(2) via restart_syscall(2).
294+ //
295+ // +stateify savable
296+ type clockNanosleepRestartBlock struct {
297+ c ktime.Clock
298+ end ktime.Time
299+ rem hostarch.Addr
300+ }
301+
302+ // Restart implements kernel.SyscallRestartBlock.Restart.
303+ func (n * clockNanosleepRestartBlock ) Restart (t * kernel.Task ) (uintptr , error ) {
304+ return 0 , clockNanosleepUntil (t , n .c , n .end , n .rem , true )
305+ }
306+
304307// Gettimeofday implements linux syscall gettimeofday(2).
305308func Gettimeofday (t * kernel.Task , args arch.SyscallArguments ) (uintptr , * kernel.SyscallControl , error ) {
306309 tv := args [0 ].Pointer ()
0 commit comments