Date: Tue, 16 Jul 2002 19:59:37 -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: <3D34DD99.11FF8526@mindspring.com> References: <20020717014008.Y99892-100000@valu.uninet.ee> <3D34AC52.2D882455@mindspring.com> <20020717005629.GA42607@allusion.net>
next in thread | previous in thread | raw e-mail | index | archive | help
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-). > 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-). 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. > 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). > 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. > 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+). The problems it's solving are real. The Windows 3.11 system with the WIN32.DLL and the corresponding VxD in it was incapable if supporting a "freethreading" model. This is because the data in any heap memory was allocated in a 64K medium model chunk, the address of which was the instance ID for the message pump, when you were running multiple instances of messages. The best that they could do is to create the concept of TLS "Thread Local Storage", and live with it. For the programs to run on both Windows 3.11 with the WIN32 API spackled onto it, and on newer Windows95 and above versions, the concept of "marshalling" data to get it between one set of TLS and another was required. Actually, due to the way VMM32.VxD was written, you actually don't need to marshal object instances created *before* a thread is created -- there will be a duplicate mapping. 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). What Apartment model threading buys you is the ability to serialize requests into an otherwise unsafe legacy inteface, 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, 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. Other than the different address spaces, which require marshalling on the local machine, and the registration and service location mechanisms, which are solvable with protocols like SLPv2, rather than jamming raw IP addresses into DCOM object server lists, Microsoft did a pretty incredible job with what they had. For implicitly serialized protocols, where pipelining is not a possibility, UNIX could really use the ability to rental or apartment model the libraries that interfaced to the protocol engine. Specifically, there has been a lot of recent bitching about the resolver library not being asynchornous. With an apartment model -- which requires the ability to know when threads attach and detach a library, so that the library can create/delete per thread context objects -- it's possible to export an asynchornous interface, while handling the serial nature of the current resolver library. Then code would not have to change, were the resolver library ever pulled out of libc, so that it could be easily fixed ("the BSD way" can be preserved by linking the ELF C library against the ELF resolv library: one of the base arguments used for the ELF switch in the first place). 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. 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. > [ ... ] > > So the general answer is "pretty much everyone whose linker is > > capable of linking programs compliant with the C++ standards, > > and whose C compiler supports a sufficiently sophisticated ability > > to escape to inline assebly to generate the data that the linker > > uses to accomplish C++ specific features, can be made to support > > linker sets". > > OT: (This isn't important to the point you were making... but then > again neither was the COM stuff above :P). I don't think a truely > standards compliant C++ compiler exists... neither G++ nor MSVC++ > comply to the standard completly.. The point is that people have been trying to for a long time. It used to be that there were no shared template instances. Then, you had to compile a "magic" version of the template code with a compiler flag, to get a shared instance. Then the compilers started supporting auto-aggregation with duplicate supression, and all that garbage wasn't necessary any more. You can assume that linker sets are portable to the platforms he listed (Linux/FreeBSD/Win32/Solaris), and the "/..." is the part that needed his iown observations for answering. Most compilers these days *at least* support that much of the standard that you can have a template class with a static instance member variable that is shared among all instances; and if the compiler supports it, there's usually some way to abuse it to get a "linker set" equivalent, although whether it can be achieved inline is always a function of the flexibility of the C compiler itself (e.g. inline assembly and segment attribution, to access the linker feature that was intended for use by C++ for that purpose). -- 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?3D34DD99.11FF8526>