News, tips, partners, and perspectives for the Oracle Solaris operating system

Goodbye (And Good Riddance) to -mt -and -D_REENTRANT

Ali Bahrami
Principal Software Engineer
(Written: December 2015)


One of the nice simplifications in Solaris 11 Update 4 is that it is no longer necessary to pass the -mt option to the compilers, or to set -D_REENTRANT when building threaded code. Nothing will stop you from doing that, but they no longer do anything, and can be removed. This is going to simplify documentation, and eliminate potential bugs when making system calls.

If you're building on Solaris 11.3 or older, you do still need to set -D_REENTRANT, but -mt is not needed.

More than once over the years, I've had to dig into the documentation to remind myself out what these settings do. We'll be tripping over them in Makefiles for years to come, and I expect official documentation for them to fade away over time. This article is for those of us in the future who enter searches into Google like "Solaris _REENTRANT what?".

Originally, SunOS, as with all versions of Unix at the time, was a single threaded system. Processes had a single thread of execution, and in fact, the notion of "thread of execution" didn't really exist. That changed during the 1990's, as Sun started producing symmetric multi-processor systems. Threading was a hot topic, and Sun was a leader in that space.

In those early systems, threading was an exotic technique that most processes didn't use. As such, all the thread APIs were found in a library, libthread, rather than in the core libc library. libc was modified to use locks to allow threads safe access to its routines, but only if the process was linked against libthread. If libthread was not present, then libc would run in the traditional unlocked manner.

The _REENTRANT macro dates from that era. When Unix system calls fail, they generally return a value that indicates failure, and set a global variable named errno with a code that describes the specific failure. In a threaded world, errno needs to be a per-thread variable rather than a single global variable. Compiling your code with -D_REENTRANT would trigger #ifdefs in the system header files to cause the name errno to resolve to a per-thread variable. A common pitfall is to employ threads in your code, and not compile it with -D_REENTRANT. All of your threads then set a single global errno, leading to all sorts of potential race conditions when handling errors. As a result, things "mostly work", with rare unexplained glitches.

At the same time, as a convenience to programmers, the compilers added the -mt option, intended to be a single option programmers could set to build code for threaded use. -mt set _REENTRANT, and also pulled in libthread, as described in the compiler manpages:

-mt    Use this option to compile and link multithreaded
       code. The -mt option assures that libraries are
       linked in the appropriate order.


For a few years, -mt was a nice and simple solution, but then, the world changed.

The first change was caused by Posix Threads, which were standardized a few years after Sun had shipped libthread and the APIs it delivers. The two APIs are extremely similar, and as the industry adopted pthreads, Sun made them available as well, providing them in libpthread. The new, slightly more complicated rule for building multithreaded code became that you set -D_REENTRANT, and link to one of libthread or libpthread. The documentation for -mt changed to:

-mt    Use this option to compile and link multithreaded
       code. The -mt option assures that libraries are
       linked in the appropriate order.

       If you are using POSIX threads, you must link with
       the options -mt -lpthread.

So much for a single option: -mt only ever did 2 things, and now one of them (-lthread) was often the wrong thing, and needed to be augmented manually by the user with -lpthread. That was slightly annoying, but it worked, and things carried on for a few more years.

The next, far bigger, change was caused by the great thread unification that was delivered by Roger Faulkner in Solaris 10. By the Solaris 10 timeframe, threads had become pervasive in Solaris, used not just by applications, but also in libraries. You might not have threaded your code, but your program might still have multiple threads running. The old model of threaded and non-threaded programs, as determined by the programmer building the program, no longer made sense. All processes are potentially threaded, all the time. Thread unification in Solaris 10 changed a number of things:

  • All the thread support migrated from libthread and libpthread to libc. libthread and libpthread because empty filter libraries, for the benefit of existing programs linked to them, as I described in a recent article on weak filters. As a result, libthread and libpthread became unnecessary cruft for new programs.
  • libc is thread safe in all contexts, rather than requiring the presence of libthread or libpthread.
  • The old 2 level M:N threading model, which had failed to deliver benefits, and which had caused many difficulties, was ripped out and thrown away.

As a result, things are vastly simpler, easier, and more reliable now. The minor exception to that is that up until Solaris 11 Update 4, it was still necessary to understand -D_REENTRANT, and -mt.

  • The need to set -D_REENTRANT in a system that is otherwise always thread capable, is one of those vestigial leftovers that is hard to defend. However, altering required a substantial amount of work, which in turn opened up other related work — a drawn out onion peeling exercise.
  • Similarly, the need for -mt makes little sense today. It does provide a more convenient way to set -D_REENTRANT, but it also drags in an empty filter library that no one needs. and its documentation is misleading.

Roger again stepped up, and delivered the final coda to thread unification. In Solaris 11 Update 4, it is no longer necessary to set -D_REENTRANT. errno is now always a per-thread value regardless of whether -D_REENTRANT is set or not. And since the only useful thing done by -mt was to set -D_REENTRANT, it is no longer necessary to set -mt either.

If you're building code on Solaris 11 Update 4 or newer, you should drop those options from your makefiles, and simplify.

[ This article is permanently archived at http://www.linker-aliens.org/blogs/ali/entry/mtreentrant/ ]

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.