Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Nov 10, 2008, 12:05:03 AM (16 years ago)
Author:
landauf
Message:

merged revisions 2111-2170 from objecthierarchy branch back to trunk.

Location:
code/trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • code/trunk

  • code/trunk/src/util

  • code/trunk/src/util/SignalHandler.cc

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