Fortran call to sleep does not block program

Viewed 233

I have the most basic Fortran program:

program sleep
    print*, "Sleeping"
    call sleep(30)
    print*, "Done"
end program sleep

which I compile with gfortran sleep.f90 (version 9.3.0). From what I understood from the sleep documentation, this program is supposed to sleep for 30 seconds, i.e. I should expect to see "Done" being printed 30 seconds after "Sleeping". This doesn't happen: I see both print statements appearing instantaneously, suggesting that call sleep(30) does not block my program in any way. Doing call sleep(10000) didn't make any difference. I am compiling and running this program on a Windows Subsystem for Linux (WSL Ubuntu 20.04).

2 Answers

So this problem was fixed through a combination of solutions suggested by @roygvib in the comments. The main issue is that sleep in the WSL (Ubuntu 20.04) environment is broken. The first step is to replace the broken /usr/bin/sleep with this Python script:

#!/usr/bin/env python3

import sys
import time

time.sleep(int(sys.argv[1]))

Then, the Fortran program is modified to make a system call to this new sleep executable:

program sleep
    print*, "Sleeping"
    call system("sleep 30")
    print*, "Done"
end program sleep

Until the next update of WSL, this hack will have to do.

The sleep procedure is not part of the Fortran standard and non-portable. Here is a solution that would potentially work on all systems with any standard-compliant Fortran compiler:

module sleep_mod

    use, intrinsic :: iso_fortran_env, only: IK => int64, RK => real64, output_unit
    implicit none

contains

    subroutine sleep(seconds)

        implicit none

        real(RK), intent(in) :: seconds ! sleep time
        integer(IK)          :: countOld, countNew, countMax
        real(RK)             :: countRate

        call system_clock( count=countOld, count_rate=countRate, count_max=countMax )
        if (countOld==-huge(0_IK) .or. nint(countRate)==0_IK .or. countMax==0_IK) then
            write(output_unit,"(A)") "Error occurred. There is no processor clock."
            error stop
        end if

        countRate = 1._RK / countRate
        do
            call system_clock( count=countNew )
            if (countNew==countMax) then
                write(output_unit,"(A)") "Error occurred. Maximum processor clock count reached."
                error stop
            end if
            if ( real(countNew-countOld,kind=RK) * countRate > seconds ) exit
            cycle
        end do

    end subroutine sleep

end module sleep_mod

program main
    use sleep_mod, only: output_unit, sleep, RK
    implicit none
    write(output_unit,"(A)") "Sleep for 5 second."
    call execute_command_line(" ") ! flush stdout
    call sleep(seconds = 5._RK)
    write(output_unit,"(A)") "Wake up."
end program main

You can test it online here: https://www.tutorialspoint.com/compile_fortran_online.php

Related