Kernel 0.1, Win

Michael David WINIKOFF winikoff@mulga.cs.mu.OZ.AU
Sun, 21 Mar 93 15:27:18 EST


Kernel -- The Second Attempt 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[NOTE: I'm starting from a conventional OS and moving away rather then starting
 from objects and moving towards OS -- I feel that this is more likely to
 yield a running system in a short amount of time. As Dennis has pointed out
 we don't have the resources to re-invent the wheel]

Rather then just present details here I'd like to throw some ideas and
justifications.

Idea 1
~~~~~~
We base the kernel on persistent processes.

[Terminology: In a moment I'll modify this to persistent objects and explain
the differences. By persistent I mean that it can be swapped out to storage,
the machine turned off and on and then continued. In practice we would like
to be able to have a large number of suspended processes on disk]

This subsumes directories and files -- a directory is just a process that 
accepts queries and returns some identifier for the processes representing files

Consider now the form of such a server (which incidently bears a striking 
resemblence to the nameservers (or dictionaries)):

	while (accept(request)) 
		case request of
			type1 : ... handle 1 ...
			type2 : ... handle 2 ...

This type of code will be very common in the system.
It allready is in event based systems.

Why then not have a process declare to the kernel that
"I handle the following request:
	req1 taking 4 parameters
	req2 taking 3 parameters
etc."

This is just an object.
It has the concept of methods. 

[Note: It is open to discussion how much the kernel should know about the form
of the parameters (Eg. number, type ...)]

[note 2: Inheritance has been left out for the moment.
 as have overloading and polymorphism]

Definition 1
~~~~~~~~~~~~
An object is a process with method declerations.

Definition 2
~~~~~~~~~~~~~
A Device or "LOw Level Object" (lolo) is an object which 
either i
(1) has been granted the privilege of being able to refer to certain hardware 
resources. (Eg. disk control registers, ethernet card)
AND/OR
(2) Has methods which are invoked upon the reciept of a particular interrupt.
(Eg. data ready)

[Note: Most lolo's will have (1) -- I think that few will have ONLY (2)]


Definition 3
~~~~~~~~~~~~~
An OID (Object IDentifier) is an atomic data item that is valid across processes
(Note: In a distributed system it would be valid across machines too) and 
can be used to address an object.

Definition 4
~~~~~~~~~~~~~
A Dictionary (Or Name Server) is an object which supports certain lookup 
operations and returns an OID.

[Note: We see the concept of object classes by the type of the supported methods
falling out. Whether  this should be enforced by the kernel or elsewhere
or not at all is open to debate]


Discussion: As can be seen, so far we need system calls to
	* Create new objects
		This must take in parameters describing
			(1) The code
			(2) The method declerations
		These two could (should?) be together in an executable
			(3) OIDs for the objects which the new object has 
				access to
		This is important -- it replaces the concept of a default
		name server. The only object that is not given an object by
		it's spawner is the initial object. Giving it a nameserver
		is part of the bootstrap process.
	* Destroy objects -- clearly this takes an OID as a parameter
	* Invoking a method
		This takes
			(1) An OID
			(2) The method "name"
			(3) The arguments
		Issues:
			What is the type of the name?
			An integer is the obvious. 
			When would the allocation of these be done?

			The permissible type of the arguments?
			in a purely OO system we could just have OIDs and be
			done. In our system it is doubtful that representing
			(eg.) an array by an object would be practicle so we 
			need to be able to pass large granularity data between
			objects. 

			This is where IPC comes in.
			(I'm using the definition that IPC involves data 
			 copying between address space]



A comment on (very) small objects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In a pure OO environment one could use an object to represent say an array
(not to mention an integer)

This is impracticle if we treat objects as processes since then a method
invocation involves a context switch.

This does not prohibit using small objects WITHIN a single larger object it's
just that these small objects can't be exported to the rest of the system.

I don't think that we can develop a system supporting small objects with 
reasonable efficiency in reasonable time. It involves too much research.

Some Other Issues
~~~~~~~~~~~~~~~~~~~~

These are areas which bear further thought.
I'll indicate my initial reactions to these issues.
Rather then spend time filling out the details now (and spark a debate on them)
I'd like to come to agreement on the basics first.

(1) Memory Allocation
(2) lolos -- how are they created, managed etc.
(3) Virtual Memory  and Address Spaces
(4) What are the semantics of persistance -- eg. what efficiency do we guarantee
[Note: Efficiency is important in design in that a gross efficiency difference
will influence the way a feature will be used.]
(5) Semantics of invocation (Eg. do we have a single threaded or multi threaded
semantics)
(6) Inheritance 
(7) Polymorphism and Overloading

---------
(1) Memory allocation:
	What kernel calls, how and should we support higher level functionality.
	(Eg. GC etc.) 
(2) lolos:
	How do we set an object up as a lolo, how do we give it access to a
	certain region of memory.
	(Implementation: we might need to have the access traped and then redone
	 by the kernel after checking -- MMUs don't neccessarily support fine
	 grain protection.
	 (Eg. this object can read bytes 100-102 and write bytes 103-110 but 
	 can't touch bytes 0-99 and 111-500)
	)
(3) Virtual Memory and Address Space
	I think we can more or less agree that seperate objects should not
	be able to read/write each others address space for robustness 
	reasons.
	Should we have an address space that is global or local to each object.
	(Note: This IS an independant issue)

	How should VM be done? I think paging is the simplest way.
	DEtails:
		User input to the process if any
		Existance of PHYS_MEM and it's management
(4) Semantics of persistance:
	One way to do persistance is to simply rely on paging -- assume all
	objects are in a very large memory and let paging load them in as
	needed.
	As Dennis has pointed out this is inefficient.
	Another way is swapping -- a process can only be either completely
	swapped out or completely in memory. 
	Disadvantage: Lose the ability to save memory by having part of a 
		process in memory
	Advantages: (1) Can be done without an MMU
		(2) By letting the user do this manually we allow coarse grain
		manual resource allocation.
		(Sort of like doing a "copy foo TO ramdisk" b4 starting
		 and having an automatic save files to hard disk from ramdisk
		 when about to shutdown)

(5) Semantics of invocation
	MOOSE is multitasking.
	What happens in the following situation:

	Object X	Object Y	Object Z
	Invoke(Z,1)
					Starts executing method 1
			Invoke(Z,2)
The three obvious possibilities are
(a) Z starts another method in parallel
(b) Y is blocked until Z finishes 
(c) Y continues and the invocation is queued.

(a) Gives us multithreading and requires us to have semaphores to co-ordinate
access to shared data.
(b) Is the simplest to implement but is less versatile
(c) Makes invocation asynchronous -- this adds paralellism to the system.

Notice that under (b) one could have the invoke call return a result.
Under (c) though the invoke would not return anything (other then
"this was succesfuly queued" OR "this failed") and the reciever would use
it's own invoke to return an answer.

Of course we could (and probly will end up doing) provide more then one.

(6) Inheritance 
	I've left this out for now.
	One question I would like to raise is WHICH INHERITANCE?
	There are multiple models -- C++, Smalltalk.
	Oh,  and this is without considering multiple inheritance.

(7) Polymorphism and Overloading
	So far I've only come across these as language design issues.
	 You have a "natural" polymorphism in some commands
	 (Eg. mv,rm,cp) when the contents of a file don't matter.

	 Could someone expound on their ideas -- how do YOU view the role
	 and function of polymorphism in an OS.

--------------------------
And of course, feel free to comment, correct, suggest, debate and/or flame.

Michael
Aka. Merlin son of Corwin and Dara, sorcerer and creator of Ghostwheel. :-)