Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Cleaned up same signal handling.

  • Loading branch information...
commit fbb468025e9b3e5d7330f98efe6589c584cd591c 1 parent 0b4d685
@brixen brixen authored
View
4 library/rubinius/configuration.rb
@@ -178,8 +178,8 @@
c.vm_variable "profiler.threshold", 1000000,
"The mininum number of nanoseconds a profiler node must have to be reported"
- c.vm_variable "vm.crash_report_path", :string,
+ c.vm_variable "vm.crash_report_path", "rubinius_last_error",
:as => "report_path",
- :description => "Set a custom path to write crash reports"
+ :description => "Name of crash report with PID appended. Written to $HOME/.rbx if no path is given"
end
View
239 vm/environment.cpp
@@ -28,10 +28,6 @@
#include <llvm/Support/ManagedStatic.h>
#endif
-#ifdef USE_EXECINFO
-#include <execinfo.h>
-#endif
-
#include "gc/finalize.hpp"
#include "signal.hpp"
@@ -50,7 +46,6 @@
#ifdef RBX_WINDOWS
#include "windows_compat.h"
#else
-#include <sys/utsname.h>
#include <dlfcn.h>
#endif
#include <fcntl.h>
@@ -72,12 +67,6 @@
namespace rubinius {
- // Used by the segfault reporter. Calculated up front to avoid
- // crashing inside the crash handler.
- static struct utsname machine_info;
- static char report_path[PATH_MAX];
- static const char* report_file_name = "rubinius_last_error";
-
Environment::Environment(int argc, char** argv)
: argc_(argc)
, argv_(0)
@@ -104,31 +93,6 @@ namespace rubinius {
load_vm_options(argc_, argv_);
root_vm = shared->new_vm();
state = new State(root_vm);
-
- uname(&machine_info);
-
- // Calculate the report_path
- if(char* home = getenv("HOME")) {
- snprintf(report_path, PATH_MAX, "%s/.rbx", home);
-
- pid_t pid = getpid();
-
- bool use_dir = false;
- struct stat s;
- if(stat(report_path, &s) != 0) {
- if(mkdir(report_path, S_IRWXU) == 0) use_dir = true;
- } else if(S_ISDIR(s.st_mode)) {
- use_dir = true;
- }
- if(use_dir) {
- snprintf(report_path + strlen(report_path), PATH_MAX, "/%s_%d", report_file_name, pid);
- } else {
- snprintf(report_path, PATH_MAX, "%s/.%s_%d", home, report_file_name, pid);
- }
- } else {
- // We check and ignore the report_path if it's 'empty'
- report_path[0] = 0;
- }
}
Environment::~Environment() {
@@ -160,192 +124,9 @@ namespace rubinius {
std::set_terminate(cpp_exception_bug);
}
-#ifndef RBX_WINDOWS
- static void null_func(int sig) {}
-#endif
-
-#ifdef USE_EXECINFO
-
- static void safe_write(int fd, const char* str, int len=0) {
- if(!len) len = strlen(str);
- if(write(fd, str, len) == 0) exit(101);
- }
-
- static void write_sig(int fd, int sig) {
- switch(sig) {
- case SIGSEGV:
- safe_write(fd, "SIGSEGV");
- break;
- case SIGBUS:
- safe_write(fd, "SIGBUS");
- break;
- case SIGILL:
- safe_write(fd, "SIGILL");
- break;
- case SIGABRT:
- safe_write(fd, "SIGABRT");
- break;
- case SIGFPE:
- safe_write(fd, "SIGFPE");
- break;
- default:
- safe_write(fd, "UNKNOWN");
- break;
- }
- }
-
- static void segv_handler(int sig) {
- static int crashing = 0;
- void* array[64];
- size_t size;
-
- // So we don't recurse!
- if(crashing) exit(101);
-
- crashing = 1;
-
- int fd = STDERR_FILENO;
-
- char* pause_env = getenv("RBX_PAUSE_ON_CRASH");
-
- if(pause_env) {
- long timeout = strtol(pause_env, NULL, 10);
- if(timeout <= 0) {
- timeout = 60;
- } else {
- timeout *= 60;
- }
- std::cerr << "\n========== CRASH (" << getpid();
- std::cerr << "), pausing for " << timeout << " seconds to attach debugger\n";
- sleep(timeout);
- }
-
- // If there is a report_path setup..
- if(report_path[0]) {
- fd = open(report_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
- // If we can't open this path, use stderr.
- if(fd == -1) fd = STDERR_FILENO;
- }
-
- // print out all the frames to stderr
- static const char header[] =
- "Rubinius Crash Report #rbxcrashreport\n\n"
- "Error: signal ";
-
- safe_write(fd, header, sizeof(header));
- write_sig(fd, sig);
-
- safe_write(fd, "\n\n[[Backtrace]]\n");
-
- // get void*'s for all entries on the stack
- size = backtrace(array, 64);
-
- backtrace_symbols_fd(array, size, fd);
-
- // Try to get the output to flush...
- safe_write(fd, "\n[[System Info]]\n");
- safe_write(fd, "sysname: ");
- safe_write(fd, machine_info.sysname);
- safe_write(fd, "\n");
- safe_write(fd, "nodename: ");
- safe_write(fd, machine_info.nodename);
- safe_write(fd, "\n");
- safe_write(fd, "release: ");
- safe_write(fd, machine_info.release);
- safe_write(fd, "\n");
- safe_write(fd, "version: ");
- safe_write(fd, machine_info.version);
- safe_write(fd, "\n");
- safe_write(fd, "machine: ");
- safe_write(fd, machine_info.machine);
- safe_write(fd, "\n");
-
- // If we didn't write to stderr, then close the file down and
- // write info to stderr about reporting the error.
- if(fd != STDERR_FILENO) {
- close(fd);
- safe_write(STDERR_FILENO, "\n---------------------------------------------\n");
- safe_write(STDERR_FILENO, "CRASH: A fatal error has occurred.\n\nBacktrace:\n");
- backtrace_symbols_fd(array, size, 2);
- safe_write(STDERR_FILENO, "\n\n");
- safe_write(STDERR_FILENO, "Wrote full error report to: ");
- safe_write(STDERR_FILENO, report_path);
- safe_write(STDERR_FILENO, "\nRun 'rbx report' to submit this crash report!\n");
- }
-
- exit(100);
- }
-#endif
-
- static void quit_handler(int sig) {
-
- if(getpgrp() == getpid()) {
- static const char msg[] = "Terminated: signal ";
- if(write(STDERR_FILENO, msg, sizeof(msg)) == 0) exit(1);
-
- switch(sig) {
- case SIGTERM:
- if(write(STDERR_FILENO, "SIGTERM\n", 8) == 0) exit(1);
- break;
-#ifndef RBX_WINDOWS
- case SIGHUP:
- if(write(STDERR_FILENO, "SIGHUP\n", 7) == 0) exit(1);
- break;
- case SIGUSR1:
- if(write(STDERR_FILENO, "SIGUSR1\n", 8) == 0) exit(1);
- break;
- case SIGUSR2:
- if(write(STDERR_FILENO, "SIGUSR2\n", 8) == 0) exit(1);
- break;
-#endif
- default:
- if(write(STDERR_FILENO, "UNKNOWN\n", 9) == 0) exit(1);
- break;
- }
- }
-
- _exit(1);
- }
-
void Environment::start_signals() {
-#ifndef RBX_WINDOWS
- struct sigaction action;
- action.sa_handler = null_func;
- action.sa_flags = 0;
- sigfillset(&action.sa_mask);
- sigaction(SIGVTALRM, &action, NULL);
-#endif
-
state->vm()->set_run_signals(true);
- signal_handler_ = new SignalHandler(state);
-
-#ifndef RBX_WINDOWS
- // Ignore sigpipe.
- signal(SIGPIPE, SIG_IGN);
-
- // Some extensions expect SIGALRM to be defined, because MRI does.
- // We'll just use a noop for it.
- signal(SIGALRM, null_func);
-
- // If we have execinfo, setup some crash handlers
-#ifdef USE_EXECINFO
- if(!getenv("DISABLE_SEGV")) {
- signal(SIGSEGV, segv_handler);
- signal(SIGBUS, segv_handler);
- signal(SIGILL, segv_handler);
- signal(SIGFPE, segv_handler);
- signal(SIGABRT, segv_handler);
- }
-#endif // USE_EXEC_INFO
-
- // Setup some other signal that normally just cause the process
- // to terminate so that we print out a message, then terminate.
- signal(SIGHUP, quit_handler);
- signal(SIGUSR1, quit_handler);
- signal(SIGUSR2, quit_handler);
-#endif // ifndef RBX_WINDOWS
-
- signal(SIGTERM, quit_handler);
+ signal_handler_ = new SignalHandler(state, config);
}
void Environment::start_finalizer() {
@@ -478,24 +259,6 @@ namespace rubinius {
start_agent(port);
}
- if(config.report_path.set_p()) {
- // Test that we can actually use this path
- int fd = open(config.report_path, O_RDONLY | O_CREAT, 0666);
- if(!fd) {
- char buf[RBX_STRERROR_BUFSIZE];
- char* err = RBX_STRERROR(errno, buf, RBX_STRERROR_BUFSIZE);
- std::cerr << "Unable to use " << config.report_path << " for crash reports.\n";
- std::cerr << "Unable to open path: " << err << "\n";
-
- // Don't use the home dir path even, just use stderr
- report_path[0] = 0;
- } else {
- close(fd);
- unlink(config.report_path);
- strncpy(report_path, config.report_path, sizeof(report_path) - 1);
- }
- }
-
state->shared().set_use_capi_lock(config.capi_lock);
}
View
211 vm/signal.cpp
@@ -1,6 +1,7 @@
#include "config.h"
#include "vm.hpp"
#include "signal.hpp"
+#include "configuration.hpp"
#include "builtin/module.hpp"
#include "builtin/array.hpp"
@@ -9,6 +10,7 @@
#include "builtin/module.hpp"
#include "builtin/class.hpp"
+#include <string>
#include <iostream>
#include <fcntl.h>
@@ -16,15 +18,31 @@
#include "dtrace/dtrace.h"
-#ifndef RBX_WINDOWS
-#include <sys/select.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#ifdef USE_EXECINFO
+#include <execinfo.h>
#endif
+#ifdef RBX_WINDOWS
#include "windows_compat.h"
+#else
+#include <dlfcn.h>
+#include <sys/utsname.h>
+#include <sys/select.h>
+#endif
namespace rubinius {
static SignalHandler* signal_handler_ = 0;
+ // Used by the segfault reporter. Calculated up front to avoid
+ // crashing inside the crash handler.
+ static struct utsname machine_info;
+ static char report_path[PATH_MAX];
+
Object* signal_handler_tramp(STATE) {
state->shared().signal_handler()->perform(state);
GCTokenImpl gct;
@@ -32,7 +50,7 @@ namespace rubinius {
return cNil;
}
- SignalHandler::SignalHandler(STATE)
+ SignalHandler::SignalHandler(STATE, Configuration& config)
: AuxiliaryThread()
, shared_(state->shared())
, target_(state->vm())
@@ -55,6 +73,8 @@ namespace rubinius {
worker_cond_.init();
pause_cond_.init();
+ setup_default_handlers(config.report_path.value);
+
start_thread(state);
}
@@ -252,4 +272,189 @@ namespace rubinius {
return true;
}
+
+ static void null_func(int sig) {}
+
+ static void safe_write(int fd, const char* str, int len=0) {
+ if(!len) len = strlen(str);
+ if(write(fd, str, len) == 0) exit(101);
+ }
+
+ static void write_sig(int fd, int sig) {
+ switch(sig) {
+ case SIGSEGV:
+ safe_write(fd, "SIGSEGV");
+ break;
+ case SIGBUS:
+ safe_write(fd, "SIGBUS");
+ break;
+ case SIGILL:
+ safe_write(fd, "SIGILL");
+ break;
+ case SIGABRT:
+ safe_write(fd, "SIGABRT");
+ break;
+ case SIGFPE:
+ safe_write(fd, "SIGFPE");
+ break;
+ default:
+ safe_write(fd, "UNKNOWN");
+ break;
+ }
+ }
+
+ static void segv_handler(int sig) {
+ void* array[64];
+ size_t size;
+ int fd = STDERR_FILENO;
+ char* pause_env = getenv("RBX_PAUSE_ON_CRASH");
+
+ if(pause_env) {
+ long timeout = strtol(pause_env, NULL, 10);
+ if(timeout <= 0) {
+ timeout = 60;
+ } else {
+ timeout *= 60;
+ }
+ std::cerr << "\n========== CRASH (" << getpid();
+ std::cerr << "), pausing for " << timeout << " seconds to attach debugger\n";
+ sleep(timeout);
+ }
+
+ // If there is a report_path setup..
+ if(report_path[0]) {
+ fd = open(report_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ // If we can't open this path, use stderr.
+ if(fd == -1) fd = STDERR_FILENO;
+ }
+
+ // print out all the frames to stderr
+ static const char header[] =
+ "Rubinius Crash Report #rbxcrashreport\n\n"
+ "Error: signal ";
+
+ safe_write(fd, header, sizeof(header));
+ write_sig(fd, sig);
+
+ safe_write(fd, "\n\n[[Backtrace]]\n");
+
+ // get void*'s for all entries on the stack
+ size = backtrace(array, 64);
+
+ backtrace_symbols_fd(array, size, fd);
+
+ // Try to get the output to flush...
+ safe_write(fd, "\n[[System Info]]\n");
+ safe_write(fd, "sysname: ");
+ safe_write(fd, machine_info.sysname);
+ safe_write(fd, "\n");
+ safe_write(fd, "nodename: ");
+ safe_write(fd, machine_info.nodename);
+ safe_write(fd, "\n");
+ safe_write(fd, "release: ");
+ safe_write(fd, machine_info.release);
+ safe_write(fd, "\n");
+ safe_write(fd, "version: ");
+ safe_write(fd, machine_info.version);
+ safe_write(fd, "\n");
+ safe_write(fd, "machine: ");
+ safe_write(fd, machine_info.machine);
+ safe_write(fd, "\n");
+
+ // If we didn't write to stderr, then close the file down and
+ // write info to stderr about reporting the error.
+ if(fd != STDERR_FILENO) {
+ close(fd);
+ safe_write(STDERR_FILENO, "\n---------------------------------------------\n");
+ safe_write(STDERR_FILENO, "CRASH: A fatal error has occurred.\n\nBacktrace:\n");
+ backtrace_symbols_fd(array, size, 2);
+ safe_write(STDERR_FILENO, "\n\n");
+ safe_write(STDERR_FILENO, "Wrote full error report to: ");
+ safe_write(STDERR_FILENO, report_path);
+ safe_write(STDERR_FILENO, "\nRun 'rbx report' to submit this crash report!\n");
+ }
+
+ raise(sig);
+ }
+
+ void SignalHandler::setup_default_handlers(std::string path) {
+#ifndef RBX_WINDOWS
+ report_path[0] = 0;
+
+ // Calculate the report_path
+ if(path.rfind("/") == std::string::npos) {
+ if(char* home = getenv("HOME")) {
+ snprintf(report_path, PATH_MAX, "%s/.rbx", home);
+
+ pid_t pid = getpid();
+
+ bool use_dir = false;
+ struct stat s;
+ if(stat(report_path, &s) != 0) {
+ if(mkdir(report_path, S_IRWXU) == 0) use_dir = true;
+ } else if(S_ISDIR(s.st_mode)) {
+ use_dir = true;
+ }
+
+ if(use_dir) {
+ snprintf(report_path + strlen(report_path), PATH_MAX, "/%s_%d",
+ path.c_str(), pid);
+ } else {
+ snprintf(report_path, PATH_MAX, "%s/.%s_%d", home, path.c_str(), pid);
+ }
+ }
+ }
+
+ if(!report_path[0]) {
+ strncpy(report_path, path.c_str(), PATH_MAX-1);
+ }
+
+ // Test that we can actually use this path.
+ int fd = open(report_path, O_RDONLY | O_CREAT, 0666);
+ if(!fd) {
+ char buf[RBX_STRERROR_BUFSIZE];
+ char* err = RBX_STRERROR(errno, buf, RBX_STRERROR_BUFSIZE);
+ std::cerr << "Unable to use " << report_path << " for crash reports.\n";
+ std::cerr << "Unable to open path: " << err << "\n";
+
+ // Don't use the home dir path even, just use stderr
+ report_path[0] = 0;
+ } else {
+ close(fd);
+ unlink(report_path);
+ }
+
+ // Get the machine info.
+ uname(&machine_info);
+
+ struct sigaction action;
+ action.sa_handler = null_func;
+ action.sa_flags = 0;
+ sigfillset(&action.sa_mask);
+ sigaction(SIGVTALRM, &action, NULL);
+
+ // Some extensions expect SIGALRM to be defined, because MRI does.
+ // We'll just use a noop for it.
+ action.sa_handler = null_func;
+ sigaction(SIGALRM, &action, NULL);
+
+ // Ignore sigpipe.
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+
+#ifdef USE_EXECINFO
+ // If we have execinfo, setup some crash handlers
+ if(!getenv("DISABLE_SEGV")) {
+ action.sa_handler = segv_handler;
+ sigaction(SIGSEGV, &action, NULL);
+ sigaction(SIGBUS, &action, NULL);
+ sigaction(SIGILL, &action, NULL);
+ sigaction(SIGFPE, &action, NULL);
+ sigaction(SIGABRT, &action, NULL);
+ }
+#endif // USE_EXEC_INFO
+#else
+ signal(SIGTERM, quit_handler);
+#endif // ifndef RBX_WINDOWS
+ }
}
View
6 vm/signal.hpp
@@ -7,10 +7,12 @@
#include "gc/root.hpp"
#include <list>
+#include <string>
namespace rubinius {
class VM;
class State;
+ class Configuration;
struct CallFrame;
class Thread;
@@ -40,9 +42,11 @@ namespace rubinius {
eCustom
};
- SignalHandler(STATE);
+ SignalHandler(STATE, Configuration& config);
virtual ~SignalHandler();
+ void setup_default_handlers(std::string path);
+
void perform(STATE);
void add_signal(State*, int sig, HandlerType type = eCustom);
View
4 vm/util/configuration.hpp
@@ -160,9 +160,9 @@ namespace config {
public:
std::string value;
- String(Configuration* config, const char* name)
+ String(Configuration* config, const char* name, const char* def = "")
: ConfigItem(config, name)
- , value("")
+ , value(def)
{}
virtual void set(const char* str) {
Please sign in to comment.
Something went wrong with that request. Please try again.