Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/util/SignalHandler.cc @ 3014

Last change on this file since 3014 was 2911, checked in by landauf, 16 years ago

Merged r1-2096 of questsystem5 back to trunk

I hope there weren't more "hidden merge changes" in r2909 than the one in OverlayGroup (removeElement) (and related to this the adjustments in NotificationQueue).

The corresponding media commit seems not yet to be done, but it doesn't break the build.

File size: 7.7 KB
RevLine 
[1505]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Christoph Renner
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
[2030]30    @file
[1505]31    @brief Implementation of the SignalHandler class.
32*/
33
34#include "SignalHandler.h"
[2030]35#include "Debug.h"
[1505]36
37#include <iostream>
[1837]38#include <cstdlib>
39#include <cstring>
[1505]40
[2171]41namespace orxonox
42{
[2662]43    SignalHandler* SignalHandler::singletonRef_s = NULL;
[2171]44}
[1505]45
[2710]46#ifdef ORXONOX_PLATFORM_LINUX
[1505]47
48#include <wait.h>
49#include <X11/Xlib.h>
50#include <X11/Xutil.h>
51#include <X11/keysym.h>
52
[2171]53namespace orxonox
[1505]54{
[2171]55    /**
56     * register signal handlers for SIGSEGV and SIGABRT
57     * @param appName path to executable eg argv[0]
58     * @param filename filename to append backtrace to
59     */
60    void SignalHandler::doCatch( const std::string & appName, const std::string & filename )
61    {
62      this->appName = appName;
63      this->filename = filename;
[1505]64
[2171]65      // make sure doCatch is only called once without calling dontCatch
66      assert( sigRecList.size() == 0 );
[1505]67
[2171]68      catchSignal( SIGSEGV );
69      catchSignal( SIGABRT );
70      catchSignal( SIGILL );
71    }
[1505]72
[2171]73    /**
74     * restore previous signal handlers
75     */
76    void SignalHandler::dontCatch()
77    {
78      for ( SignalRecList::iterator it = sigRecList.begin(); it != sigRecList.end(); it++ )
79      {
80        signal( it->signal, it->handler );
81      }
[1505]82
[2171]83      sigRecList.clear();
84    }
[1505]85
[2171]86    /**
87     * catch signal sig
88     * @param sig signal to catch
89     */
90    void SignalHandler::catchSignal( int sig )
91    {
92      sig_t handler = signal( sig, SignalHandler::sigHandler );
[1505]93
[2171]94      assert( handler != SIG_ERR );
[1505]95
[2171]96      SignalRec rec;
97      rec.signal = sig;
98      rec.handler = handler;
[1505]99
[2171]100      sigRecList.push_front( rec );
101    }
[1505]102
[2171]103    /**
104     * sigHandler is called when receiving signals
105     * @param sig
106     */
107    void SignalHandler::sigHandler( int sig )
108    {
[2662]109      for ( SignalCallbackList::iterator it = SignalHandler::getInstance().callbackList.begin(); it != SignalHandler::getInstance().callbackList.end(); it++  )
[2171]110      {
111        (*(it->cb))( it->someData );
112      }
[1505]113
[2171]114      std::string sigName = "UNKNOWN";
[1505]115
[2171]116      switch ( sig )
117      {
118        case SIGSEGV:
119          sigName = "SIGSEGV";
120          break;
121        case SIGABRT:
122          sigName = "SIGABRT";
123          break;
124        case SIGILL:
125          sigName = "SIGILL";
126          break;
127      }
[1505]128
[2710]129      COUT(0) << "recieved signal " << sigName.c_str() << std::endl << "try to write backtrace to file orxonox_crash.log" << std::endl;
[1505]130
[2171]131      int sigPipe[2];
132      if ( pipe(sigPipe) == -1 )
133      {
134        perror("pipe failed!\n");
135        exit(EXIT_FAILURE);
136      }
[1505]137
[2171]138      int sigPid = fork();
[1505]139
[2171]140      if ( sigPid == -1 )
141      {
142        perror("fork failed!\n");
143        exit(EXIT_FAILURE);
144      }
[1505]145
[2171]146      // gdb will be attached to this process
147      if ( sigPid == 0 )
148      {
[2662]149        getInstance().dontCatch();
[2171]150        // wait for message from parent when it has attached gdb
151        int someData;
[1505]152
[2171]153        read( sigPipe[0], &someData, sizeof(someData) );
[1505]154
[2171]155        if ( someData != 0x12345678 )
156        {
157          COUT(0) << "something went wrong :(" << std::endl;
158        }
[1505]159
[2171]160        return;
161      }
[1505]162
[2171]163      int gdbIn[2];
164      int gdbOut[2];
165      int gdbErr[2];
[1505]166
[2171]167      if ( pipe(gdbIn) == -1 || pipe(gdbOut) == -1 || pipe(gdbErr) == -1 )
168      {
169        perror("pipe failed!\n");
170        kill( sigPid, SIGTERM );
171        waitpid( sigPid, NULL, 0 );
172        exit(EXIT_FAILURE);
173      }
[1505]174
[2171]175      int gdbPid = fork();
176      // this process will run gdb
[1505]177
[2171]178      if ( gdbPid == -1 )
179      {
180        perror("fork failed\n");
181        kill( sigPid, SIGTERM );
182        waitpid( sigPid, NULL, 0 );
183        exit(EXIT_FAILURE);
184      }
[1505]185
[2171]186      if ( gdbPid == 0 )
187      {
188        // start gdb
[1505]189
[2171]190        close(gdbIn[1]);
191        close(gdbOut[0]);
192        close(gdbErr[0]);
[1505]193
[2171]194        dup2( gdbIn[0], STDIN_FILENO );
195        dup2( gdbOut[1], STDOUT_FILENO );
196        dup2( gdbErr[1], STDERR_FILENO );
[1505]197
[2171]198        execlp( "sh", "sh", "-c", "gdb", (void*)NULL);
199      }
[1505]200
[2171]201      char cmd[256];
[2662]202      snprintf( cmd, 256, "file %s\nattach %d\nc\n", getInstance().appName.c_str(), sigPid );
[2171]203      write( gdbIn[1], cmd, strlen(cmd) );
[1505]204
[2171]205      int charsFound = 0;
206      int promptFound = 0;
207      char byte;
208      while ( read( gdbOut[0], &byte, 1 ) == 1 )
209      {
210        if (
211          charsFound == 0 && byte == '(' ||
212          charsFound == 1 && byte == 'g' ||
213          charsFound == 2 && byte == 'd' ||
214          charsFound == 3 && byte == 'b' ||
215          charsFound == 4 && byte == ')' ||
216          charsFound == 5 && byte == ' '
217            )
218              charsFound++;
219        else
220          charsFound = 0;
[1505]221
[2171]222        if ( charsFound == 6 )
223        {
224          promptFound++;
225          charsFound = 0;
226        }
[1505]227
[2171]228        if ( promptFound == 3 )
229        {
230          break;
231        }
232      }
[1505]233
[2171]234      int someData = 0x12345678;
235      write( sigPipe[1], &someData, sizeof(someData) );
[1505]236
[2171]237      write( gdbIn[1], "bt\nk\nq\n", 7 );
[1505]238
239
240      charsFound = 0;
[2171]241      promptFound = 0;
242      std::string bt;
243      while ( read( gdbOut[0], &byte, 1 ) == 1 )
244      {
245        bt += std::string( &byte, 1 );
[1505]246
[2171]247        if (
248          charsFound == 0 && byte == '(' ||
249          charsFound == 1 && byte == 'g' ||
250          charsFound == 2 && byte == 'd' ||
251          charsFound == 3 && byte == 'b' ||
252          charsFound == 4 && byte == ')' ||
253          charsFound == 5 && byte == ' '
254            )
255              charsFound++;
256        else
257          charsFound = 0;
[1505]258
[2171]259        if ( charsFound == 6 )
260        {
261          promptFound++;
262          charsFound = 0;
263          bt += "\n";
264        }
[1505]265
[2171]266        if ( promptFound == 3 )
267        {
268          break;
269        }
270      }
[1505]271
272
[2171]273      waitpid( sigPid, NULL, 0 );
274      waitpid( gdbPid, NULL, 0 );
[1505]275
[2171]276      int wsRemoved = 0;
[1505]277
[2171]278      while ( wsRemoved < 2 && bt.length() > 0 )
279      {
280        if ( bt[1] == '\n' )
281          wsRemoved++;
282        bt.erase(0, 1);
283      }
[1505]284
[2171]285      if ( bt.length() > 0 )
286        bt.erase(0, 1);
[1505]287
[2171]288      time_t now = time(NULL);
[1505]289
[2731]290      std::string timeString =
[2171]291                         "=======================================================\n"
292                         "= time: " + std::string(ctime(&now)) +
[2731]293                         "=======================================================\n";
[2171]294      bt.insert(0, timeString);
[1505]295
[2753]296      FILE * f = fopen( getInstance().filename.c_str(), "w" );
[1505]297
[2171]298      if ( !f )
299      {
[2662]300        perror( ( std::string( "could not append to " ) + getInstance().filename ).c_str() );
[2171]301        exit(EXIT_FAILURE);
302      }
[1505]303
[2171]304      if ( fwrite( bt.c_str(), 1, bt.length(), f ) != bt.length() )
305      {
[2662]306        COUT(0) << "could not write " << bt.length() << " byte to " << getInstance().filename << std::endl;
[2171]307        exit(EXIT_FAILURE);
308      }
[1505]309
[2171]310      exit(EXIT_FAILURE);
311    }
[1505]312
[2171]313    void SignalHandler::registerCallback( SignalCallback cb, void * someData )
314    {
315      SignalCallbackRec rec;
316      rec.cb = cb;
317      rec.someData = someData;
318
319      callbackList.push_back(rec);
320    }
[1505]321}
322
[2710]323#endif /* ORXONOX_PLATFORM_LINUX */
Note: See TracBrowser for help on using the repository browser.