[Portland] In process? Out of process? And more...

George Staikos staikos at kde.org
Sat Dec 10 19:31:29 EET 2005


On Friday 09 December 2005 07:07, Lars Knoll wrote:
> > I just said that because i thought problems should be fixed at the
> > lowest possible layer. Bypassing them with daemons and IPC looks a bit
> > like an overkill and should only be the last choice.
>
> I think most of us agree that unifying event loops is a good idea. It will
> however not solve every issue. One of the main problems I see with an
> in-process approach is potential stability and security issues.

  We have hard evidence of this already with nspluginviewer in konqueror.  Our 
native plugin format, kparts, turns out to be less stable and more of a 
problem than nspluginviewer in user's eyes, despite the fact that our KParts 
are actually better written and more stable.  Anyone can prove this to 
themself by running flashplayer through valgrind and comparing to, say, a 
KHTML plugin. (ok, ok, don't try kaffeine :-)) 

  Lars knows nspluginviewer quite well.  Despite some IPC design issues, it's 
actually extremely robust.  Many browser developers have told me privately 
and publically that they would like to move to this model, but many of them 
have technical issues preventing it.

> ISVs test their application with a set of libraries they link against on a
> certain desktop. an in-process approach basically means that the
> application developer can not know what kind of code might get executed in
> it's process space.

  At best they can hope there is a specification to work from.  Very few 
opensource libraries have this.

> The other problem is interoperability between different major versions of
> the same library (Qt3 vs Qt4, Gtk2 vs a future Gtk3). These usually define
> similar sets of symbols which could lead to larger problems when loading
> them into the same address space.

   This is a very big and real issue with plugins.  Even worse when you start 
to see libraries that clearly the people on this list haven't run into yet, 
such as openldap or openssl.

> So I think that even though an out-of-process approach looks like overkill
> it's the safer road to go. On a standard desktop environment you will
> probably also not need a special daemon as the desktop has applications
> running that can just take over these functions.

   I think this is only part of the answer.  Here is how I see it:

We need to define a protocol in the abstract sense.  We can provide a sample 
implementation in plain C with no dependencies to prove that it is generic 
and usable for any type of application.  We can provide implementations in Qt 
and GTK+ to show that it works well with existing applications on the 
desktops.  And we make the implementation a completely separate aspect from 
the protocol.  This way, we are free to implement any one or more of many 
mechanisms for accessing the desktop.  We can do a RUDI-style IPC based 
system, a user-space runtime tool system (external executable), or native 
linking.

Let's look at this from an app developer perspective.
1) I need something that is available in my language, and feels like a 
first-class citizen (even if it really isn't underneath - that doesn't 
matter).
2) I need something that works with my toolkit in my language.
3) I have specific goals and tasks, and if I really want something that hooks 
into the desktop tightly, I am doing something very specialized and I can and 
-want- to do it natively.
4) I don't want to know about implementation because that's error-prone and 
not my business.  Notice that this means I don't want to be reading 
configuration files myself.  I want to ask what I want via API and be told 
the answer.
5) This should, in theory, be portable to Windows and Mac OS X too, since this 
is where my migration path comes from and writing code 3 times is no fun.

Let's take some examples:
bool addMenuEntry(const char *name, const char *executable);

This is a horrible interface because it talks about implementation details, 
not an abstract concept.  This would not work well on any platform I know of 
except perhaps if it adds a dock entry on Mac OS X, which is not even what 
the API suggests it does.

bool addMenuEntry(const char *desktopFile);

This is better in some ways because the .desktop file can contain enough 
information for all platforms.  However it still misses a few points.  For 
instance, is there even a menu?  On some platforms this is completely wrong 
conceptually.

bool installMyApplication(struct AppInfo *myAppInfo);

This is getting very close, I think.  It's task is to do the "right thing" on 
whichever platform the application is running on.  If it needs a .desktop 
file, it builds it from the appinfo.  If the app wants a launcher/dock entry, 
it can suggest that via a flag in the AppInfo.  There are no assumptions made 
here on the Portland side OR on the app-developer side.  This is what I call 
a nice, robust, abstract API.  And honestly, this is what we have in our own 
libraries for commercial development.

At a higher level, say a GTK+ or Qt wrapper, these things could be converted 
to more native structures and any existing knowledge can be auto-filled.

<tangent>
This does expose a somewhat interesting issue though.  If we abstract it so 
far, it makes support costs higher.  I think this is quite a tangent, but 
it's an extremely significant issue.  If you ask me, writing the app in two 
toolkits is cheaper than the tech-support and QA costs of testing it on all 
those platforms, especially using this generic library.  Do we have a case 
where we need more management folks involved in this before we spend too much 
effort on technical issues?
</tangent>

Ok, so let's consider the implementation of installMyApplication().  I imagine 
it would look something like this:

installmyapp_linux.c
installmyapp_win32.c
installmyapp_macosx.c

Consider installmyapp_linux.c:
bool installMyApplication(struct AppInfo *myAppInfo) {
   DesktopHandler *h = desktopHandler();
   if (!h) return false;
   return (h->installMyApplication)(myAppInfo);
}

DesktopHandler *desktopHandler() {
   if (globalHandlerObject) return globalHandlerObject;
   Desktop d = detectDesktop();
   globalHandlerObject = loadHandlerForDesktop(d);
   return globalHandlerObject;
}


DesktopHandler* could have fields indicating app preference for (or 
prohibiting the library from using) in-process, out-of-process, etc, but 
would typically take the best available option.

I think this gives us maximal flexibility for later.  We can break major tasks 
down to give more finegrained (with caveats) access to the system, we can 
change implementations, and more.  The only exposure we have is in any global 
types we expose.

It also allows us to get to a proof-of-concept very rapidly.  We can implement 
a few specific tasks and use a backend written in the most rapid manner.

Any thoughts?

-- 
George Staikos
KDE Developer				http://www.kde.org/
Staikos Computing Services Inc.		http://www.staikos.net/



More information about the Portland mailing list