Hi everyone, hi Klaus,
while discussing a paper about multithreading with pthreads, some people pointed out that it is not legal regarding standard C++ when using a static member of a class as a thread start function.
The reason is that a thread start function handed to pthread_create MUST have external C linkage, which is not guaranteed to be the case with static members. In fact, many compilers declare such members with the same calling conventions that an extern "C" function uses, but the standard doesn't require this. Indeed, there are (according to external informations) compilers that act differently here.
To fulfill the requirements of the standard, VDR's thread start function should have the following signature:
extern "C" void *StartThread(cThread *Thread);
class cThread { friend void *StartThread(cThread *Thread); /* ... */ };
Don't get me wrong, this is not a problem with current gcc versions, but... Since the standard doesn't require gcc to behave the way it does, future changes to the ABI could affect this region and could render current code unfunctional...
Even worse, some implementations of pthread lack a construct that declares the members of pthread.h extern "C" when compiled in C++ mode. (But this won't be a problem here I guess, since I suppose VDR won't run on AIX, so, just for the record).
Greetings, Sascha Volkenandt
Sources: http://www.lambdacs.com/cpt/FAQ.html#Q345 http://groups.google.com/group/comp.unix.programmer/msg/cd9ed9b098a9cbc9
Sascha Volkenandt wrote:
Hi everyone, hi Klaus,
while discussing a paper about multithreading with pthreads, some people pointed out that it is not legal regarding standard C++ when using a static member of a class as a thread start function.
The reason is that a thread start function handed to pthread_create MUST have external C linkage, which is not guaranteed to be the case with static members. In fact, many compilers declare such members with the same calling conventions that an extern "C" function uses, but the standard doesn't require this. Indeed, there are (according to external informations) compilers that act differently here.
To fulfill the requirements of the standard, VDR's thread start function should have the following signature:
extern "C" void *StartThread(cThread *Thread);
class cThread { friend void *StartThread(cThread *Thread); /* ... */ };
This would allow anybody to do
cThread t; StartThread(&t);
which I don't think would be a good thing to do.
Any ideas how to prevent this from happening?
Klaus
Don't get me wrong, this is not a problem with current gcc versions, but... Since the standard doesn't require gcc to behave the way it does, future changes to the ABI could affect this region and could render current code unfunctional...
Even worse, some implementations of pthread lack a construct that declares the members of pthread.h extern "C" when compiled in C++ mode. (But this won't be a problem here I guess, since I suppose VDR won't run on AIX, so, just for the record).
Klaus Schmidinger wrote:
This would allow anybody to do
cThread t; StartThread(&t);
which I don't think would be a good thing to do.
Any ideas how to prevent this from happening?
It's perfectly okay to declare StartThread
extern "C" static void *StartThread(cThread *Thread);
within thread.c so it isn't visible outside the object thread.o. Such an invalid use would be caught by the (dynamic, in case of plugins) linker. With gcc 4.0 fulfilling the current standard the friend declaration isn't even a valid implicit forward declaration anymore, so a misuse of StartThread would even result in a compile time error then.
Greetings, Sascha Volkenandt
On 2/12/06, Sascha Volkenandt (ML) lists@magoa.net wrote:
Klaus Schmidinger wrote:
This would allow anybody to do
cThread t; StartThread(&t);
which I don't think would be a good thing to do.
Any ideas how to prevent this from happening?
It's perfectly okay to declare StartThread
extern "C" static void *StartThread(cThread *Thread);
Shouldn't a nameless namepsace be used here? gcc 3.4.3 does not like extern "C" static at all (error: multiple storage classes in declaration of ...). i.e., in thread.c:
namespace { extern "C" void *StartThread(cThread *Thread) { .... } }
Jonas Munsin schrieb:
Shouldn't a nameless namepsace be used here? gcc 3.4.3 does not like extern "C" static at all (error: multiple storage classes in declaration of ...). i.e., in thread.c:
namespace { extern "C" void *StartThread(cThread *Thread) { .... } }
Yes, that works, too (except that gcc 2.95 that is still used for linvdr doesn't care about namespaces ;) )
Regarding standard C++, I guess the anonymous namespace would be the most preferable solution.
Greetings, Sascha Volkenandt
Sascha Volkenandt schrieb:
The reason is that a thread start function handed to pthread_create MUST have external C linkage, which is not guaranteed to be the case with static members. In fact, many compilers declare such members with the same calling conventions that an extern "C" function uses, but the standard doesn't require this. Indeed, there are (according to external informations) compilers that act differently here.
IMHO calling conventions ( like _stdcall and _cdecl ) are about parameter cleanup and ordering and exnrnal c linkage is about how the function name is written ( mangled or not). I can see that calling convention could make problems with pthread, but cannot see what extern "C" should have to to with that. please enligthen me.
regards, gunnar
Gunnar Roth wrote:
IMHO calling conventions ( like _stdcall and _cdecl ) are about parameter cleanup and ordering and exnrnal c linkage is about how the function name is written ( mangled or not). I can see that calling convention could make problems with pthread, but cannot see what extern "C" should have to to with that. please enligthen me.
To quote my first source in the initial post:
"While most C++ implementations do NOT use calling conventions compatible with C for normal member functions, many DO for static member functions. Some, on the other hand, don't, and there's no reason they should. (That is, ANSI C++ says they needn't.)"
Its just that a program compiled in C++ mode doesn't need to follow C calling conventions (especially cleanup is important here) according to the standard. Since extern "C" should declare default C calling conventions within C++ code, it has something to do with it, I guess ;)
Greetings, Sascha Volkenandt