Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/objecthierarchy2/src/util/SignalHandler.cc @ 2344

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

Completed destruction of static elements like XMLPort, Identifier, etc.
Of initially about 250 memory leaks (not in the actual meaning but the memory was never freed anyway) only 1 remains in TinyCpp.

  • Core class is now a normal Singleton that gets created and destroyed in main.
  • The same goes for Language, LuaBind, SignalHandler and PlayerManager.
  • Added a new std::set to the CommandExecutor so that the external ConsoleCommands can get destroyed too.
  • Code for destroying CommandLineArguments
  • Added destruction code for ConstructionCallbacks in Identifier
  • Moved internal identifier map (the one with the typeid(.) names) in a static function in Identifier. This was necessary in order to destroy ALL Identifiers with the static destruction function. Before it was possible to create an Identifier with having a class instance (that would call RegisterObject) for instance by simply accessing it via getIdentifier.
  • Removed a big memory leak in Button (forgot to destroy the ConfigValueContainers)
  • Added destruction code for InputBufferListenerTuples in InputBuffer destructor.
  • Added destruction code for load and save executors in both XMLPortParam and XMLPortObject
  • Added destruction code for ConsoleCommands in GSRoot, GSGraphics and GSLevel (temporary solution anyway)
  • Deleting the CEGUILua script module seems to work properly now, one memory leak less (GUIManager.cc)
  • Added global destruction calls in Main.cc
  • Property svn:eol-style set to native
  • Property svn:mergeinfo set to (toggle deleted branches)
    /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 <iostream>
38#include <cstdlib>
39#include <cstring>
40
41namespace orxonox
42{
43    SignalHandler* SignalHandler::singletonRef_s = NULL;
44}
45
46#if ORXONOX_PLATFORM != ORXONOX_PLATFORM_WIN32
47
48#include <wait.h>
49#include <X11/Xlib.h>
50#include <X11/Xutil.h>
51#include <X11/keysym.h>
52
53namespace orxonox
54{
55    bool SignalHandler::bXAutoKeyRepeatOn_ = false;
56
57    SignalHandler::SignalHandler()
58    {
59    }
60
61    /**
62     * register signal handlers for SIGSEGV and SIGABRT
63     * @param appName path to executable eg argv[0]
64     * @param filename filename to append backtrace to
65     */
66    void SignalHandler::doCatch( const std::string & appName, const std::string & filename )
67    {
68      this->appName = appName;
69      this->filename = filename;
70
71      // prepare for restoring XAutoKeyRepeat
72      Display* display;
73      if ((display = XOpenDisplay(0)))
74      {
75        XKeyboardState oldState;
76        XGetKeyboardControl(display, &oldState);
77        if (oldState.global_auto_repeat == AutoRepeatModeOn)
78          bXAutoKeyRepeatOn_ = true;
79        else
80          bXAutoKeyRepeatOn_ = false;
81        XCloseDisplay(display);
82      }
83      else
84      {
85        std::cout << "Warning: couldn't open X display to restore XAutoKeyRepeat." << std::endl;
86        bXAutoKeyRepeatOn_ = false;
87      }
88
89
90      // make sure doCatch is only called once without calling dontCatch
91      assert( sigRecList.size() == 0 );
92
93      catchSignal( SIGSEGV );
94      catchSignal( SIGABRT );
95      catchSignal( SIGILL );
96    }
97
98    /**
99     * restore previous signal handlers
100     */
101    void SignalHandler::dontCatch()
102    {
103      for ( SignalRecList::iterator it = sigRecList.begin(); it != sigRecList.end(); it++ )
104      {
105        signal( it->signal, it->handler );
106      }
107
108      sigRecList.clear();
109    }
110
111    /**
112     * catch signal sig
113     * @param sig signal to catch
114     */
115    void SignalHandler::catchSignal( int sig )
116    {
117      sig_t handler = signal( sig, SignalHandler::sigHandler );
118
119      assert( handler != SIG_ERR );
120
121      SignalRec rec;
122      rec.signal = sig;
123      rec.handler = handler;
124
125      sigRecList.push_front( rec );
126    }
127
128    /**
129     * sigHandler is called when receiving signals
130     * @param sig
131     */
132    void SignalHandler::sigHandler( int sig )
133    {
134      for ( SignalCallbackList::iterator it = SignalHandler::getInstance().callbackList.begin(); it != SignalHandler::getInstance().callbackList.end(); it++  )
135      {
136        (*(it->cb))( it->someData );
137      }
138
139      std::string sigName = "UNKNOWN";
140
141      switch ( sig )
142      {
143        case SIGSEGV:
144          sigName = "SIGSEGV";
145          break;
146        case SIGABRT:
147          sigName = "SIGABRT";
148          break;
149        case SIGILL:
150          sigName = "SIGILL";
151          break;
152      }
153
154      if (bXAutoKeyRepeatOn_)
155      {
156        std::cout << "Trying to restore XAutoKeyRepeat" << std::endl;
157        Display* display;
158        if ((display = XOpenDisplay(0)))
159        {
160          XAutoRepeatOn(display);
161          XCloseDisplay(display);
162        }
163      }
164
165      COUT(0) << "recieved signal " << sigName.c_str() << std::endl << "try to write backtrace to file orxonox.log" << std::endl;
166
167      int sigPipe[2];
168      if ( pipe(sigPipe) == -1 )
169      {
170        perror("pipe failed!\n");
171        exit(EXIT_FAILURE);
172      }
173
174      int sigPid = fork();
175
176      if ( sigPid == -1 )
177      {
178        perror("fork failed!\n");
179        exit(EXIT_FAILURE);
180      }
181
182      // gdb will be attached to this process
183      if ( sigPid == 0 )
184      {
185        getInstance().dontCatch();
186        // wait for message from parent when it has attached gdb
187        int someData;
188
189        read( sigPipe[0], &someData, sizeof(someData) );
190
191        if ( someData != 0x12345678 )
192        {
193          COUT(0) << "something went wrong :(" << std::endl;
194        }
195
196        return;
197      }
198
199      int gdbIn[2];
200      int gdbOut[2];
201      int gdbErr[2];
202
203      if ( pipe(gdbIn) == -1 || pipe(gdbOut) == -1 || pipe(gdbErr) == -1 )
204      {
205        perror("pipe failed!\n");
206        kill( sigPid, SIGTERM );
207        waitpid( sigPid, NULL, 0 );
208        exit(EXIT_FAILURE);
209      }
210
211      int gdbPid = fork();
212      // this process will run gdb
213
214      if ( gdbPid == -1 )
215      {
216        perror("fork failed\n");
217        kill( sigPid, SIGTERM );
218        waitpid( sigPid, NULL, 0 );
219        exit(EXIT_FAILURE);
220      }
221
222      if ( gdbPid == 0 )
223      {
224        // start gdb
225
226        close(gdbIn[1]);
227        close(gdbOut[0]);
228        close(gdbErr[0]);
229
230        dup2( gdbIn[0], STDIN_FILENO );
231        dup2( gdbOut[1], STDOUT_FILENO );
232        dup2( gdbErr[1], STDERR_FILENO );
233
234        execlp( "sh", "sh", "-c", "gdb", (void*)NULL);
235      }
236
237      char cmd[256];
238      snprintf( cmd, 256, "file %s\nattach %d\nc\n", getInstance().appName.c_str(), sigPid );
239      write( gdbIn[1], cmd, strlen(cmd) );
240
241      int charsFound = 0;
242      int promptFound = 0;
243      char byte;
244      while ( read( gdbOut[0], &byte, 1 ) == 1 )
245      {
246        if (
247          charsFound == 0 && byte == '(' ||
248          charsFound == 1 && byte == 'g' ||
249          charsFound == 2 && byte == 'd' ||
250          charsFound == 3 && byte == 'b' ||
251          charsFound == 4 && byte == ')' ||
252          charsFound == 5 && byte == ' '
253            )
254              charsFound++;
255        else
256          charsFound = 0;
257
258        if ( charsFound == 6 )
259        {
260          promptFound++;
261          charsFound = 0;
262        }
263
264        if ( promptFound == 3 )
265        {
266          break;
267        }
268      }
269
270      int someData = 0x12345678;
271      write( sigPipe[1], &someData, sizeof(someData) );
272
273      write( gdbIn[1], "bt\nk\nq\n", 7 );
274
275
276      charsFound = 0;
277      promptFound = 0;
278      std::string bt;
279      while ( read( gdbOut[0], &byte, 1 ) == 1 )
280      {
281        bt += std::string( &byte, 1 );
282
283        if (
284          charsFound == 0 && byte == '(' ||
285          charsFound == 1 && byte == 'g' ||
286          charsFound == 2 && byte == 'd' ||
287          charsFound == 3 && byte == 'b' ||
288          charsFound == 4 && byte == ')' ||
289          charsFound == 5 && byte == ' '
290            )
291              charsFound++;
292        else
293          charsFound = 0;
294
295        if ( charsFound == 6 )
296        {
297          promptFound++;
298          charsFound = 0;
299          bt += "\n";
300        }
301
302        if ( promptFound == 3 )
303        {
304          break;
305        }
306      }
307
308
309      waitpid( sigPid, NULL, 0 );
310      waitpid( gdbPid, NULL, 0 );
311
312      int wsRemoved = 0;
313
314      while ( wsRemoved < 2 && bt.length() > 0 )
315      {
316        if ( bt[1] == '\n' )
317          wsRemoved++;
318        bt.erase(0, 1);
319      }
320
321      if ( bt.length() > 0 )
322        bt.erase(0, 1);
323
324      time_t now = time(NULL);
325
326      std::string timeString = "\n\n\n\n"
327                         "=======================================================\n"
328                         "= time: " + std::string(ctime(&now)) +
329             "=======================================================\n";
330      bt.insert(0, timeString);
331
332      FILE * f = fopen( getInstance().filename.c_str(), "a" );
333
334      if ( !f )
335      {
336        perror( ( std::string( "could not append to " ) + getInstance().filename ).c_str() );
337        exit(EXIT_FAILURE);
338      }
339
340      if ( fwrite( bt.c_str(), 1, bt.length(), f ) != bt.length() )
341      {
342        COUT(0) << "could not write " << bt.length() << " byte to " << getInstance().filename << std::endl;
343        exit(EXIT_FAILURE);
344      }
345
346      exit(EXIT_FAILURE);
347    }
348
349    void SignalHandler::registerCallback( SignalCallback cb, void * someData )
350    {
351      SignalCallbackRec rec;
352      rec.cb = cb;
353      rec.someData = someData;
354
355      callbackList.push_back(rec);
356    }
357}
358
359#endif /* ORXONOX_PLATFORM == ORXONOX_PLATFORM_WIN32 */
Note: See TracBrowser for help on using the repository browser.