Page 3 of 3
Re:Contexts, Threads, Capabilities and Interfaces
Posted: Mon Sep 19, 2005 4:18 am
by JoeKayzA
Colonel Kernel wrote:
LOL... isn't that the
first question you should be asking, before all the implementation details?
;D In fact I'm glad that I thought about it at all!
Colonel Kernel wrote:
... -- what's the difference between this scheme, and an OS that uses synchronous IPC with priority inheritance?
I had a similar discussion with Legend some time ago - I was not yet able to decide. From the functional point of view, a sendAndWaitForReply() action would be quite the same as a remote procedure call with migration - as long as you manage to transfer priority attributes along with the message. That's what I wanted to address with my post about 'thread slots' and 'thread schedules' above (far above). You could see a thread as a stack, that holds local data and the call history, which is only valid within one address space - but you could also see it from a higher level perspective, as a an entry in the scheduler's queue, that gets a timeslice and runs code - independent from the address space (the scheduler doesn't need to know about this).
But maybe it's better to stick with the traditional (L4-style) messaging system, enhance it with priority inheritance, and build the higher level construct 'the thread schedule' on top of this. I'll think about it.
@Crazed123: To be honest - I always thought about thread migration to be accomplished in a 'call'-style. That means:
A thread from context "Hugo" wants to call a procedure in context "Oscar". The thread then migrates to "Oscar", but its full stack and data in "Hugo" is still preserved. When the procedure is finished, it returns from "Oscar", all the stack in "Oscar" is disposed, and the thread returns to "Hugo" again, where it gets it old stack back.
What you propose here - let the thread permanently stay in context "Oscar" - would mean a 'jump'-style migration. I honestly don't think that this is needed that often, I would implement it on top of the above, 'call'-style, migration scheme. Instead of returning, the migrated thread would do a system call that tells the system explicitly to remove all the stack and data in context "Hugo", as well as the return information, since it doesn't want to return.
But you could also implement this scheme on top of messaging, like Colonel Kernel proposed. The server thread, who received the message, could do a system call, that lets the system destroy the client thread - while it is still in blocked state.
Anyway, thx for the replies!
cheers Joe
Re:Contexts, Threads, Capabilities and Interfaces
Posted: Mon Sep 19, 2005 9:54 am
by Crazed123
I'm a bit too busy with contexts right now to have designed my thread structures fully, but I do have a useful idea for how to implement both types of thread migration. My system is based on capabilities, and so each user has associated with them a number of capabilities. These are the user's "authority" that are inherited by any context or thread created by this user. A thread could have a similar list of capabilities that could be obtained for user code by a system call.
Thus, jump-style thread migration could be implemented however (how I described it, full stack migration, entirely new stack, take your pick from the cornucopia!), and call-style migration could simply be a remote procedure call which made the system call to obtain its threads capabilities. In a remote procedure call system that actually CALLS procedures, rather than sending and receiving messages it would then be astoundingly easy to inherit priorities and other thread information, as the same thread would just be running with a program counter in another context.
Of course, if you want to talk about messages than a nice idea might be to allow threads access to some of their own information (setpriority(), getcaps(), getuid()), with the calls to manipulate it being based on a thread id and a security mechanism. When a thread did a call-migrate it would send a message containing the call to be made, its thread id (if the messaging system doesn't make that implicit), and the bit of security data that would give the other thread permission to impersonate it.
Re:Contexts, Threads, Capabilities and Interfaces
Posted: Mon Sep 19, 2005 11:30 am
by JoeKayzA
Crazed123 wrote:
... rather than sending and receiving messages it would then be astoundingly easy to inherit priorities and other thread information, as the same thread would just be running with a program counter in another context.
...
So you would actually make the 'context', in which a thread runs, a capability that the thread has access to. And the address space, in turn, is a set of capabilities (one per page) that the context contains. Did I get that right? Hmm, I start to like that idea.
cheers Joe
Re:Contexts, Threads, Capabilities and Interfaces
Posted: Mon Sep 19, 2005 2:41 pm
by Crazed123
You're right about the first part. My idea is that a thread makes a system call (FindContext() in Glider) that attempts to find a context, either by name or by an implemented interface (so that a VFS interface could be searched for, rather than just the Reiser4FS driver). If an appropriate context is found, its ID is returned and another call can be made to obtain a capability to that context (Permit(nil,cap) in this case). This capability specifies which other interfacing system calls (I'm going to revise Permit() so it takes a capability, Match() and Import() also require this capability to have certain rights) so that the exact specifics of an interface can be checked, the context itself imported into the current address space, and allowed rights checked for given interfaces. Permit() in that last case will return a capability to an interface (Object 0 in every Context is the context itself, thus allowing capabilities to the context. Context 0 will be the kernel, thus allowing capabilities to it. Just noting these namespace features.), which can then be passed to Link() in order to obtain an actual table of pointers to the places the symbols are used. I've ditched automatic linking of interfaces for now in the name of simplicity, it could be added back later.
My thoughts about call-type thread migration were that a thread's context (process) normally stores things like a user ID, group ID, scheduling information, priority, etc. Calls could be provided to the thread to access some of this information. This would mean that in an RPC system that actually CALLS remote procedures (by changing the current thread's program counter to the function entry point, NOT by passing a request in a message) all of this information could be easily inherited by the called remote procedure by the fact that the current thread would still technically be running, with its own priority, under its own scheduling time, blahblahblah... and could make the calls itself while in the foreign context to learn its thread info.
The last system call I've listed there is rather important. It takes a special capability that must point to the kernel itself (Context 0,Object 0) and have a special right. Its other parameter is a currently invalid capability. A user ID for this capability should probably also be passed in. Anyway, the Super() call checks the kernel capability for Super() rights, and if they are found it hunts down the object designated by the invalid capability, makes a Key() call from the TUnknownInterface that must be supported by any contexts exporting interfaces, takes the given key and turns the specified invalid capability into a valid one that contains the specified context, object and rights. This creates a more specific form of superuser privilege than just letting the superuser do whatever they want.
This Super() call would be useful in providing persistence to important capabilities, as keys and capabilities could be written to disk cleartext with the permissions set so that only their owner could read or write them. When that owner logged in their capabilities would be retrieved from disk and assigned to their proper programs, or assigned as user authorities. From there, whenever a program was started anew a key could be searched for on disk and handed to it to use, thus keeping the old capabilities valid. The big problem with this is that I think it is rather crack-prone to write keys cleartext to disk, because any program running for user X could just look up his/her keys and then forge capabilities to all of that user's servers. Given that system breakins tend to occur under the username that runs say... the webserver and other services to the internet I don't like the implication that a cracker could take your keys and just forge capabilities to all of your server prolaries, possibly including the kernel. Hmmm....