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

next in thread | previous in thread | raw e-mail | index | archive | help
Jordan DeLong wrote:
>         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).

I'd argue that with legacy code, this wouldn't be an issue, and
B wouldn't be talking to a proxy object because legacy code would
not be doing that.  8-).

But assuming it did, I'd call this an application bug, since the
callback execution is not required to occur synchronously; in
fact, the application should be filtering the execution as if
it were a totally seperate context.  The bug is in the lack of
masking.

You can cause this same bug in UNIX using System V IPC by not
passing a specific "msgtyp" value to msgrcv(2), thereby receiving
messages outside of the intended context (i.e. in state zero,
receive on A,B, or C; instate 1, receive only Q, R, or S, etc.).


> 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?

Design the code so that it doesn't need it.  If you don't
violate call order layering rules, it never becomes an issue;
you really have to wonder why you are reentring code on the
same thread: what is it that you need to enter it to have it
do that you could have done before, but failed to do, for no
good reason?

You're really mixing programming models here; you need to decide
if you are protecting code, or protecting data -- *one* or the
*other* -- and then stick with it, instead of bouncing off the
walls.

> 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.

It's not really necessary, either.  In the sample code that comes
with their SDK, e.g. the POP3 server, Microsoft creates a pool of
threads, rather than creating and destoring one per call.  I
really don't know who programs like you are suggesting.


> 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.

Or you don't connect things with pointers all over the place;
the point of OO programming is to limit the object relationships
to those which are necessary to solve the problem... and no more.
8-).


> 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.

D = Distributed.  "Subset" is a matter of definition.  COM has
a subset of the functionality of DCOM, in that DCOM can do
everything COM does *plus* do it remotely.  DCOM is only a
subset if you look at it from an interface persepctive: it
implements the COM API, but it's not the sum total of code
that implements the COM API; but that's "implements" as in
"an implementation class", not as in "a part of the whole".


> 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.

This is practice; it wasn't intended by design.  One problem is
that programmers insisted on breaking up modules in such a way
that the inter-module latency made a significant difference to
the overall performance.  That's bad coding on their part.
Another problem is that there was never a mechanism whereby a
programmer could say "I don't give a damn where this functionality
comes from, just call it and have it be there when that happens"
(hence my earlier reference to SLPv2; Salutation also fits the
bill, FWIW; Microsoft never deployed either).


> > 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).

I never care about reentring GUI components; I can only have one
modal dialog pending at one time, and I can only be interacting
with a single event source (human being) at a time, anyway.  Only
badly written code ever has a problem with this.


> Furthermore it would be better to forward port the old interfaces
> (or perferably provide new thread safe versions) than to add
> layers of cruft.

Sure.  And when you can figure out how to get people to do
this, get FreeBSD to take the resolver out of libc, put it in
a seperate "libresolv", and update the code to bind9.

It's unreasonable to expect everyone to throw away their
investment just because it would be more convenient for you
if they were to throw away their investment.  It would be
more conveninent for me if all system calls took a call
context argument, and returned immediately, so I could use
my full quantum, and do all sysystem processing asynchornously.
It would also be more convenient for  me if most of the locking
was unnecessary because all of the kernel code had been
refactored to align API's on the basis of contention for stall
points.  It would be nice if I could just legally print money
with my printer, any time I needed more.  If you are going to
wish for the impossible, wish big.  8-).


> > 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.

Such as?


> > 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.

You can't force a non-freethreadable module to operate in a mode
where freethreading is required.  It will refuse.  It's an attribute
you set on the COM object.


> > 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.

You can use that fact to do useful work related to per-thread:
data, not code.


> 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?

No.  Because you can't associate the thread context.  You could
do this in a really ugly way (and garbage collect it, as you
suggest), but it requires getting the thread ID and using it as
a hash key into your late-bound object allocation list, so that
you reuse a given object with a given thread (very expensive);
it also fails to solve the problem, unless you run threaded all
the time, since an unthreaded program would not have a thread
for which an allocation exists, nor really need to spend the
overhead.

By doing this on a thread-entry/exit basis, you avoid the case
where the application is non-threaded, you avoid the thread identity
problem, and you avoid the garbage collection (unless you are a
memory vendor, garbage collection is a bad idea; it sucks very
much for any embedded system: we're talking ~16M footprint for a
JVM -- Kaffee -- and 32M for one that doesn't try as hard to
collect -- JDK2).


> > 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).

The problem was not "how do I do this while alienating my existing
customer base", it was "how do I do this and maintain compatability
with my existing customer base".  FreeBSD (and UNIX in general) have
done some damn stupid things in the name of legacy systems support;
look at POSIX: by rights, a scratch implementation of an OS would
"do POSIX right", by implementing it as a user space library on
an efficient an orthogonal API that probably looked very little
like the POSIX API (maybe kqueue based, maybe whatever...).

People who live in glass houses shouldn't throw stones.

-- Terry

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?3D3507A1.A166072D>