|
mOS introduction
UniOS and mOS
mOS is the part of the UniOS project that describes the principles by which UniOS systems work, including things as how the flexibility, generality, security and IPC work. UniOS will also have to in more detail define specific policies and layouts as well as implementations for different platforms, since mOS with its flexibility allows for great freedom in the final system.
mOS is therefore just a part of UniOS, but will initially, before the serious work of realization has begun, remain the biggest working field. Expect changes to this document.
Object model
The base idea is an object-oriented system. With object-oriented I don't mean that the OS has to be written in an OO language, but that the things that the OS is concerned with are generalized to be different kinds of the same concept, objects. Every time the word "objects" is used, these system objects are meant. The model does not follow the traditional OO paradigm too closely, but does resemble it.
Everything in the system is an object. Also many objects that are usually implemented as compile-time objects or external files should be made as system objects, giving other objects, including authorized users, the ability to modify it's value independent of the parent application itself.
That means, applications don't need to interfere to have their settings changed. This is much like configuration files that can be modified by any text editor, except that these changes can affect the application immediately.
Object definition
The requirements for being called an object is not very restrictive. The types of objects and their characteristics and behavior differ very much. But there are some restrictions. Every object is registered with one object manager (OID server) and supports at least one set of methods, which is implemented by an Object Handler (OH).
An object is referred to as a single instance.
An object type means a special kind of objects, not any specific object.
Object axioms
Objects live until they are deliberately killed, or all use of them ceases. To own an object (be the parent) is also counted as using it. That means that if the parent is killed, so are all children, and the children's children, and so on. When an object is removed and someone uses it, it can either still be removed and users are notified, or it can just be released by its parent, and so live until not used anymore.
An object by default has all rights to all objects under it. Objects can be notified when objects they use are altered. Objects can be moved and still maintain all uses and users. This is possible since registration of use is two-fold - use is registered both for the used and the user. The system is persistent. All objects are stored on persistent storage. For performance reasons, many objects will be cached in RAM, but changes are written to disk sooner or later. Different policies as to when changes are written can be applied. Since processes are objects as well, they can be suspended and written to disk. Their entire environment (related objects) is saved, and they can be brought up again on initiative from a user or the system. All objects are children of the storage device where they are stored.
Where to use objects
When should objects be used, and when should ordinary compile-time options be used? In general, objects are used when you want to do IPC or make some aspect of your application accessible to outside components. Other things that are objects are all files and input and output devices (actually, all devices are objects).
Interfaces
An interface is as the methods in classes - a set of actions that are logically related and all applicable to the same kind of object. All objects conform to defined interfaces. Which interfaces are supported by an object depends on the nature of the particular object type. All access to an object is done via these interfaces. What an object type can do is defined by what interfaces it supports.
Observe that a single object may support several interfaces, unlike traditional objects. This makes up for the objects' inability to use inheritance. Instead of starting with a general object type and gradually refining its behavior to the final state through inheritance, objects may or may not be used for specific purposes from the start. They can still share the same methods and be accessible in the same manner by having them support the same interface. Conversion between interfaces can also be done transparently. This should be a more natural way than inheritance in the case of whole computer systems.
Interfaces are declared to the system, and they never change. If new features are introduced, they have to be added in an add-on interface, for the sake of compability.
Examples of common interfaces are TTY output, directory, plain text format, HTML format, GUI window and process.
Object ID
Every object has a unique (on that system) id, short called OID. The only thing that OIDs does is to identify each object.
mOS security
An important goal in mOS is high security, both against failing processes, malicious programs and user attacks, both local and networked, with purpose to gain inappropriate information or wreak havoc. The model with using interfaces provides a flexible base for security policies. Access to an object is considered for every supported interface. Compare this to the rather inflexible read/write/execute access types in UNIX. Specific security policies are not enforced the system - it could be wide open or shut tight or anything in between, it's all up to the administrator - and the UniOS implementation.
Object Handlers
Something that corresponds to the actual code that performs the methods of traditional objects is needed. I call the constructions that do this 'object handlers', OHs. These are the very things that bring the system to life. Whenever an object need to do something, it's the OH of that object type that does it. It's also the OH that decides on what interfaces are supported by the object type it maintains. Who gets to use the interfaces is not a decision for the OH. This is fully handled by the security policy enforcer. In fact, OHs has notably little power over the use of the objects they implement interfaces for.
An Object Handler is an object too... all OH's share one interface, with commands (mainly for use by the system) that has to do with its function.
OH example
Let me take an example of how OH's would work: When a method in an interface of an object is called by another object that has been granted access, the following happens. The OH that implements the interface for the type of objects that the current one belongs to is called, with the caller's parameters and the OID of the called object. The OH does whatever needs to be done, like fetching the object's data from its own (the OH's) storage and then returns the result to the caller. For the caller it looks like he talks to the object, when he in fact talks to an OH. If the object can, logically, be represented in several ways (like text, that can be shown as formatted or pure text), the OH can say that the object supports both interfaces. Both interfaces point to the same OH, but different entry points of course. If now only the OH implements stripping of formatting tags, clients can access the text, even if they do not support formatted text. They just see that the objects in question support the text interface, that's all they have to know.
Hardware representation
Hardware is in no way excluded from the object model. Each hardware device is used solely by one object, which by natural reasons is hardware-dependent - a device driver, commonly called a low-level abstract in the UniOS project. Drivers present the rest of the system (or rather objects that are granted access) with at least a standardized interface (specific interfaces can also be provided, to let high-performance apps make the most efficient use of devices). Other objects can then register use of the driver just like they would for every object.
A difference is that hardware cannot migrate between machines as software can - software objects will always use the local version of certain hardware drivers. Migrating software should change to use local drivers as invisibly as possible.
System tree
So, there are all these objects. They need to be organized if this isn't going to be really messy. A UNIX-like approach is preferred. Objects are children of other objects, which are children too... all objects are finally connected through a "super root", forming one single system tree. Users don't have access to the whole of this tree. They automatically have access to things below their home location. For other resources, they have to apply for access, just like other obejcts have to.
OID servers
The system needs to keep track of all these objects. The task isn't easy - there's MANY objects, spread on different physical storage. The solution is to divide the responsibility. Everything on a media is a child of the media's object representation, in one or several steps. So, let the media take care of its own sub-tree. This is done by an OID server. In the bottom there is the super root, which acts as an OID server. It maintains only the most fundamental parts of the tree. On this are storage devices mounted - as other OID servers.
Wherever a new OID server is encountered in the system tree, the former server's responsibility ceases. The sub-tree of an OID server is solely up to that server. The most common OID servers are the root, hard drives, network modules (which translates all IPC and requests etc. into network packets) and diskette drives (logically each diskette is an OID server, but the driver takes care of that). OID servers are meant to be nested; other servers may lay inside a server's tree, and use the parent OID server's storage service just like a file would.
A popular example of this is the case with compressed archives. They are all OID servers, and have their own implementation of the directory and raw data interfaces. Access itself can be seamless.
Note that OID servers have, just as OH's, little control over who they work for and for what purpose they work, except the purpose of providing to the system a sub-tree.
CPU schedulers
If it doesn't bring unacceptably low performance, CPU scheduling modules should also be made stackable. There's a root scheduler, which abstracts the processor(s). Then additional schedulers can be stacked at different levels in the system tree, providing specialized scheduling algorithms like real-time scheduling, background processing or user-defined priority levels.
User management
Users are represented as objects, with their usual place in the system tree. When a user logs in locally, the keyboard, screen, etc. are bound to his user object, to serve the right user. Users are stackable. Special "users" can be created to manage groups of physical users, implement distributed storage and computing, and certainly other things as well. Users gain access to resources in the same way as all objects do. Uses are registered for the user objects, just as for other objects.
binEng
|