Changeset 2111 for code/branches/objecthierarchy/src/util/SignalHandler.cc
- Timestamp:
- Nov 2, 2008, 12:38:26 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
code/branches/objecthierarchy/src/util/SignalHandler.cc
r2101 r2111 40 40 #include <cstring> 41 41 42 SignalHandler * SignalHandler::singletonRef = NULL; 42 namespace orxonox 43 { 44 SignalHandler * SignalHandler::singletonRef = NULL; 45 } 43 46 44 47 #if ORXONOX_PLATFORM != ORXONOX_PLATFORM_WIN32 … … 49 52 #include <X11/keysym.h> 50 53 51 bool SignalHandler::bXAutoKeyRepeatOn_ = false; 52 53 SignalHandler::SignalHandler() 54 namespace orxonox 54 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 } 55 358 } 56 359 57 /**58 * register signal handlers for SIGSEGV and SIGABRT59 * @param appName path to executable eg argv[0]60 * @param filename filename to append backtrace to61 */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 XAutoKeyRepeat68 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 else76 bXAutoKeyRepeatOn_ = false;77 XCloseDisplay(display);78 }79 else80 {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 dontCatch87 assert( sigRecList.size() == 0 );88 89 catchSignal( SIGSEGV );90 catchSignal( SIGABRT );91 catchSignal( SIGILL );92 }93 94 /**95 * restore previous signal handlers96 */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 sig109 * @param sig signal to catch110 */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 signals126 * @param sig127 */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 process179 if ( sigPid == 0 )180 {181 getInstance()->dontCatch();182 // wait for message from parent when it has attached gdb183 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 gdb209 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 gdb221 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 else252 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 else289 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 354 360 #endif /* ORXONOX_PLATFORM == ORXONOX_PLATFORM_WIN32 */
Note: See TracChangeset
for help on using the changeset viewer.