Displaying articles with tag

Platform Abstraction Musings

Posted by rue, Wed Feb 13 03:25:00 UTC 2008

The current platform abstraction in Rubinius is a bit hodgepodge--it works, but the responsibilities and hierarchies are not defined in any predictable manner. What I have been thinking about is a basic idea of a simple hierarchical model where each platform is resolved to a class that provides a complete implementation for it by inheriting and selectively overriding the specifications from its superclasses.

General idea

So, we take POSIX to be one of the top-level implementations (others could be WinNT etc.) POSIX implements the default platform that could run any theoretical operating system that did not deviate from or extend the standard in any (meaningful for us) way. Then, POSIX can be subclassed for example as Linux, which allows us to override the parts of POSIX where a Linux machine will differ or provide extra functionality. This can further be subclassed as Debian < Linux, for example, if anything like that is needed. Furthermore, we can use Ruby modules to represent cross-cutting concerns. So while we could split Linux into Linux32 and Linux64, it may be simpler to just implement Linux as a 32-bit and provide Linux64 (or even just a Generic64 for some things) as a module that can be inserted anywhere it is needed. Further, we can even divide to OS versions.

1
2
3
4
5
6
7
8
9
10
11
12

    # A 64-bit MonkeyLinux 1.8 could look like this
        POSIX
          ^
          |
        Linux
          ^
          |
     MonkeyLinux <<< Linux64
          ^
          |
    MonkeyLinux::V18

The beauty of it is, of course, that it is not necessary to go that deep. If Linux Distro X does not need to specify any behaviour deviating from the base Linux provided, then that is what is used.

Config vs. Runtime

This scheme needs to be split into two components: the build-time config such as struct and constant definitions and the runtime that uses those definitions where needed, uses FFI to attach functions etc. Ideally we would implement both of these in the same class/module hierarchy thereby reducing any mismatch problems but parallel hierarchies work too if they turn out to be considerably easier to implement.

Either way, the first step would be the build-time setup of creating platform.conf, types.conf and so on. This is already done with the tools we have (StructGenerator et al.) but we can make it easier to manage by splitting it up into the above-described hierarchy. When the time comes to build, we just resolve the correct class to use (more about this further down) and ask it to generate the config information or provide the data to do so--not sure what will turn out to be easier here yet. It would also probably be a good idea to codify the exact platform class used here so that it does not need to be re-resolved when the runtime starts. The runtime side of course largely corresponds to what you can see in kernel/platform now, with the exception that, for example, the .attach_method call that ultimately gets run is possibly the result of overrides in the descent through the class hierarchy instead of a hardcoded guess.

Resolving the Correct Platform

The only obvious problem remaining is the actual method of determining which path should be taken in the platform implementation hierarchy. Broadly, two methods can be used: registration or resolution. The former keeps some type of a matching table that selects the correct class based on the key (platform info) given. The latter, which at this point seems favourable, would instead take the approach of testing the platform info against its children's filters/resolvers and passing it further down as necessary. In this scheme, let us say that 'amd64-freebsd6.2' is passed in. The top-level Platform uses POSIX.resolve to determine it is a POSIX platform (initially this 'check' is probably platform !~ /winnt/i or something) and then POSIX peddles it to its subclasses until possibly BSD.resolve accepts it and so on until no subclass can further resolve it. Modules, of course, are taken into account in this whenever inserted.

0 comments | Filed Under: rubinius | Tags: