Idioms for separating out OS-specific stuff


#1

I have a few functions that:

  • get the current user’s login name
  • checks to see what the CPU % of a process is (non the Ruby
    process, another process). This includes all the threads that the
    process has
  • forks a new process
  • sees if a process is still running
  • gets the utilization percentage of a NIC on the machine
  • the load average of the machine
  • the number of CPUs on a given machine

This is all working fine on Linux with kernel 2.4. However, the code
doesn’t quite run correctly on a 2.6 kernel (not sure why yet). And
forget about OS X and Windows and *BSD.

Are there any good Ruby idioms for managing the separate OS-specific
functions?

My first thought:
module SystemSpecificMethods
module Linux
# generic linux functions in here

module 2.4
  # linux 2.4 functions in here
end

module 2.6
  # linux 2.6 functions in here
end

end

module Windows
# Windows functions here
end

module BSD
# OS X and maybe *BSD functions here
end
end

And then probe (somwhow?) to figure out what OS I’m running on and
then including the correct modules into my code. So, if I were using
Linux 2.6, I’d include SystemSpecificFunctions::Linux and
SystemSpecificFunctions::Linux::2.6.

But I’m sure that’s a pretty dumb way of doing it, as I’m not terribly
bright.

Joe


#2

On Mar 8, 2006, at 4:18 PM, Joe Van D. wrote:

And then probe (somwhow?) to figure out what OS I’m running on and
then including the correct modules into my code.

As far as probing goes…

irb(main):026:0> Config::CONFIG[‘host_os’]
=> “darwin8.4.0”
irb(main):027:0> Config::CONFIG[‘arch’]
=> “powerpc-darwin8.4.0”

etc.

You can also try shelling out and calling uname, but that of course
won’t work on windows for example.

logan:/Users/logan% uname -s
Darwin
logan:/Users/logan% uname -r
8.5.0
logan:/Users/logan% uname -v
Darwin Kernel Version 8.5.0: Sun Jan 22 10:38:46 PST 2006;
root:xnu-792.6.61.obj~1/RELEASE_PPC
logan:/Users/logan% uname -a
Darwin logan-capaldos.poly.edu 8.5.0 Darwin Kernel Version 8.5.0: Sun
Jan 22 10:38:46 PST 2006; root:xnu-792.6.61.obj~1/RELEASE_PPC Power
Macintosh powerpc


#3

On Mar 8, 2006, at 4:18 PM, Joe Van D. wrote:

Are there any good Ruby idioms for managing the separate OS-
specific functions?

Lots of ways to do this. Here is another thought:

class A
case RUBY_PLATFORM
when /linux/
def alpha; ‘linux implmentation’; end
when /darwin/
def alpha; ‘darwin implementation’; end
else
def alpha; ‘default implementation’; end
end
def beta; ‘works on all systems’; end
end

puts A.new.alpha # ‘darwin implementation’ (on Mac OS X)
puts A.new.beta # ‘works on all systems’

Gary W.


#4

Joe Van D. wrote:

  • gets the utilization percentage of a NIC on the machine

I’ve been wondering how to do that, either on 2.4 or 2.6. What are you
using?


#5

On 3/8/06, Joel VanderWerf removed_email_address@domain.invalid wrote:

Joe Van D. wrote:

  • gets the utilization percentage of a NIC on the machine

I’ve been wondering how to do that, either on 2.4 or 2.6. What are you
using?

I don’t have the code in front of me, but there’s a file in /proc
(maybe /proc/net?) that details the TX and RX information for each NIC
(in packets or bytes transferred). Keep track of the total amount of
stuff transferred over time, divide by the capacity of the NIC over
that time period (I think I cheat and assume gigabit NICs, since
that’s all we have here), and there you are.

It turns out that it’s pretty hard to get the utilization much above
10%. But I’m not sure of the best way of generating a ton of useless
network traffic.

Joe


#6

Quoting Joe Van D. removed_email_address@domain.invalid:

  • the number of CPUs on a given machine

And then probe (somwhow?) to figure out what OS I’m running on
and
then including the correct modules into my code. So, if I were
using
Linux 2.6, I’d include SystemSpecificFunctions::Linux and
SystemSpecificFunctions::Linux::2.6.

Maybe it would be better to break up the modules by feature rather
than platform. Forking processes is the same on BSD and all Linux
flavors, for example.

So, you’d have a module for POSIX-style fork, for example, and
another for /proc/cpuinfo. The former would provide just the
process creation methods, and the latter would provide just the
methods for enumerating CPUs.

Then you could give each module a singleton method to test for the
presence of its associated feature – e.g. check whether
‘/proc/cpuinfo’ exists.

Then you could iterate through those modules and simply include the
ones whose feature checks pass. Probably you’d want to write some
additional stuff to wrap that process too.

Anyway, advantages:

  • automatically deal with unknown systems that have combinations of
    known features

  • avoid duplication between different platforms with common
    features

-mental