Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 16 Jul 2002 23:27:24 -0500
From:      Jordan DeLong <fracture@allusion.net>
To:        Terry Lambert <tlambert2@mindspring.com>
Cc:        Taavi Talvik <taavi@uninet.ee>, freebsd-chat@FreeBSD.ORG
Subject:   Re: Linker sets portability
Message-ID:  <20020717042724.GA45349@allusion.net>
In-Reply-To: <3D34DD99.11FF8526@mindspring.com>
References:  <20020717014008.Y99892-100000@valu.uninet.ee> <3D34AC52.2D882455@mindspring.com> <20020717005629.GA42607@allusion.net> <3D34DD99.11FF8526@mindspring.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Tue, Jul 16, 2002 at 07:59:37PM -0700, Terry Lambert wrote:
> Jordan DeLong wrote:
> > > Microsoft DLL's have that ability, derived from OLE, and based on
> > > the current COM (Common Object Model) to create arbitrary support
> > 
> > Component object model actually, I believe.
> 
> I don't know; "Common Object Model" is what they called it in
> the "ViPER Microsoft ActiveX Preview" back in June of 1996,
> when they gave me the CDROM to run on Microsoft Windows NT 4.0
> Beta 2.  8-) 8-).

http://www.microsoft.com/com/ calls it "Component".

Possible they just renamed it (they have a history of renaming things
and then pretending they are new).

> > If you spend a few moments playing with COM, you'd probably realize
> > that the COM threading models are so painfully braindead it's not even
> > funny (and they're a symptom of the rampant misuse of threading found
> > in win32, not a sign of win32 being ahead of unix).
> 
> I guess I'll have to turn in my "Microsoft ActiveX Server Design
> Team" T-Shirt at the front office?  8-).

Ahh I was being rhetorical; not actually intending to suggest you
hadn't played with it.

> Actually, they are very natural, once you understand why they
> are the way they are.  Specifically, the reasons behind the
> reasons behind marshalling have to do with WIN32.DLL on Windows
> 3.11.

I'm not interested in the history of any API.  Historical crap (i.e.
very ungraceful aging) is the reason the win32 api is so crufty.

When interoperating with old code, there's no reason that people
couldn't make their own wrappers which just syncronize entry across
threads.  Bundling it into the do-everything-object-model is just
uncontrolled bloat, not to mention that STA doesn't really solve the
problem.

> > Basically if you want to use more than one appartment in the same
> > process, you're going to have trouble (and keep in mind this is
> > the whole theoretical point of the threading models):
> > 
> > Because calls into the STA from other appartments are implemented
> > by using a hidden "COM Window" and packaging every call into a
> > windows message, anytime you enter a modal message pump from the
> > main STA another thread can renter the STA's objects -- and there
> > is *no* way to effectively lock them out as one would normally do
> > in an MTA app because it's the same physical thread, even though
> > it is a different "logical" thread (i.e. it would own any critical
> > section objects already, etc).  This behavior is entirely unpredictable
> > and unavoidable, because you have no control over the internals
> > IMessageFilter can't solve the problem, but i'm getting off track)
> > of modal message pumps (which exist in several apis).
> 
> Actually, we faced this problem at Artisoft, when we implemented
> soft updates in 1995, after we ported the Heidemann VFS stacking
> framework and the Berkeley FFS to Windows95 (well before soft
> updates were supported on any BSD -- Matt Day did most of the
> work on the Soft Updates implementation).
> 
> The trick is that you can't use a semaphore, you  have to use a
> mutual exclusion.  This bit us when the timer thread would fire
> for the kernel thread we had running the soft updates update
> clock, since it would basically grab any thread context to run
> on (like FreeBSD has been proposing to do for interrupt threads).
> 
> If you use the real mutual exclusion primitives, rather than
> the semaphore calls, it's not a problem.  For this to work,
> you have to "OpenDriver" a VXD that implements the exlusion
> mechanism using the kernel primitives.  It's really pretty
> trivial, if you have the DDK license, which any (at the time)
> "MSDN Level 2" or better developer network member had (it was
> a matter of paying for the SDK's and DDK's, in other words).

Maybe i'm not understanding the above, but it sounds like you're
just suggesting using the in-kernel locking stuff through a new
api provided by a module.  I don't see how this would solve the
problem as it is the same thread:
	Thread A in main STA spawns a worker thread B
	Thread B Coinits multi
	A and B do a lame dance with a HGLOBAL istream to marshal
		an interface pointer over so B can call back when
		it is done with the work.
	A enters a modal dialog or message box
	B calls a proxy object which makes a win32 message and
		posts it to thread A's "Com window" message queue
	A gets the message and executes the specified method
now no matter how you try to lock anything all you can do is
have A return.  It can't wait on the mutex for itself to finish,
no matter what kind of mutexes you're using.

This of course *could* lead to A coming back from a modal message
loop with a bunch of stuff completely changed.  In legacy code that
isn't written with this in mind (or with reentrency in mind in
general) problems could result (and legacy code is one the major
uses of the STA (ms also suggests using it for threads which display
UI).

> > OTOH if you put stuff into the MTA and try to access other pieces
> > in an STA which may call back into it (the mta), win32 will actually
> > spawn a new thread for every method call back into the MTA.  So
> > that's gross, but it's worse than just gross:  because this is a
> > differen't physical thread (but the same "logical" thread, if you
> > take my meaning) it can't recurse on mutexes.
> 
> You never want recursion on mutexes.  If your code recurses on
> mutexes, it's broken, unless you have explicit recursion counting
> so that you know it's happening.  With "context stealing", there
> is really no way to make provably correct code, if you permit
> mutex recursion.  So, actually, I would blame your code, not the
> ViPER framework.

The win32 mutex objects all explicitly support recursion.
CRITICAL_SECTION objects have a recursion count for exactly this,
etc.

I don't see what's wrong with recursing on mutexes... it's a fairly
common practice in "OO" COM code to have a coclass with a lock
member and just protect around functions which need access to other
members.  How would you propose doing that when the object can't
know if one of the functions is going to reenter the object somewhere
else?

Certainly, regardless of whether or not recursing on mutexes is
kosher, the creation of a new thread for each method call across
the appartments is quite lame.

> > I don't see why the win32 people couldn't have just done their
> > component thing without regard to threading, and let individual
> > app/component writers deal with it.  It's just trying to solve too
> > many (nonexistant) problems with one architecture (for more of this
> > see their new COR/CLR/.NET (whatever it's called this week) replacement
> > for COM+).
[ ... ]
> In the free-threading case, there was an attempt to make the API
> compatible between NT and Windows 95/98.  For that to work, the
> marshalling ("CoCreateFreeThreadedMarshaller()") was required,
> since the data may be in a different address space, and that's
> what enabled DCOM ("COM+" as you've called it).

The free threaded marshaller is just an implementation of IMarshal
which doesn't.  The only reason it exists is because marshalling is
slow and stupid for in proc stuff.  The ftm is also relatively rarely
used, because in order for an object to safely use it, all interface
pointers it internally holds have to also use the ftm implementation
of IMarshall.

COM+ is just Yet Another Renaming of COM by MS.  It's the same thing
as COM; DCOM is a subset of the overal label.

Furthermore, in reality it is quite rare to use com without knowing
if something is in a different adress space, or even a different
threading model.

> What Apartment model threading buys you is the ability to
> serialize requests into an otherwise unsafe legacy inteface,

but this isn't actually true if the legacy code uses any apis
which enter modal message pumps (i.e. message box, dialogs, etc).
Furthermore it would be better to forward port the old interfaces
(or perferably provide new thread safe versions) than to add
layers of cruft.

> using a simple to write wrapper around the Thunk entry points.
> Rental model threading permits the use of local globals, so
> long as they aren't used simultaneously (in the FreeBSD world,

Rental model threading was never implemented by MS.  In win2k they
released a new "neutral appartment", which is similar to the old
RTA idea, but differs in some significant ways.

> this would be like implementing the interface "x_r()" via a
> set of locking primitives and a call to "x()").  Again, it
> permits a certain level of backward compatability, and, if the
> code is written correcly, it can attempt to set freethreding,
> fail to do so, and continue to run (in a degraded peroformance
> mode) successfully.

I don't follow this about freethreading.

[ ... ]
> Similarly, all of the "x" and "x_r" versions of routines could
> have been resolved via "rental model", without having to introduce
> a new API.  For each instance of a thread, there would be a
> late-bound allocation of a thread specific "global" context,
> and the APIs would "just work" without all the glue and kludgery
> that we see today.  The contexts would be freed on "thread
> detach", so there would be no memory leak.

I'm not sure what this (and some omitted above it) is about either:
com threading appartments don't provide the thread detach entry --
that's just part of the way libraries work in win32.

What would be nicer though for various _r types of things (and this
may well be what is done when neccesary; I'm not too familiar with
the stuff) is to "late" allocate any per thread data needed as you
suggested, and then use an atexit()-style function which would get
called when the thread is shut down.  I dunno pthreads very well,
but there may even already be such a call?

> Say what you will about them, they thought a number of these
> issues out, while UNIX has been sitting on it's academic laurels
> and doing nothing.

I give MS credit where it is due, but one thing I don't give them
credit for is "thinking things out" (I.e. design).  Apparetment
models exist as a lame attempted hack to allow older OLE stuff to
work with newer things.  It does it poorly because it was poorly
designed, and has aged poorly (much like the rest of their API).

-- 
Jordan DeLong
fracture@allusion.net


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-chat" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020717042724.GA45349>