On Tue, Oct 29, 2013 at 09:58:25PM +0100, Andy Polyakov wrote: > I feel like saying few words. One should recognize that by the time > multi-threading support was taking shape there was a whole variety > of threading implementations and callbacks were the only way to > convey the specifics. Nowadays we're pretty much talking only about
Certainly. I'm not saying "omg, that OpenSSL is insanez!!". I should repeat my problem case: we have libraries that depend on OpenSSL libraries, and it should be possible to for our libraries to work in threaded programs. But right now a Java program that uses JGSS with the JNI shim to the C GSS-API libraries using Heimdal's libgss crashes in RAND_bytes(). Heimdal can't provide locking callbacks (how could it? it might step on some other caller's toes in the same process). The app can't either (since in this case it's not using OpenSSL directly at all). > pthreads and Windows, and one can indeed argue why wouldn't OpenSSL > simply default to either of the two when appropriate. While it's > more than appropriate on Windows as it is, on pthreads-powered > Unices it's not as obvious. Because pthreads can be undesired in > some situations. Basically it boils down to question whether or not > libcrypto may be linked with libpthread or not. And answer is > actually "not desired." Ideally libcrypto should *detect* if More details would be nice. What follows is speculation of mine as to what you might have in mind (or even if you don't, it might be relevant). To summarize the below: OpenSSL .so's should always be linked with -lpthread on OSes where there's a standard libpthread that threaded apps are expected to use; OpenSSL static link archives should assume no threading libraries and rely on the callers to provide the threading callbacks. Distros that focus on static linking should ship OpenSSL static link archives only and shuld ensure that dependents of OpenSSL initialize it correctly when used in threaded programs. Linux still has the multiple process models problem that Solaris <9 used to have: - statically linked with libc but not -lpthread - statically linked with libc and -lpthread - dynamically linked with libc but not -lpthread - dynamically linked with libc and -lpthread - mixed: not originally linked with -lpthread but a dlopen()ed object brought it in I dunno about Linux, but IIUC loading libpthread at run-time in the third case works fine. It also works fine in S8 and S9. It's loading libpthread at run-time in the first case that leads to fireworks. The mixed case is a very difficult one to handle correctly in any library. Merely using dlsym() on RTLD_DEFAULT is not good enough: pthreads symbols might appear later on. Typically the mixed case results when an app uses the name service switch without nscd, or PAM, and one of those pluggable things loads libcrypto. If the app also uses libcrypto then... who knows. (It's clearly insane to support a static libc and have an RTLD. And yet Solaris used to support that... But then, it stopped supporting that for a reason: it was insanely expensive in terms of engineering costs.) I'm not sure that OpenSSL should support such madness in any way other than at ./Configure time: the builder person picks. I.e., this is the distro builder's problem. Some distros are very focused on static linking. Others are not. Static link archives don't record dependencies, so we can't speak of building libcrypto.a with -lpthread. So in the static link build option OpenSSL needs to know whether to assume pthreads or not, and only the builder can tell OpenSSL. In the shared object build of OpenSSL it's just easier to link with -lpthread if the target has pthreads. E.g., a distro that is mostly-dynamically-linked should just ship OpenSSL libs linked with -lpthread, while a distro that is mostly-statically-linked should ship OpenSSL .a's built to not use pthreads. A distro with both should *probably* build OpenSSL .a's w/o pthread and .so's with. A distro might want to require that pthreads is *always* available, even with linking statically. Or perhaps you were thinking of apps that use GNU Pth, but those should either build their own private OpenSSL libs or they should use static link OpenSSL archives. I don't think OpenSSL should bend over backwards to support third-party alternate threading libraries where the OS has a single supported standard. If an OS has multiple supported alternatives then OpenSSL should pick one at run-time, but this is very difficult (see below). > *hosting* application is linked with libpthread and only *then* > adjust accordingly. Is there way to detect if application is linked > with libpthread at run-time? There is DSO_global_lookup. See above. Using weak symbols might work, but it might be very OS-dependent; I'm not prepared to research that for every target, or even more than one or two targets. Using dlsym() seems like asking for trouble. > As for pthread_once [and Windows counterpart]. I'd argue that it > would be more appropriate to initialize the default callbacks > through initialization segment (facility used for "pre-main" > execution of "constructors"), which is guaranteed to be MT-safe. > Such framework (as well as "destructors") would be useful in more > places. Like DllMain and .init? .init in particular is fraught with risk: https://blogs.oracle.com/rie/entry/init_and_fini_processing_who .init execution order is basically unreliable: by design. We should assume that it can change at any time in any ELF RTLD that doesn't guarantee otherwise (and they should keep their options open), and since at least one RTLD won't... At least OpenSSL shouldn't be involved in circular dependencies... DllMain clearly would work for Windows, but there's no need to worry about the statically-linked-with-libc-not-with-pthreads-then-dlopen case on Windows, so it seems like unnecessary complexity unless we also decide to use .init on ELF targets. My advice: stay away from .init. Let the distro builder decide how to build OpenSSL. But if we must pick from several threading libraries at run-time then hopefully the RTLD can make that choice for us, else the only choice left would be to use a .init. > As for config-time detection. My major objection is following. > Software is called so for a reason, and config-time detection is > effectively against its nature. Because it "hardwires" it to > specific set of interfaces. Wouldn't it be more natural for > *soft*ware to detect feature at *run-time* and adapt? This is > actually what's is implemented in several places in OpenSSL. Sort of. On Solaris 10 and up, for example, threading is *always* there, as is the RTLD, and there's no static link archives for core OS libraries (static linking is supported, just not for libc and friends). On Solaris 10 the correct answer is to just use pthreads. On a Linux distro that's only/mostly dynamically linked the same answer applies as to Solaris. On other Linux distros there will be sadness regardless of what OpenSSL does. > >A few notes and questions: > > > > - Locks in OpenSSL are really reader-writer locks, but the sample code > > in crypto/threads/*.c uses mutexes only. > > > > How important is it that reader/writer locks be used instead of > > exclusive locks? > > For historical reasons mentioned above mutexes are common > denominator. Whether or not one should switch to more sophisticated > primitives is question about whether or not do we want to support > legacy multi-threading systems. The answer is probably yes. Of > course one can add more callbacks, see which one are set and opt for > more refined methods if available. But But OpenSSL explicitly treats all locks as reader/writer locks. Using exclusive locks under the hood clearly does not break anything. Using reader/writer locks *might* improve performance, and will expose as bugs any cases where reader/writer locks are not used correctly. > > - The add_lock stuff should just use OPENSSL_atomic_add() wherever it > > exists. > > > > How would I determine at build-time (in ./Configure and in > > ./crypto/lock.c) whether OPENSSL_atomic_add is available? > > #ifdef OPENSSL_CPUID_OBJ Ah, excellent, thanks! > Well, DSO_global_lookup is more consistent with above:-) While we > are at it, it's appropriate to add atomic pointer swap that can be > used to maintain linked lists without mutex-ing. Well, if it's exported anyways. But I don't see OPENSSL_atomic_add in libeay.num! Nico -- ______________________________________________________________________ OpenSSL Project http://www.openssl.org Development Mailing List openssl-dev@openssl.org Automated List Manager majord...@openssl.org