Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2664 was 2639, checked in by rgrieder, 16 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
Line 
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/**
30    @file
31    @brief Implementation of the SignalHandler class.
32*/
33
34#include "SignalHandler.h"
35#include "Debug.h"
36
37#include <cassert>
38#include <iostream>
39#include <cstdlib>
40#include <cstring>
41
42namespace orxonox
43{
44    SignalHandler * SignalHandler::singletonRef = NULL;
45}
46
47#ifdef ORXONOX_PLATFORM_LINUX
48
49#include <wait.h>
50#include <X11/Xlib.h>
51#include <X11/Xutil.h>
52#include <X11/keysym.h>
53
54namespace orxonox
55{
56    bool SignalHandler::bXAutoKeyRepeatOn_ = false;
57
58    SignalHandler::SignalHandler()
59    {
60    }
61
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;
71
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      }
89
90
91      // make sure doCatch is only called once without calling dontCatch
92      assert( sigRecList.size() == 0 );
93
94      catchSignal( SIGSEGV );
95      catchSignal( SIGABRT );
96      catchSignal( SIGILL );
97    }
98
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      }
108
109      sigRecList.clear();
110    }
111
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 );
119
120      assert( handler != SIG_ERR );
121
122      SignalRec rec;
123      rec.signal = sig;
124      rec.handler = handler;
125
126      sigRecList.push_front( rec );
127    }
128
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      }
139
140      std::string sigName = "UNKNOWN";
141
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      }
154
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      }
165
166      COUT(0) << "recieved signal " << sigName.c_str() << std::endl << "try to write backtrace to file orxonox.log" << std::endl;
167
168      int sigPipe[2];
169      if ( pipe(sigPipe) == -1 )
170      {
171        perror("pipe failed!\n");
172        exit(EXIT_FAILURE);
173      }
174
175      int sigPid = fork();
176
177      if ( sigPid == -1 )
178      {
179        perror("fork failed!\n");
180        exit(EXIT_FAILURE);
181      }
182
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;
189
190        read( sigPipe[0], &someData, sizeof(someData) );
191
192        if ( someData != 0x12345678 )
193        {
194          COUT(0) << "something went wrong :(" << std::endl;
195        }
196
197        return;
198      }
199
200      int gdbIn[2];
201      int gdbOut[2];
202      int gdbErr[2];
203
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      }
211
212      int gdbPid = fork();
213      // this process will run gdb
214
215      if ( gdbPid == -1 )
216      {
217        perror("fork failed\n");
218        kill( sigPid, SIGTERM );
219        waitpid( sigPid, NULL, 0 );
220        exit(EXIT_FAILURE);
221      }
222
223      if ( gdbPid == 0 )
224      {
225        // start gdb
226
227        close(gdbIn[1]);
228        close(gdbOut[0]);
229        close(gdbErr[0]);
230
231        dup2( gdbIn[0], STDIN_FILENO );
232        dup2( gdbOut[1], STDOUT_FILENO );
233        dup2( gdbErr[1], STDERR_FILENO );
234
235        execlp( "sh", "sh", "-c", "gdb", (void*)NULL);
236      }
237
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) );
241
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;
258
259        if ( charsFound == 6 )
260        {
261          promptFound++;
262          charsFound = 0;
263        }
264
265        if ( promptFound == 3 )
266        {
267          break;
268        }
269      }
270
271      int someData = 0x12345678;
272      write( sigPipe[1], &someData, sizeof(someData) );
273
274      write( gdbIn[1], "bt\nk\nq\n", 7 );
275
276
277      charsFound = 0;
278      promptFound = 0;
279      std::string bt;
280      while ( read( gdbOut[0], &byte, 1 ) == 1 )
281      {
282        bt += std::string( &byte, 1 );
283
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;
295
296        if ( charsFound == 6 )
297        {
298          promptFound++;
299          charsFound = 0;
300          bt += "\n";
301        }
302
303        if ( promptFound == 3 )
304        {
305          break;
306        }
307      }
308
309
310      waitpid( sigPid, NULL, 0 );
311      waitpid( gdbPid, NULL, 0 );
312
313      int wsRemoved = 0;
314
315      while ( wsRemoved < 2 && bt.length() > 0 )
316      {
317        if ( bt[1] == '\n' )
318          wsRemoved++;
319        bt.erase(0, 1);
320      }
321
322      if ( bt.length() > 0 )
323        bt.erase(0, 1);
324
325      time_t now = time(NULL);
326
327      std::string timeString = "\n\n\n\n"
328                         "=======================================================\n"
329                         "= time: " + std::string(ctime(&now)) +
330             "=======================================================\n";
331      bt.insert(0, timeString);
332
333      FILE * f = fopen( getInstance()->filename.c_str(), "a" );
334
335      if ( !f )
336      {
337        perror( ( std::string( "could not append to " ) + getInstance()->filename ).c_str() );
338        exit(EXIT_FAILURE);
339      }
340
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      }
346
347      exit(EXIT_FAILURE);
348    }
349
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    }
358}
359
360#endif /* ORXONOX_PLATFORM_LINUX */
Note: See TracBrowser for help on using the repository browser.