Skip to content

Commit

Permalink
Refactor Environment/cli.cpp around
Browse files Browse the repository at this point in the history
  • Loading branch information
Evan Phoenix committed Dec 11, 2009
1 parent 35b6a84 commit db6659b
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 169 deletions.
13 changes: 0 additions & 13 deletions vm/config_parser.cpp
Expand Up @@ -38,19 +38,6 @@ namespace rubinius {
}
}


void ConfigParser::process_argv(int argc, char** argv) {
for(int i=1; i < argc; i++) {
char* arg = argv[i];
if(strncmp(arg, "-X", 2) == 0) {
import_line(arg + 2);
continue;
}

if(arg[0] != '-' || strcmp(arg, "--") == 0) return;
}
}

bool ConfigParser::load_file(std::string path) {
std::ifstream stream(path.c_str());
if(!stream) return false;
Expand Down
1 change: 0 additions & 1 deletion vm/config_parser.hpp
Expand Up @@ -30,7 +30,6 @@ namespace rubinius {
virtual ~ConfigParser();

bool load_file(std::string path);
void process_argv(int argc, char** argv);
Entry* parse_line(const char* line);
void import_line(const char* line);
void import_many(std::string string);
Expand Down
103 changes: 28 additions & 75 deletions vm/drivers/cli.cpp
Expand Up @@ -14,39 +14,7 @@
using namespace std;
using namespace rubinius;

/* Loads the runtime kernel files. They're stored in /kernel.
* These files consist of classes needed to bootstrap the kernel
* and just get things started in general.
*
* @param root [String] The file root for /kernel. This expects to find
* alpha.rbc (will compile if not there).
* @param env [Environment&] The environment for Rubinius. It is the uber
* manager for multiple VMs and process-Ruby interaction.
*/
static void load_runtime_kernel(Environment& env, std::string root) {
std::string dirs = root + "/index";
std::ifstream stream(dirs.c_str());
if(!stream) {
std::cout << "It appears that " << root << "/index is missing.\n";
exit(1);
}

// Load the ruby file to prepare for bootstrapping Ruby!
// The bootstrapping for the VM is already done by the time we're here.
env.run_file(root + "/alpha.rbc");

while(!stream.eof()) {
std::string line;

stream >> line;
stream.get(); // eat newline

// skip empty lines
if(line.size() == 0) continue;

env.load_directory(root + "/" + line);
}
}
static void check_directory(std::string root);

/* The main function here handles the CL arguments passed to it.
* It then boots the VM, runs the appropriate file (`loader`),
Expand All @@ -62,12 +30,9 @@ static void load_runtime_kernel(Environment& env, std::string root) {
* function does not deal with that subject.
*/
int main(int argc, char** argv) {
Environment env;
Environment env(argc, argv);
env.setup_cpp_terminate();

env.state->init_stack_size();
env.state->set_stack_start(&env);

try {
if(const char* var = getenv("RBX_OPTIONS")) {
env.load_string(var);
Expand All @@ -77,47 +42,12 @@ int main(int argc, char** argv) {
env.load_conf(path);
}

env.load_config_argv(argc, argv);

const char* runtime = getenv("RBX_RUNTIME");

if(!runtime) {
struct stat st;

runtime = RBX_RUNTIME;
if(stat(runtime, &st) == -1 || !S_ISDIR(st.st_mode)) {

std::cerr << "ERROR: unable to find runtime directory" << std::endl;
std::cerr << std::endl;
std::cerr << "Rubinius was configured to find the runtime directory at:" << std::endl;
std::cerr << std::endl << " " << runtime << std::endl;
std::cerr << std::endl;
std::cerr << "but that directory does not exist." << std::endl;
std::cerr << std::endl;
std::cerr << "Set the environment variable RBX_RUNTIME to the location" << std::endl;
std::cerr << "of the directory with the compiled Rubinius kernel files." << std::endl;
std::cerr << std::endl;
std::cerr << "You may have configured Rubinius for a different install" << std::endl;
std::cerr << "directory but you have not run \'rake install\' yet." << std::endl;
std::cerr << std::endl;

exit(1);
}
}

std::string root = std::string(runtime);

env.load_platform_conf(root);
env.boot_vm();
env.load_argv(argc, argv);

load_runtime_kernel(env, std::string(root));

std::string loader = root + "/loader.rbc";
if(!runtime) runtime = RBX_RUNTIME;

env.enable_preemption();
env.start_signals();
env.run_file(loader);
check_directory(runtime);
env.run_from_filesystem(runtime);

} catch(Assertion *e) {
std::cout << "VM Assertion:" << std::endl;
Expand Down Expand Up @@ -173,3 +103,26 @@ int main(int argc, char** argv) {
env.halt();
return env.exit_code();
}

static void check_directory(std::string runtime) {
struct stat st;

if(stat(runtime.c_str(), &st) == -1 || !S_ISDIR(st.st_mode)) {

std::cerr << "ERROR: unable to find runtime directory" << std::endl;
std::cerr << std::endl;
std::cerr << "Rubinius was configured to find the runtime directory at:" << std::endl;
std::cerr << std::endl << " " << runtime << std::endl;
std::cerr << std::endl;
std::cerr << "but that directory does not exist." << std::endl;
std::cerr << std::endl;
std::cerr << "Set the environment variable RBX_RUNTIME to the location" << std::endl;
std::cerr << "of the directory with the compiled Rubinius kernel files." << std::endl;
std::cerr << std::endl;
std::cerr << "You may have configured Rubinius for a different install" << std::endl;
std::cerr << "directory but you have not run \'rake install\' yet." << std::endl;
std::cerr << std::endl;

exit(1);
}
}
138 changes: 114 additions & 24 deletions vm/environment.cpp
Expand Up @@ -39,35 +39,26 @@

namespace rubinius {

Environment::Environment()
: agent(0)
Environment::Environment(int argc, char** argv)
: argc_(argc)
, argv_(argv)
, agent(0)
{
#ifdef ENABLE_LLVM
assert(llvm::llvm_start_multithreaded() && "llvm doesn't support threading!");
#endif

shared = new SharedState(config, config_parser);
state = shared->new_vm();

VM::init_stack_size();
}

Environment::~Environment() {
VM::discard(state);
SharedState::discard(shared);
}

void Environment::load_config_argv(int argc, char** argv) {
config_parser.process_argv(argc, argv);
config_parser.update_configuration(config);

if(config.print_config > 1) {
std::cout << "========= Configuration =========\n";
config.print(true);
std::cout << "=================================\n";
} else if(config.print_config) {
config.print();
}
}

void cpp_exception_bug() {
std::cerr << "[BUG] Uncaught C++ internal exception\n";
std::cerr << "So sorry, it appears that you've encountered an internal\n";
Expand All @@ -83,8 +74,44 @@ namespace rubinius {
std::set_terminate(cpp_exception_bug);
}

// Trampoline to call scheduler_loop()
static void* __thread_tramp__(void* arg) {
Environment* env = static_cast<Environment*>(arg);
env->scheduler_loop();
return NULL;
}

// Runs forever, telling the VM to reschedule threads ever 10 milliseconds
void Environment::scheduler_loop() {
// First off, we don't want this thread ever receiving a signal.
sigset_t mask;
sigfillset(&mask);
if(pthread_sigmask(SIG_SETMASK, &mask, NULL) != 0) {
abort();
}

struct timespec requested;
struct timespec actual;

requested.tv_sec = 0;
requested.tv_nsec = 10000000; // 10 milliseconds

Interrupts& interrupts = shared->interrupts;

for(;;) {
nanosleep(&requested, &actual);
if(interrupts.enable_preempt) {
interrupts.set_timer();
}
}
}

// Create the preemption thread and call scheduler_loop() in the new thread
void Environment::enable_preemption() {
state->setup_preemption();
if(pthread_create(&preemption_thread_, NULL, __thread_tramp__, this) != 0) {
std::cerr << "Unable to create preemption thread!\n";
exit(1);
}
}

static void null_func(int sig) {}
Expand Down Expand Up @@ -216,12 +243,33 @@ namespace rubinius {
process_xflags = false;
}

if(!process_xflags || strncmp(arg, "-X", 2) != 0) {
if(process_xflags && strncmp(arg, "-X", 2) == 0) {
config_parser.import_line(arg + 2);
} else {
ary->set(state, which_arg++, String::create(state, arg)->taint(state));
}
}

state->set_const("ARGV", ary);

// Now finish up with the config
//
// Respect -Xint
if(config.jit_force_off) {
config.jit_enabled.set("no");
}

if(config.qa_port > 0) start_agent(config.qa_port);

config_parser.update_configuration(config);

if(config.print_config > 1) {
std::cout << "========= Configuration =========\n";
config.print(true);
std::cout << "=================================\n";
} else if(config.print_config) {
config.print();
}
}

void Environment::load_directory(std::string dir) {
Expand Down Expand Up @@ -269,13 +317,6 @@ namespace rubinius {
}

void Environment::boot_vm() {
if(config.qa_port > 0) start_agent(config.qa_port);

// Respect -Xint
if(config.jit_force_off) {
config.jit_enabled.set("no");
}

state->initialize();
state->boot();

Expand Down Expand Up @@ -357,4 +398,53 @@ namespace rubinius {
if(config.qa_verbose) agent->set_verbose();
agent->run();
}

/* Loads the runtime kernel files. They're stored in /kernel.
* These files consist of classes needed to bootstrap the kernel
* and just get things started in general.
*
* @param root [String] The file root for /kernel. This expects to find
* alpha.rbc (will compile if not there).
* @param env [Environment&] The environment for Rubinius. It is the uber
* manager for multiple VMs and process-Ruby interaction.
*/
void Environment::load_kernel(std::string root) {
std::string dirs = root + "/index";
std::ifstream stream(dirs.c_str());
if(!stream) {
std::cerr << "It appears that " << root << "/index is missing.\n";
exit(1);
}

// Load the ruby file to prepare for bootstrapping Ruby!
// The bootstrapping for the VM is already done by the time we're here.
run_file(root + "/alpha.rbc");

while(!stream.eof()) {
std::string line;

stream >> line;
stream.get(); // eat newline

// skip empty lines
if(line.size() == 0) continue;

load_directory(root + "/" + line);
}
}

void Environment::run_from_filesystem(std::string root) {
int i = 0;
state->set_stack_start(&i);

load_platform_conf(root);
boot_vm();
load_argv(argc_, argv_);

load_kernel(root);

enable_preemption();
start_signals();
run_file(root + "/loader.rbc");
}
}
17 changes: 15 additions & 2 deletions vm/environment.hpp
Expand Up @@ -14,6 +14,12 @@ namespace rubinius {
class QueryAgent;

class Environment {
// The thread used to trigger preemptive thread switching
pthread_t preemption_thread_;

int argc_;
char** argv_;

public:
SharedState* shared;
VM* state;
Expand All @@ -23,20 +29,27 @@ namespace rubinius {
Configuration config;

public:
Environment();
Environment(int argc, char** argv);
~Environment();

void setup_cpp_terminate();

void load_config_argv(int argc, char** argv);
void load_argv(int argc, char** argv);
void load_kernel(std::string root);
void load_directory(std::string dir);
void load_platform_conf(std::string dir);
void load_conf(std::string path);
void load_string(std::string str);
void run_file(std::string path);
void enable_preemption();
void run_from_filesystem(std::string root);
void boot_vm();

void enable_preemption();
// Run in a seperate thread to provide preemptive thread
// scheduling.
void scheduler_loop();

void halt();
int exit_code();
void start_signals();
Expand Down

0 comments on commit db6659b

Please sign in to comment.