Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/util/signal_handler.cc @ 10111

Last change on this file since 10111 was 9406, checked in by bensch, 18 years ago

orxonox/trunk: merged the proxy back

merged with commandsvn merge -r9346:HEAD https://svn.orxonox.net/orxonox/branches/proxy .

no conflicts

File size: 6.0 KB
RevLine 
[7361]1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11### File Specific:
12   main-programmer: Christoph Renner
13   co-programmer: ...
14*/
15
16#include "signal_handler.h"
[7461]17#include <assert.h>
[7361]18
[8228]19SignalHandler * SignalHandler::singletonRef = NULL;
20
[7439]21#ifndef __WIN32__
22
[9240]23#include <wait.h>
24
[7361]25SignalHandler::SignalHandler()
26{
27}
28
[9406]29/**
30 * register signal handlers for SIGSEGV and SIGABRT
31 * @param appName path to executable eg argv[0]
32 * @param fileName filename to append backtrace to
33 */
34void SignalHandler::doCatch( const std::string & appName, const std::string & fileName )
[7361]35{
36  this->appName = appName;
[9406]37  this->fileName = fileName;
38 
39  // make sure doCatch is only called once without calling dontCatch
40  assert( sigRecList.size() == 0 );
[7461]41
[7361]42  catchSignal( SIGSEGV );
43  catchSignal( SIGABRT );
44}
45
[9406]46/**
47 * restore previous signal handlers
48 */
[7361]49void SignalHandler::dontCatch()
50{
51  for ( SignalRecList::iterator it = sigRecList.begin(); it != sigRecList.end(); it++ )
52  {
53    signal( it->signal, it->handler );
54  }
55
56  sigRecList.clear();
57}
58
[9406]59/**
60 * catch signal sig
61 * @param sig signal to catch
62 */
[7361]63void SignalHandler::catchSignal( int sig )
64{
[8293]65  sig_t handler = signal( sig, SignalHandler::sigHandler );
[7361]66
67  assert( handler != SIG_ERR );
68
69  SignalRec rec;
70  rec.signal = sig;
71  rec.handler = handler;
72
73  sigRecList.push_front( rec );
74}
75
[9406]76/**
77 * sigHandler is called when receiving signals
78 * @param sig
79 */
[7361]80void SignalHandler::sigHandler( int sig )
81{
[8228]82  for ( SignalCallbackList::iterator it = SignalHandler::getInstance()->callbackList.begin(); it != SignalHandler::getInstance()->callbackList.end(); it++  )
83  {
84    (*(it->cb))( it->someData );
85  }
[8293]86
87  std::string sigName = "UNKNOWN";
[8228]88 
[7361]89  switch ( sig )
90  {
91    case SIGSEGV:
92      sigName = "SIGSEGV";
93      break;
94    case SIGABRT:
95      sigName = "SIGABRT";
96      break;
97  }
98
99  printf( "recieved signal %s\ntry to write backtrace to file orxonox.backtrace\n", sigName.c_str() );
[9240]100 
101  int sigPipe[2];
102  if ( pipe(sigPipe) == -1 )
103  {
104    perror("pipe failed!\n");
105    exit(EXIT_FAILURE);
106  }
107 
108  int sigPid = fork();
[7361]109
[9240]110  if ( sigPid == -1 )
111  {
112    perror("fork failed!\n");
113    exit(EXIT_FAILURE);
114  }
[7361]115
[9240]116  // gdb will be attached to this process
117  if ( sigPid == 0 )
118  {
119    getInstance()->dontCatch();
120    // wait for message from parent when it has attached gdb
121    int someData;
[7461]122
[9240]123    read( sigPipe[0], &someData, sizeof(someData) );
[7361]124
[9240]125    if ( someData != 0x12345678 )
126    {
127      printf("something went wrong :(\n");
128    }
[7361]129
[9240]130    return;
131  }
[8068]132
[9240]133  int gdbIn[2];
134  int gdbOut[2];
135  int gdbErr[2];
136 
137  if ( pipe(gdbIn) == -1 || pipe(gdbOut) == -1 || pipe(gdbErr) == -1 )
[7361]138  {
[9240]139    perror("pipe failed!\n");
140    kill( sigPid, SIGTERM );
141    waitpid( sigPid, NULL, 0 );
142    exit(EXIT_FAILURE);
143  }
[7361]144
[9240]145  int gdbPid = fork();
146  // this process will run gdb
147 
148  if ( gdbPid == -1 )
149  {
150    perror("fork failed\n");
151    kill( sigPid, SIGTERM );
152    waitpid( sigPid, NULL, 0 );
153    exit(EXIT_FAILURE);
[7361]154  }
[9240]155 
156  if ( gdbPid == 0 )
[7361]157  {
[9240]158    // start gdb
159   
160    close(gdbIn[1]);
161    close(gdbOut[0]);
162    close(gdbErr[0]);
163
164    dup2( gdbIn[0], STDIN_FILENO );
165    dup2( gdbOut[1], STDOUT_FILENO );
166    dup2( gdbErr[1], STDERR_FILENO );
167   
168    execlp( "sh", "sh", "-c", "gdb", (void*)NULL);
169  }
170
171  char cmd[256];
172  snprintf( cmd, 256, "file %s\nattach %d\nc\n", getInstance()->appName.c_str(), sigPid );
173  write( gdbIn[1], cmd, strlen(cmd) );
174
175  int charsFound = 0;
176  int promptFound = 0;
177  char byte;
178  while ( read( gdbOut[0], &byte, 1 ) == 1 )
179  {
180    if ( 
181      charsFound == 0 && byte == '(' ||
182      charsFound == 1 && byte == 'g' ||
183      charsFound == 2 && byte == 'd' ||
184      charsFound == 3 && byte == 'b' ||
185      charsFound == 4 && byte == ')' ||
186      charsFound == 5 && byte == ' '
187        )
188          charsFound++;
[9406]189    else
190      charsFound = 0;
[9240]191
192    if ( charsFound == 6 )
[7361]193    {
[9240]194      promptFound++;
195      charsFound = 0;
196    }
[7361]197
[9240]198    if ( promptFound == 3 )
199    {
200      break;
[7361]201    }
[9240]202  }
203 
204  int someData = 0x12345678;
205  write( sigPipe[1], &someData, sizeof(someData) );
[7461]206
[9406]207  write( gdbIn[1], "bt\nk\nq\n", 7 );
[9240]208
209 
210  charsFound = 0;
211  promptFound = 0;
212  std::string bt;
213  while ( read( gdbOut[0], &byte, 1 ) == 1 )
214  {
215    bt += std::string( &byte, 1 );
216
217    if ( 
218      charsFound == 0 && byte == '(' ||
219      charsFound == 1 && byte == 'g' ||
220      charsFound == 2 && byte == 'd' ||
221      charsFound == 3 && byte == 'b' ||
222      charsFound == 4 && byte == ')' ||
223      charsFound == 5 && byte == ' '
224        )
225          charsFound++;
[9406]226    else
227      charsFound = 0;
[9240]228
229    if ( charsFound == 6 )
[7366]230    {
[9240]231      promptFound++;
232      charsFound = 0;
233      bt += "\n";
[7366]234    }
[9240]235
[9406]236    if ( promptFound == 3 )
[9240]237    {
238      break;
239    }
[7361]240  }
[9240]241
242
243  waitpid( sigPid, NULL, 0 );
244  waitpid( gdbPid, NULL, 0 );
245 
246  int wsRemoved = 0;
247
248  while ( wsRemoved < 2 && bt.length() > 0 )
249  {
250    if ( bt[1] == '\n' )
251      wsRemoved++;
252    bt.erase(0, 1);
253  }
254
255  if ( bt.length() > 0 )
256    bt.erase(0, 1);
257
258  time_t now = time(NULL);
259
260  std::string timeString = "\n\n\n\n"
261                           "=======================================================\n"
262                           "= time: " + std::string(ctime(&now)) +
263                           "=======================================================\n";
264  bt.insert(0, timeString);
265 
[9406]266  FILE * f = fopen( getInstance()->fileName.c_str(), "a" );
[9240]267
268  if ( !f )
269  {
[9406]270    perror( ( std::string( "could not append to " ) + getInstance()->fileName ).c_str() );
[9240]271    exit(EXIT_FAILURE);
272  }
273
274  if ( fwrite( bt.c_str(), 1, bt.length(), f ) != bt.length() )
275  {
[9406]276    printf( ( std::string("could not write %d byte to ") + getInstance()->fileName ).c_str(), bt.length());
[9240]277    exit(EXIT_FAILURE);
278  }
279
280  exit(EXIT_FAILURE);
[7361]281}
282
[8228]283void SignalHandler::registerCallback( SignalCallback cb, void * someData )
284{
285  SignalCallbackRec rec;
286  rec.cb = cb;
287  rec.someData = someData;
288 
289  callbackList.push_back(rec);
290}
291
[7439]292#endif /* __WIN32__ */
Note: See TracBrowser for help on using the repository browser.