Reputation:
Is the following supported across *nix platforms?
#include <cstdio>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
class SignalProcessor
{
public:
static void OnMySignal(int sig_num)
{
printf("Caught %d signal\n", sig_num);
fflush(stdout);
return;
}
};
using namespace std;
int main()
{
signal(SIGINT,SingalProcessor::OnMySignal);
printf("Ouch\n");
pause();
return 0;
}
Upvotes: 2
Views: 1176
Reputation: 264461
Technically no you can't.
You just happen to be getting lucky that your compiler is using the same calling convention that it uses for 'C' functions. As the C++ ABI is not defined the next version of the compiler is free to use a completely different calling convention and this will mess with your code with no warning from the compiler.
See: http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
See the note at the end of this section
Note: static member functions do not require an actual object to be invoked, so pointers-to-static-member-functions are usually type-compatible with regular pointers-to-functions. However, although it probably works on most compilers, it actually would have to be an extern "C" non-member function to be correct, since "C linkage" doesn't only cover things like name mangling, but also calling conventions, which might be different between C and C++.
Edit:
To answer the comment by Sasha:
Using threading as an example:
#include <iostream>
class Thread
{ public: virtual void run() = 0; };
extern "C" void* startThrerad(void* data)
{
Thread* thread = reinterpret_cast<Thread*>(data);
try
{
thread->run();
}
catch(...)
{ /* Log if required. Don't let thread exit with exception. */ }
return NULL;
}
class MyJob: public Thread
{
public: virtual void run() {std::cout << "HI\n";}
};
int main()
{
MyJob job; // MyJob inherits from Thread
pthread_t th;
// In most situation you do not need to dynamic cast.
// But if you use multiple inheritance then things may get
// interesting, as such best to always use it.
pthread_create(&th,NULL,startThrerad,dynamic_cast<Thread*>(&job));
void* result;
pthread_join(th,&result);
}
Upvotes: 5
Reputation: 44804
I do the equivalent with Windows thead procedures and other assorted callbacks, and RTX interrupts all the time. The only real gotchas are that the members have to be static (which you already figured out), and that you have to make sure your routine is set to use the standard C/system call calling convention. Sadly, how you do that is platform dependent. In Win32 it is with the "__stdcall" modifier.
Note that you can use the passback-in pointer paramteter to "convert" such calls into normal class method calls. Like so ("self_calling_callback" is the static method):
unsigned long __stdcall basic_thread::self_calling_callback (void *parameter) {
if (parameter) {
basic_thread * thread = reinterpret_cast<basic_thread *>(parameter);
thread->action_callback();
}
return 0;
// The value returned only matters if someone starts calling GetExitCodeThread
// to retrieve it.
}
basic_thread::basic_thread () {
// Start thread.
m_Handle = CreateThread(NULL,
0,
self_calling_callback,
(PVOID)this,
0,
&m_ThreadId );
if( !IsHandleValid() )
throw StartException("CreateThread() failed", GetLastError());
}
Upvotes: -1
Reputation: 402
That should work just fine. In fact, you could expand that function to call specific instances of that class dependent on the signal caught. For example, if you add a non-static method Process to you class, you can do something like this:
SignalProcessor* sp[MAX_SIGNALS];
static void SignalProcessor::OnMySignal(int sig_num)
{
printf("Caught %d signal\n", sig_num);
if (0 < sp[sig_num])
sp[sig_num]->Process();
fflush(stdout);
return;
}
Upvotes: -1