Permalink
Browse files

Add VMManager, fix exit to behave well

  • Loading branch information...
Evan Phoenix
Evan Phoenix committed Feb 6, 2009
1 parent 07f1f6c commit 6cfae75edcd9ad8f59c0cef3f8b77ebf72f8dd69
@@ -5,10 +5,12 @@ def initialize
def get_variable(name)
Ruby.primitive :vm_get_config_item
+ raise PrimitiveFailure, "Unable to get config variable"
end
def get_section(section)
Ruby.primitive :vm_get_config_section
+ raise PrimitiveFailure, "Unable to get config section"
end
def section(section)
View
@@ -95,8 +95,8 @@ namespace rubinius {
}
Object* System::vm_exit(STATE, Fixnum* code) {
- ::exit(code->to_native());
- return code;
+ state->thread_state()->raise_exit(code);
+ return NULL;
}
Fixnum* System::vm_fork(VM* state)
View
@@ -90,7 +90,7 @@ int main(int argc, char** argv) {
env.enable_preemption();
env.run_file(loader);
- return 0;
+ return env.exit_code();
} catch(Assertion *e) {
std::cout << "VM Assertion:" << std::endl;
View
@@ -26,13 +26,16 @@
namespace rubinius {
Environment::Environment() {
- state = new VM(VM::default_bytes, false);
+ shared = manager.create_shared_state();
+ state = manager.create_vm(shared);
+ state->initialize(VM::default_bytes);
+
TaskProbe* probe = TaskProbe::create(state);
state->probe.set(probe->parse_env(NULL) ? probe : (TaskProbe*)Qnil);
}
Environment::~Environment() {
- delete state;
+ manager.destroy_vm(state);
}
void Environment::enable_preemption() {
@@ -137,4 +140,16 @@ namespace rubinius {
delete cf;
}
+ int Environment::exit_code() {
+ if(state->thread_state()->raise_reason() == cExit) {
+ if(Fixnum* fix = try_as<Fixnum>(state->thread_state()->raise_value())) {
+ return fix->to_native();
+ } else {
+ return -1;
+ }
+ }
+
+ return 0;
+ }
+
}
View
@@ -5,11 +5,14 @@
#include <stdexcept>
#include "vm.hpp"
+#include "vm_manager.hpp"
namespace rubinius {
class Environment {
public:
+ VMManager manager;
+ SharedState* shared;
VM* state;
Environment();
@@ -22,6 +25,7 @@ namespace rubinius {
void run_file(std::string path);
void enable_preemption();
void boot_vm();
+ int exit_code();
};
}
View
@@ -16,7 +16,9 @@ namespace rubinius {
enum PrimitiveRuntimeCode {
- kPrimitiveFailed = 0
+ // A weird value, but works well. It looks like a reference to the highest
+ // address in memory.
+ kPrimitiveFailed = ((unsigned int)-1) & ~TAG_REF_MASK
};
View
@@ -6,7 +6,8 @@ namespace rubinius {
cNone,
cException,
cReturn,
- cBreak
+ cBreak,
+ cExit
};
}
View
@@ -0,0 +1,16 @@
+namespace rubinius {
+
+ class RefCount {
+ int ref_count_;
+
+ public:
+ void ref() {
+ ref_count_++;
+ }
+
+ bool deref() {
+ return --ref_count_ <= 0;
+ }
+ };
+
+}
View
@@ -19,4 +19,10 @@ namespace rubinius {
raise_value_ = value;
destination_scope_ = dest;
}
+
+ void ThreadState::raise_exit(Object* code) {
+ raise_reason_ = cExit;
+ raise_value_ = code;
+ destination_scope_ = 0;
+ }
}
View
@@ -47,6 +47,7 @@ namespace rubinius {
void raise_exception(Exception* exc);
void raise_return(Object* value, VariableScope* dest);
void raise_break(Object* value, VariableScope* dest);
+ void raise_exit(Object* code);
};
};
View
@@ -30,10 +30,35 @@
#define GO(whatever) globals.whatever
namespace rubinius {
- VM::VM(size_t bytes, bool boot)
- : current_mark(NULL)
+
+ SharedState::~SharedState() {
+ if(!initialized_) return;
+
+ delete om;
+ delete global_cache;
+ delete user_config;
+
+#ifdef ENABLE_LLVM
+ if(!reuse_llvm) llvm_cleanup();
+#endif
+ }
+
+ VM::VM(SharedState& shared, int id)
+ : id_(id)
+ , shared(shared)
+ , globals(shared.globals)
+ , om(shared.om)
+ , global_cache(shared.global_cache)
+ , config(shared.config)
+ , interrupts(shared.interrupts)
+ , symbols(shared.symbols)
+ , user_config(shared.user_config)
+ , current_mark(NULL)
, reuse_llvm(true)
, use_safe_position(false)
+ {}
+
+ void VM::initialize(size_t bytes)
{
config.compile_up_front = false;
config.jit_enabled = false;
@@ -42,21 +67,19 @@ namespace rubinius {
VM::register_state(this);
user_config = new ConfigParser();
+ shared.user_config = user_config;
om = new ObjectMemory(this, bytes);
+ shared.om = om;
+
probe.set(Qnil, &globals.roots);
- if(boot) this->boot();
- }
+ global_cache = new GlobalCache;
+ shared.global_cache = global_cache;
- VM::~VM() {
- delete user_config;
- delete om;
- delete signal_events;
- delete global_cache;
-#ifdef ENABLE_LLVM
- if(!reuse_llvm) llvm_cleanup();
-#endif
+ this->boot();
+
+ shared.set_initialized();
}
void VM::boot() {
@@ -86,8 +109,6 @@ namespace rubinius {
signal_events->start(new event::Child::Event(this));
- global_cache = new GlobalCache;
-
VMMethod::init(this);
#ifdef ENABLE_LLVM
View
@@ -6,6 +6,8 @@
#include "gc_object_mark.hpp"
#include "thread_state.hpp"
+#include "refcount.hpp"
+
#include <pthread.h>
#include <setjmp.h>
@@ -78,19 +80,56 @@ namespace rubinius {
{}
};
+ class SharedState : public RefCount {
+ private:
+ bool initialized_;
+ int id_;
+
+ public:
+ Globals globals;
+ ObjectMemory* om;
+ GlobalCache* global_cache;
+ Configuration config;
+ Interrupts interrupts;
+ SymbolTable symbols;
+ ConfigParser *user_config;
+
+ public:
+ SharedState(int id)
+ : initialized_(false)
+ , id_(id)
+ , om(0)
+ , global_cache(0)
+ , user_config(0)
+ {}
+
+ ~SharedState();
+
+ int id() {
+ return id_;
+ }
+
+ void set_initialized() {
+ initialized_ = true;
+ }
+ };
+
class VM {
+ private:
+ int id_;
+
public:
/* Data members */
- Globals globals;
+ SharedState& shared;
+ Globals& globals;
ObjectMemory* om;
event::Loop* events;
event::Loop* signal_events;
GlobalCache* global_cache;
TypedRoot<TaskProbe*> probe;
- Primitives* primitives;
- Configuration config;
- Interrupts interrupts;
- SymbolTable symbols;
+ Configuration& config;
+ Interrupts& interrupts;
+ SymbolTable& symbols;
ConfigParser *user_config;
ThreadState thread_state_;
@@ -126,15 +165,20 @@ namespace rubinius {
static const size_t default_bytes = 1048576 * 3;
- /* Inline methods */
+ public: /* Inline methods */
+
+ int id() {
+ return id_;
+ }
ThreadState* thread_state() {
return &thread_state_;
}
/* Prototypes */
- VM(size_t bytes = default_bytes, bool boot_now = true);
- ~VM();
+ VM(SharedState& shared, int id);
+
+ void initialize(size_t bytes = default_bytes);
// Initialize the basic objects and the execution machinery
void boot();
View
@@ -0,0 +1,33 @@
+#include "vm_manager.hpp"
+#include "vm.hpp"
+
+namespace rubinius {
+ SharedState* VMManager::create_shared_state() {
+ SharedState* shared = new SharedState(share_id_++);
+ shares_[shared->id()] = shared;
+ return shared;
+ }
+
+ VM* VMManager::create_vm(SharedState* shared) {
+ VM* vm = new VM(*shared, vm_id_++);
+ vms_[vm->id()] = vm;
+
+ shared->ref();
+ return vm;
+ }
+
+ void VMManager::destroy_vm(VM* vm) {
+ SharedState* shared = &vm->shared;
+ VMMap::iterator i = vms_.find(vm->id());
+ assert(i != vms_.end());
+
+ vms_.erase(i);
+ delete vm;
+ if(shared->deref()) {
+ ShareMap::iterator si = shares_.find(shared->id());
+ assert(si != shares_.end());
+ shares_.erase(si);
+ delete shared;
+ }
+ }
+}
View
@@ -0,0 +1,29 @@
+
+#include <map>
+
+namespace rubinius {
+ class SharedState;
+ class VM;
+
+ typedef std::map<int, SharedState*> ShareMap;
+ typedef std::map<int, VM*> VMMap;
+
+ class VMManager {
+ int share_id_;
+ int vm_id_;
+
+ ShareMap shares_;
+ VMMap vms_;
+ public:
+
+ VMManager()
+ : share_id_(0)
+ , vm_id_(0)
+ {}
+
+ SharedState* create_shared_state();
+ VM* create_vm(SharedState*);
+
+ void destroy_vm(VM*);
+ };
+}
View
@@ -676,6 +676,8 @@ namespace rubinius {
}
}
break;
+ case cExit:
+ return NULL;
default:
std::cout << "bug!\n";
abort();

0 comments on commit 6cfae75

Please sign in to comment.