Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/buildsystem2/src/util/SignalHandler.cc @ 2639

Last change on this file since 2639 was 2639, checked in by rgrieder, 15 years ago

Cleanup in OrxonoxConfig.h.in. Made use of various CMake features like CheckInclude or CheckCompiles to determine some options and macros in the config header file.

Also removed util/Integers.h and placed the code directory in OrxonoxConfig.h.in.

  • Property svn:eol-style set to native
  • Property svn:mergeinfo set to (toggle deleted branches)
    /code/branches/questsystem2/src/util/SignalHandler.ccmergedeligible
    /code/branches/ceguilua/src/orxonox/SignalHandler.cc1802-1808
    /code/branches/core3/src/orxonox/SignalHandler.cc1572-1739
    /code/branches/gcc43/src/orxonox/SignalHandler.cc1580
    /code/branches/gui/src/orxonox/SignalHandler.cc1635-1723
    /code/branches/input/src/orxonox/SignalHandler.cc1629-1636
    /code/branches/objecthierarchy/src/util/SignalHandler.cc2100,​2110-2169
    /code/branches/script_trigger/src/orxonox/SignalHandler.cc1295-1953,​1955
File size: 8.6 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
[2030]37#include <cassert>
[1505]38#include <iostream>
[1837]39#include <cstdlib>
40#include <cstring>
[1505]41
[2171]42namespace orxonox
43{
44    SignalHandler * SignalHandler::singletonRef = NULL;
45}
[1505]46
[2639]47#ifdef ORXONOX_PLATFORM_LINUX
[1505]48
49#include <wait.h>
50#include <X11/Xlib.h>
51#include <X11/Xutil.h>
52#include <X11/keysym.h>
53
[2171]54namespace orxonox
[1505]55{
[2171]56    bool SignalHandler::bXAutoKeyRepeatOn_ = false;
[1505]57
[2171]58    SignalHandler::SignalHandler()
59    {
60    }
[1505]61
[2171]62    /**
63     * register signal handlers for SIGSEGV and SIGABRT
64     * @param appName path to executable eg argv[0]
65     * @param filename filename to append backtrace to
66     */
67    void SignalHandler::doCatch( const std::string & appName, const std::string & filename )
68    {
69      this->appName = appName;
70      this->filename = filename;
[1505]71
[2171]72      // prepare for restoring XAutoKeyRepeat
73      Display* display;
74      if ((display = XOpenDisplay(0)))
75      {
76        XKeyboardState oldState;
77        XGetKeyboardControl(display, &oldState);
78        if (oldState.global_auto_repeat == AutoRepeatModeOn)
79          bXAutoKeyRepeatOn_ = true;
80        else
81          bXAutoKeyRepeatOn_ = false;
82        XCloseDisplay(display);
83      }
84      else
85      {
86        std::cout << "Warning: couldn't open X display to restore XAutoKeyRepeat." << std::endl;
87        bXAutoKeyRepeatOn_ = false;
88      }
[1505]89
90
[2171]91      // make sure doCatch is only called once without calling dontCatch
92      assert( sigRecList.size() == 0 );
[1505]93
[2171]94      catchSignal( SIGSEGV );
95      catchSignal( SIGABRT );
96      catchSignal( SIGILL );
97    }
[1505]98
[2171]99    /**
100     * restore previous signal handlers
101     */
102    void SignalHandler::dontCatch()
103    {
104      for ( SignalRecList::iterator it = sigRecList.begin(); it != sigRecList.end(); it++ )
105      {
106        signal( it->signal, it->handler );
107      }
[1505]108
[2171]109      sigRecList.clear();
110    }
[1505]111
[2171]112    /**
113     * catch signal sig
114     * @param sig signal to catch
115     */
116    void SignalHandler::catchSignal( int sig )
117    {
118      sig_t handler = signal( sig, SignalHandler::sigHandler );
[1505]119
[2171]120      assert( handler != SIG_ERR );
[1505]121
[2171]122      SignalRec rec;
123      rec.signal = sig;
124      rec.handler = handler;
[1505]125
[2171]126      sigRecList.push_front( rec );
127    }
[1505]128
[2171]129    /**
130     * sigHandler is called when receiving signals
131     * @param sig
132     */
133    void SignalHandler::sigHandler( int sig )
134    {
135      for ( SignalCallbackList::iterator it = SignalHandler::getInstance()->callbackList.begin(); it != SignalHandler::getInstance()->callbackList.end(); it++  )
136      {
137        (*(it->cb))( it->someData );
138      }
[1505]139
[2171]140      std::string sigName = "UNKNOWN";
[1505]141
[2171]142      switch ( sig )
143      {
144        case SIGSEGV:
145          sigName = "SIGSEGV";
146          break;
147        case SIGABRT:
148          sigName = "SIGABRT";
149          break;
150        case SIGILL:
151          sigName = "SIGILL";
152          break;
153      }
[1505]154
[2171]155      if (bXAutoKeyRepeatOn_)
156      {
157        std::cout << "Trying to restore XAutoKeyRepeat" << std::endl;
158        Display* display;
159        if ((display = XOpenDisplay(0)))
160        {
161          XAutoRepeatOn(display);
162          XCloseDisplay(display);
163        }
164      }
[1505]165
[2171]166      COUT(0) << "recieved signal " << sigName.c_str() << std::endl << "try to write backtrace to file orxonox.log" << std::endl;
[1505]167
[2171]168      int sigPipe[2];
169      if ( pipe(sigPipe) == -1 )
170      {
171        perror("pipe failed!\n");
172        exit(EXIT_FAILURE);
173      }
[1505]174
[2171]175      int sigPid = fork();
[1505]176
[2171]177      if ( sigPid == -1 )
178      {
179        perror("fork failed!\n");
180        exit(EXIT_FAILURE);
181      }
[1505]182
[2171]183      // gdb will be attached to this process
184      if ( sigPid == 0 )
185      {
186        getInstance()->dontCatch();
187        // wait for message from parent when it has attached gdb
188        int someData;
[1505]189
[2171]190        read( sigPipe[0], &someData, sizeof(someData) );
[1505]191
[2171]192        if ( someData != 0x12345678 )
193        {
194          COUT(0) << "something went wrong :(" << std::endl;
195        }
[1505]196
[2171]197        return;
198      }
[1505]199
[2171]200      int gdbIn[2];
201      int gdbOut[2];
202      int gdbErr[2];
[1505]203
[2171]204      if ( pipe(gdbIn) == -1 || pipe(gdbOut) == -1 || pipe(gdbErr) == -1 )
205      {
206        perror("pipe failed!\n");
207        kill( sigPid, SIGTERM );
208        waitpid( sigPid, NULL, 0 );
209        exit(EXIT_FAILURE);
210      }
[1505]211
[2171]212      int gdbPid = fork();
213      // this process will run gdb
[1505]214
[2171]215      if ( gdbPid == -1 )
216      {
217        perror("fork failed\n");
218        kill( sigPid, SIGTERM );
219        waitpid( sigPid, NULL, 0 );
220        exit(EXIT_FAILURE);
221      }
[1505]222
[2171]223      if ( gdbPid == 0 )
224      {
225        // start gdb
[1505]226
[2171]227        close(gdbIn[1]);
228        close(gdbOut[0]);
229        close(gdbErr[0]);
[1505]230
[2171]231        dup2( gdbIn[0], STDIN_FILENO );
232        dup2( gdbOut[1], STDOUT_FILENO );
233        dup2( gdbErr[1], STDERR_FILENO );
[1505]234
[2171]235        execlp( "sh", "sh", "-c", "gdb", (void*)NULL);
236      }
[1505]237
[2171]238      char cmd[256];
239      snprintf( cmd, 256, "file %s\nattach %d\nc\n", getInstance()->appName.c_str(), sigPid );
240      write( gdbIn[1], cmd, strlen(cmd) );
[1505]241
[2171]242      int charsFound = 0;
243      int promptFound = 0;
244      char byte;
245      while ( read( gdbOut[0], &byte, 1 ) == 1 )
246      {
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        }
[1505]264
[2171]265        if ( promptFound == 3 )
266        {
267          break;
268        }
269      }
[1505]270
[2171]271      int someData = 0x12345678;
272      write( sigPipe[1], &someData, sizeof(someData) );
[1505]273
[2171]274      write( gdbIn[1], "bt\nk\nq\n", 7 );
[1505]275
276
277      charsFound = 0;
[2171]278      promptFound = 0;
279      std::string bt;
280      while ( read( gdbOut[0], &byte, 1 ) == 1 )
281      {
282        bt += std::string( &byte, 1 );
[1505]283
[2171]284        if (
285          charsFound == 0 && byte == '(' ||
286          charsFound == 1 && byte == 'g' ||
287          charsFound == 2 && byte == 'd' ||
288          charsFound == 3 && byte == 'b' ||
289          charsFound == 4 && byte == ')' ||
290          charsFound == 5 && byte == ' '
291            )
292              charsFound++;
293        else
294          charsFound = 0;
[1505]295
[2171]296        if ( charsFound == 6 )
297        {
298          promptFound++;
299          charsFound = 0;
300          bt += "\n";
301        }
[1505]302
[2171]303        if ( promptFound == 3 )
304        {
305          break;
306        }
307      }
[1505]308
309
[2171]310      waitpid( sigPid, NULL, 0 );
311      waitpid( gdbPid, NULL, 0 );
[1505]312
[2171]313      int wsRemoved = 0;
[1505]314
[2171]315      while ( wsRemoved < 2 && bt.length() > 0 )
316      {
317        if ( bt[1] == '\n' )
318          wsRemoved++;
319        bt.erase(0, 1);
320      }
[1505]321
[2171]322      if ( bt.length() > 0 )
323        bt.erase(0, 1);
[1505]324
[2171]325      time_t now = time(NULL);
[1505]326
[2171]327      std::string timeString = "\n\n\n\n"
328                         "=======================================================\n"
329                         "= time: " + std::string(ctime(&now)) +
330             "=======================================================\n";
331      bt.insert(0, timeString);
[1505]332
[2171]333      FILE * f = fopen( getInstance()->filename.c_str(), "a" );
[1505]334
[2171]335      if ( !f )
336      {
337        perror( ( std::string( "could not append to " ) + getInstance()->filename ).c_str() );
338        exit(EXIT_FAILURE);
339      }
[1505]340
[2171]341      if ( fwrite( bt.c_str(), 1, bt.length(), f ) != bt.length() )
342      {
343        COUT(0) << "could not write " << bt.length() << " byte to " << getInstance()->filename << std::endl;
344        exit(EXIT_FAILURE);
345      }
[1505]346
[2171]347      exit(EXIT_FAILURE);
348    }
[1505]349
[2171]350    void SignalHandler::registerCallback( SignalCallback cb, void * someData )
351    {
352      SignalCallbackRec rec;
353      rec.cb = cb;
354      rec.someData = someData;
355
356      callbackList.push_back(rec);
357    }
[1505]358}
359
[2639]360#endif /* ORXONOX_PLATFORM_LINUX */
Note: See TracBrowser for help on using the repository browser.