[PATCH] Make libcxx compile on x86_64 Linux w/ g++ 4.4.3

Hi,
Just thought I'd contribute a small patch that helped libcxx compile on my machine using g++ 4.4.3 with -std=c++0x. Without it I got the following message:

+ g++ -std=c++0x -c -g -Os -fPIC -nostdinc++ -I../include ../src/condition_variable.cpp
In file included from ../src/condition_variable.cpp:11:
../include/thread: In member function ‘std::__1::thread& std::__1::thread::operator=(std::__1::thread&&)’:
../include/thread:268: error: no match for ‘operator!=’ in ‘((std::__1::thread*)this)->std::__1::thread::__t_ != std::__1::__get_nullptr_t()’
../include/system_error:569: note: candidates are: bool std::__1::operator!=(const std::__1::error_condition&, const std::__1::error_condition&)
../include/system_error:565: note: bool std::__1::operator!=(const std::__1::error_condition&, const std::__1::error_code&)
../include/system_error:561: note: bool std::__1::operator!=(const std::__1::error_code&, const std::__1::error_condition&)
../include/system_error:557: note: bool std::__1::operator!=(const std::__1::error_code&, const std::__1::error_code&)
../include/cstddef:73: note: bool std::__1::operator!=(std::__1::nullptr_t, std::__1::nullptr_t)
../include/thread:271: error: cannot convert ‘std::__1::nullptr_t’ to ‘pthread_t’ in assignment

This happens because nullptr is not convertible or comparable to integral types (except bool), only pointers and pointer-to-members (http://en.wikipedia.org/wiki/C%2B%2B0x#Null_pointer_constant), so you can't use it to check or set __t, at least not directly. There's probably a better way to do it than this, just thought I'd bring the matter to your attention. For what it's worth, I haven't hacked the test script to run on my machine yet so I haven't tested it, but it does compile with minimal #warnings about exception_ptr not being implemented.

mrj10@mjlap:~/llvm/libcxx/include$ svn diff thread
Index: thread

Thanks Matt. What is pthread_t on your system? And are you sure that assigning NULL to it is putting it into a state that means "not a thread"?

-Howard

When I was fixing these problems (sorry for missing the move case), I
used "0" instead of either NULL or nullptr. That's not guaranteed to
work either, and I didn't check glibc to see if it's actually the
not-a-thread value, but it at least made things compile.

Howard, is there a reason you're using pthread_t and literal no-thread
values everywhere instead of using thread::id? Using thread::id
everywhere would reduce the number of places that need porting.

Yes. I like to minimize levels of inlining when the cost to do so is low. It makes non-optimized (e.g. debug) builds run faster which in turn can make the entire customer development process faster/more livable.

I did think about using thread::id as you suggest, but found the cost of not doing so acceptable.

-Howard

Howard Hinnant wrote:

Thanks Matt. What is pthread_t on your system? And are you sure that assigning NULL to it is putting it into a state that means "not a thread"?
  

glibc defines pthread_t as unsigned long. Assigning NULL to it is
definitely not a good idea; at the very least, GCC ought to generate
warnings about the misuse of NULL. (And so would Clang.)

I've looked at the Single Unix Specification, and I don't think
pthread_t is supposed to even have a "not a thread" value. So you can
either go the separate bool way for glibc systems, or look at the glibc
code to find a valid sentinel and pray they don't change anything.

For what it's worth, current glibc stores a pointer in pthread_t too, so
0 can probably be used as a sentinel for now. That said, be aware that
it unconditionally dereferences that pointer, so if you accidentally
pass it to a pthread_* function, you'll get a segmentation fault, not an
error.

Sebastian

Howard Hinnant wrote:

Thanks Matt. What is pthread_t on your system? And are you sure that assigning NULL to it is putting it into a state that means "not a thread"?

glibc defines pthread_t as unsigned long. Assigning NULL to it is
definitely not a good idea; at the very least, GCC ought to generate
warnings about the misuse of NULL. (And so would Clang.)

Agreed. I've changed to '0', but haven't checked it in yet.

I've looked at the Single Unix Specification, and I don't think
pthread_t is supposed to even have a "not a thread" value.

You are correct.

So you can
either go the separate bool way for glibc systems, or look at the glibc
code to find a valid sentinel and pray they don't change anything.

If the separate bool is needed for glibc, I'd prefer it go under an #ifdef. I don't want to sacrifice performance for portability.

For what it's worth, current glibc stores a pointer in pthread_t too, so
0 can probably be used as a sentinel for now.

Good. The posix community is aware (I think) that a sentinel value is desired. It comes in very handy when a function needs to detect if this thread was the last one to execute it (like a recursive mutex).

That said, be aware that
it unconditionally dereferences that pointer, so if you accidentally
pass it to a pthread_* function, you'll get a segmentation fault, not an
error.

This is allowed behavior for pthread_join and pthread_detach (according to the posix spec). Though I would think it higher quality to return EINVAL.

Thanks Sebastian.

-Howard