[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-mac
Subject: Re: [KDE/Mac] [CODE] Multithreaded SIGSEGV signal handling,
From: Jonas_Bähr <jonas.baehr () web ! de>
Date: 2011-09-25 12:34:49
Message-ID: 8AC44E9E-36AA-45B3-B148-8321F20D95CD () web ! de
[Download RAW message or body]
Hi,
Am 25.09.2011 um 01:37 schrieb Michael Pyne:
> [...]
> With that said I don't think the code uses as many POSIX options as
> the rest
> of KSharedDataCache (e.g. process-shared mutexes as unimplemented on
> Mac OS X)
> but I wanted to give a chance for you guys to test the prototype code
> beforehand and let me know if there's problems.
>
> You'll want to compile with something like this:
> $CXX -O2 -o sigcatcher -lrt -pthread sigcatcher.cpp
Here is the first issue: librt doesn't exist here (Mac OS X 10.5
"Leopard").
However, the code compiles without the "-lrt".
$ g++ -O2 -o sigcatcher -pthread sigcatcher.cpp
$ g++ --version
i686-apple-darwin9-g++-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5493)
> Make sure optimization is enabled to ensure volatile is used where
> it's
> needed. Assuming everything works right you should get output like:
>
> $ ./sigcatcher
> Hello, World!
> Got a result of 1
> Exited thread
> $
The next problem is, that sem_init(..) isn't implemented here.
$ ./sigcatcher
Error: sem_init: Function not implemented
$
It seems that only named semaphores are implemented.
I've changed this part of your code to use sem_open(..) instead [see
attachment] and then I get the expected result:
["sigcatcher-sem_open.cpp" (sigcatcher-sem_open.cpp)]
/*
* Copyright © 2011 Michael Pyne <mpyne@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <iostream>
#include <errno.h>
#include <string.h>
#include <semaphore.h>
#include <stdlib.h>
#include <pthread.h>
#include <signal.h>
#include <setjmp.h>
#include <unistd.h>
class KSDCOperation
{
public:
virtual ~KSDCOperation();
virtual void operator()() = 0;
};
KSDCOperation::~KSDCOperation()
{
}
struct SigCatcherSharedData
{
sem_t* workSemaphore;
volatile int keepLooping;
volatile bool resultValid;
volatile sig_atomic_t resultLock;
KSDCOperation *operation;
};
struct SigCatcherSignalHandlerData
{
sigjmp_buf env;
};
pthread_key_t gSigThreadKey;
static void memoryFaultHandler(int signal)
{
std::cout << "Hello from sig handler." << std::endl;
// Figure out what KSDC object we need to jump back to.
SigCatcherSignalHandlerData *localData = reinterpret_cast<SigCatcherSignalHandlerData *>(
pthread_getspecific(gSigThreadKey)
);
// Nothing to do now but jump to our pre-arranged error handler.
siglongjmp(localData->env, signal);
}
void* signalCatcherThread(void *in)
{
SigCatcherSharedData *shared = reinterpret_cast<SigCatcherSharedData *>(in);
// Store the information needed for our thread's signal handler now.
pthread_key_create(&gSigThreadKey, free);
SigCatcherSignalHandlerData *localData = new SigCatcherSignalHandlerData;
pthread_setspecific(gSigThreadKey, localData);
// Set the signals we'll handle
sigset_t handledSignals;
// Block all signals
sigfillset(&handledSignals);
// Except these...
sigdelset(&handledSignals, SIGSEGV);
sigdelset(&handledSignals, SIGBUS);
sigdelset(&handledSignals, SIGFPE);
sigdelset(&handledSignals, SIGILL);
int err;
if ((err = pthread_sigmask(SIG_SETMASK, &handledSignals, 0)) != 0) {
std::cerr << "error: pthread_sigmask: " << strerror(err) << std::endl;
}
// Now establish handlers for signals that are not blocked
struct sigaction sigHandler;
sigHandler.sa_handler = memoryFaultHandler;
sigemptyset(&sigHandler.sa_mask);
sigHandler.sa_flags = 0;
if ((err = sigaction(SIGSEGV, &sigHandler, 0)) < 0) {
std::cerr << "Error: sigaction: " << strerror(err) << std::endl;
}
if ((err = sigaction(SIGBUS, &sigHandler, 0)) < 0) {
std::cerr << "Error: sigaction: " << strerror(err) << std::endl;
}
if ((err = sigaction(SIGFPE, &sigHandler, 0)) < 0) {
std::cerr << "Error: sigaction: " << strerror(err) << std::endl;
}
if ((err = sigaction(SIGILL, &sigHandler, 0)) < 0) {
std::cerr << "Error: sigaction: " << strerror(err) << std::endl;
}
int jmpResult = sigsetjmp(localData->env, 1);
if (jmpResult) {
// siglongjmp called
std::cerr << "Caught signal: " << jmpResult << std::endl;
// Mark whatever operation was going on as failed.
shared->resultValid = false;
// Ensure we unlock our shared data if we had it locked before.
shared->resultLock = 0;
pthread_exit(0);
}
else {
// jmpbuf set, continue as normal
shared->resultValid = true;
while (shared->keepLooping) {
while (sem_wait(shared->workSemaphore) != 0) {
if (errno != EINTR) {
err = errno;
std::cerr << "Error: sem_wait: " << strerror(err) << std::endl;
shared->resultValid = false;
shared->resultLock = 0;
pthread_exit(0);
}
}
// This should only happen if the parent thread has told us to
// exit.
if (!shared->keepLooping) {
pthread_exit(0);
}
// Actually do the freakin' work
(*shared->operation)();
// Uncomment one of these to simulate a crash.
//*(reinterpret_cast<int*>(0)) = 5;
//volatile int dummy = 1/0;
// Free up out parent thread currently spinning.
shared->resultLock = 0;
}
}
return 0;
}
class HelloOperation : public KSDCOperation
{
public:
HelloOperation() : KSDCOperation(), m_done(false)
{
}
virtual void operator()()
{
std::cout << "Hello, World!" << std::endl;
m_done = true; // Result
}
// Just to show how results would have to be stored in the functor object
// itself.
bool m_done;
};
int main()
{
SigCatcherSharedData sharedData;
sharedData.keepLooping = true;
sharedData.resultValid = true;
sharedData.operation = 0;
int err;
sem_t* sem = sem_open("sharedData.workSemaphore", O_CREAT, 0777, 0);
if (sem == SEM_FAILED) {
err = errno;
std::cerr << "Error: sem_init: " << strerror(err) << std::endl;
exit(1);
}
else {
sharedData.workSemaphore = sem;
}
pthread_t exeThread;
if ((err = pthread_create(&exeThread, 0, signalCatcherThread, &sharedData)) < 0) {
std::cerr << "Error: pthread_create: " << strerror(err) << std::endl;
exit(1);
}
// For each task to complete, we need to have a KSDCOperation object, and
// get our spinlock ready by calling ref. Then we post to the workSemaphore
// to free our work thread and spin on resultLock. We must ALWAYS check the
// validity of the result however. If invalid the thread has terminated,
// though we can re-create and try again.
sharedData.resultLock = 1;
HelloOperation *op = new HelloOperation;
sharedData.operation = op;
sem_post(sharedData.workSemaphore);
while(sharedData.resultLock)
;
if(sharedData.resultValid) {
std::cout << "Got a result of " << op->m_done << std::endl;
}
else {
std::cerr << "WHOA, something happened! :(\n";
pthread_join(exeThread, 0);
exit(1);
}
// Normal termination. No need to use resultLock spinlock here.
sharedData.keepLooping = false;
sem_post(sharedData.workSemaphore);
pthread_join(exeThread, 0);
delete sharedData.operation;
if (sem_close(sharedData.workSemaphore) < 0) {
err = errno;
std::cerr << "Error: sem_close: " << strerror(err) << std::endl;
exit(1);
}
std::cout << "Exited thread\n";
return 0;
}
$ g++ -O2 -o sigcatcher-sem_open -pthread sigcatcher-sem_open.cpp
$ ./sigcatcher-sem_open
Hello, World!
Got a result of 1
Exited thread
$
bye,
Jonas
>
> If you want to see the signal handler in action there's a couple of
> lines you
> can uncomment (just grep for uncomment to find where).
>
> Obviously any other feedback on possible issues is appreciated as
> well, but
> basically I'd like to catch any portability issues early this time
> instead of
> after-the-fact.
>
> Please CC me on any replies as I'm not subscribed.
>
> Regards,
> - Michael
> Pyne<sigcatcher.cpp>_______________________________________________
> kde-mac@kde.org
> List Information: https://mail.kde.org/mailman/listinfo/kde-mac
> KDE/Mac Information: http://techbase.kde.org/index.php?title=Projects/KDE_on_Mac_OS_X
_______________________________________________
kde-mac@kde.org
List Information: https://mail.kde.org/mailman/listinfo/kde-mac
KDE/Mac Information: http://techbase.kde.org/index.php?title=Projects/KDE_on_Mac_OS_X
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic