diff --git a/lib/process_shared/posix/semaphore.rb b/lib/process_shared/posix/semaphore.rb index 11f9e9d..a1ef3a5 100644 --- a/lib/process_shared/posix/semaphore.rb +++ b/lib/process_shared/posix/semaphore.rb @@ -83,10 +83,6 @@ module ProcessShared sem_wait(@sem) end - NS_PER_S = 1e9 - US_PER_NS = 1000 - TV_NSEC_MAX = (NS_PER_S - 1) - # Decrement the value of the semaphore if it can be done # immediately (i.e. if it was non-zero). Otherwise, wait up to # +timeout+ seconds until another process increments via {#post}. @@ -100,24 +96,9 @@ module ProcessShared def try_wait(timeout = nil) if timeout now = TimeVal.new - abs_timeout = TimeSpec.new - LibC.gettimeofday(now, nil) - - abs_timeout[:tv_sec] = now[:tv_sec]; - abs_timeout[:tv_nsec] = now[:tv_usec] * US_PER_NS - - # add timeout in seconds to abs_timeout; careful with rounding - sec = timeout.floor - nsec = ((timeout - sec) * NS_PER_S).floor - - abs_timeout[:tv_sec] += sec - abs_timeout[:tv_nsec] += nsec - while abs_timeout[:tv_nsec] > TV_NSEC_MAX - abs_timeout[:tv_sec] += 1 - abs_timeout[:tv_nsec] -= NS_PER_S - end - + abs_timeout = now.to_time_spec + abs_timeout.add_seconds!(timeout) sem_timedwait(@sem, abs_timeout) else sem_trywait(@sem) diff --git a/lib/process_shared/posix/time_spec.rb b/lib/process_shared/posix/time_spec.rb index 36e36c6..246bf1f 100644 --- a/lib/process_shared/posix/time_spec.rb +++ b/lib/process_shared/posix/time_spec.rb @@ -1,8 +1,11 @@ require 'ffi' +require 'process_shared/time_spec' module ProcessShared module Posix class TimeSpec < FFI::Struct + include ProcessShared::TimeSpec + layout(:tv_sec, :time_t, :tv_nsec, :long) end diff --git a/lib/process_shared/posix/time_val.rb b/lib/process_shared/posix/time_val.rb index edac9df..cc856d4 100644 --- a/lib/process_shared/posix/time_val.rb +++ b/lib/process_shared/posix/time_val.rb @@ -1,10 +1,23 @@ require 'ffi' +require 'process_shared/posix/time_spec' + module ProcessShared module Posix class TimeVal < FFI::Struct + US_PER_NS = 1000 + layout(:tv_sec, :time_t, :tv_usec, :suseconds_t) + + def to_time_spec + ts = TimeSpec.new + + ts[:tv_sec] = self[:tv_sec]; + ts[:tv_nsec] = self[:tv_usec] * US_PER_NS + + ts + end end end end diff --git a/lib/process_shared/time_spec.rb b/lib/process_shared/time_spec.rb new file mode 100644 index 0000000..1bca648 --- /dev/null +++ b/lib/process_shared/time_spec.rb @@ -0,0 +1,22 @@ +module ProcessShared + module TimeSpec + NS_PER_S = 1e9 + US_PER_NS = 1000 + TV_NSEC_MAX = (NS_PER_S - 1) + + # Assuming self responds to setting the value of [:tv_sec] and + # [:tv_nsec], add +secs+ to the time spec. + def add_seconds!(float_sec) + # add timeout in seconds to abs_timeout; careful with rounding + sec = float_sec.floor + nsec = ((float_sec - sec) * NS_PER_S).floor + + self[:tv_sec] += sec + self[:tv_nsec] += nsec + while self[:tv_nsec] > TV_NSEC_MAX + self[:tv_sec] += 1 + self[:tv_nsec] -= NS_PER_S + end + end + end +end