#include "rust_internal.h" #include "rust_util.h" #define KLOG_(...) \ KLOG(this, kern, __VA_ARGS__) #define KLOG_ERR_(field, ...) \ KLOG_LVL(this, field, log_err, __VA_ARGS__) rust_kernel::rust_kernel(rust_srv *srv, size_t num_threads) : _region(srv, true), _log(srv, NULL), srv(srv), max_id(0), rval(0), num_threads(num_threads), live_tasks(0), env(srv->env) { isaac_init(this, &rctx); create_schedulers(); } rust_scheduler * rust_kernel::create_scheduler(int id) { _kernel_lock.lock(); rust_srv *srv = this->srv->clone(); rust_scheduler *sched = new (this, "rust_scheduler") rust_scheduler(this, srv, id); KLOG_("created scheduler: " PTR ", id: %d, index: %d", sched, id, sched->list_index); _kernel_lock.unlock(); return sched; } void rust_kernel::destroy_scheduler(rust_scheduler *sched) { _kernel_lock.lock(); KLOG_("deleting scheduler: " PTR ", name: %s, index: %d", sched, sched->name, sched->list_index); rust_srv *srv = sched->srv; delete sched; delete srv; _kernel_lock.unlock(); } void rust_kernel::create_schedulers() { KLOG_("Using %d scheduler threads.", num_threads); for(size_t i = 0; i < num_threads; ++i) { threads.push(create_scheduler(i)); } } void rust_kernel::destroy_schedulers() { for(size_t i = 0; i < num_threads; ++i) { destroy_scheduler(threads[i]); } } void rust_kernel::log_all_scheduler_state() { for(size_t i = 0; i < num_threads; ++i) { threads[i]->log_state(); } } /** * Checks for simple deadlocks. */ bool rust_kernel::is_deadlocked() { return false; } void rust_kernel::log(uint32_t level, char const *fmt, ...) { char buf[BUF_BYTES]; va_list args; va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); _log.trace_ln(NULL, level, buf); va_end(args); } void rust_kernel::fatal(char const *fmt, ...) { char buf[BUF_BYTES]; va_list args; va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); _log.trace_ln(NULL, (uint32_t)0, buf); exit(1); va_end(args); } rust_kernel::~rust_kernel() { destroy_schedulers(); } void * rust_kernel::malloc(size_t size, const char *tag) { return _region.malloc(size, tag); } void * rust_kernel::realloc(void *mem, size_t size) { return _region.realloc(mem, size); } void rust_kernel::free(void *mem) { _region.free(mem); } void rust_kernel::signal_kernel_lock() { _kernel_lock.lock(); _kernel_lock.unlock(); } int rust_kernel::start_task_threads() { for(size_t i = 0; i < num_threads; ++i) { rust_scheduler *thread = threads[i]; thread->start(); } for(size_t i = 0; i < num_threads; ++i) { rust_scheduler *thread = threads[i]; thread->join(); } return rval; } void rust_kernel::fail() { // FIXME: On windows we're getting "Application has requested the // Runtime to terminate it in an unusual way" when trying to shutdown // cleanly. set_exit_status(PROC_FAIL_CODE); #if defined(__WIN32__) exit(rval); #endif for(size_t i = 0; i < num_threads; ++i) { rust_scheduler *thread = threads[i]; thread->kill_all_tasks(); } } rust_task_id rust_kernel::create_task(rust_task *spawner, const char *name, size_t init_stack_sz) { scoped_lock with(_kernel_lock); rust_scheduler *thread = threads[isaac_rand(&rctx) % num_threads]; rust_task *t = thread->create_task(spawner, name, init_stack_sz); t->user.id = max_id++; task_table.put(t->user.id, t); return t->user.id; } rust_task_id rust_kernel::create_task(rust_task *spawner, const char *name) { return create_task(spawner, name, env->min_stack_size); } rust_task * rust_kernel::get_task_by_id(rust_task_id id) { scoped_lock with(_kernel_lock); rust_task *task = NULL; // get leaves task unchanged if not found. task_table.get(id, &task); if(task) { if(task->get_ref_count() == 0) { // this means the destructor is running, since the destructor // grabs the kernel lock to unregister the task. Pretend this // doesn't actually exist. return NULL; } else { task->ref(); } } return task; } void rust_kernel::release_task_id(rust_task_id id) { scoped_lock with(_kernel_lock); task_table.remove(id); } void rust_kernel::wakeup_schedulers() { for(size_t i = 0; i < num_threads; ++i) { rust_scheduler *sched = threads[i]; scoped_lock with(sched->lock); sched->lock.signal_all(); } } #ifdef __WIN32__ void rust_kernel::win32_require(LPCTSTR fn, BOOL ok) { if (!ok) { LPTSTR buf; DWORD err = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buf, 0, NULL ); KLOG_ERR_(dom, "%s failed with error %ld: %s", fn, err, buf); LocalFree((HLOCAL)buf); I(this, ok); } } #endif void rust_kernel::set_exit_status(int code) { scoped_lock with(_kernel_lock); // If we've already failed then that's the code we're going to use if (rval != PROC_FAIL_CODE) { rval = code; } } // // Local Variables: // mode: C++ // fill-column: 78; // indent-tabs-mode: nil // c-basic-offset: 4 // buffer-file-coding-system: utf-8-unix // End: //