static bool js_object_external_function_callback( const jerry_api_object_t *function_object_ptr, const jerry_api_value_t *this_object_ptr, jerry_api_value_t *result_value_ptr, const jerry_api_value_t js_api_arguments[], const jerry_api_length_t argumentCount) { const auto position = JSObject::js_object_external_functions_map__.find(function_object_ptr); assert(position != JSObject::js_object_external_functions_map__.end()); auto callback = position->second; // TODO: Use current context JSContextGroup js_context_group; const auto js_context = js_context_group.CreateContext(); auto function_object = JSObject(js_context, function_object_ptr); auto this_object = JSObject(js_context, *this_object_ptr); const auto arguments = detail::to_vector(js_context, js_api_arguments, argumentCount); auto callback_result = callback(function_object, this_object, arguments); auto callback_result_value = static_cast<jerry_api_value_t>(callback_result); // callback value should be considered "unmanaged" from Daisy callback_result.unmanaged(); detail::js_jerry_api_value_make_copy(callback_result_value, result_value_ptr); return true; }
Thread* Thread::join(STATE, Object* timeout) { if(!vm()) return nil<Thread>(); Thread* self = this; OnStack<2> os(state, self, timeout); state->vm()->become_unmanaged(); { utilities::thread::Mutex::LockGuard guard(self->join_lock_); state->vm()->become_managed(); atomic::memory_barrier(); if(self->alive()->true_p()) { UnmanagedPhase unmanaged(state); if(timeout->nil_p()) { self->join_cond_.wait(self->join_lock_); } else { struct timespec ts = {0,0}; self->join_cond_.offset(&ts, as<Float>(timeout)->value()); if(self->join_cond_.wait_until(self->join_lock_, &ts) == utilities::thread::cTimedOut) { return nil<Thread>(); } } } } return self; }
void Fiber::suspend_and_continue(STATE) { UnmanagedPhase unmanaged(state); { std::unique_lock<std::mutex> lk(vm()->fiber_wait_mutex()); vm()->set_suspended(); while(!wakeup_p()) { vm()->fiber_wait_condition().wait(lk); } clear_wakeup(); vm()->set_resuming(); } { std::lock_guard<std::mutex> guard(state->vm()->thread()->fiber_mutex()); vm()->set_running(); while(!restart_context()->suspended_p()) { ; // spin wait } state->vm()->thread()->current_fiber(state, this); } }
void Fiber::restart(STATE) { UnmanagedPhase unmanaged(state); { std::lock_guard<std::mutex> guard(state->vm()->thread()->fiber_mutex()); if(!vm()->suspended_p()) { std::ostringstream msg; msg << "attempt to restart non-suspended (" << vm()->fiber_transition_flag() << ") fiber"; Exception::raise_fiber_error(state, msg.str().c_str()); } state->vm()->set_suspending(); restart_context(state->vm()); wakeup(); while(vm()->suspended_p()) { std::lock_guard<std::mutex> guard(vm()->fiber_wait_mutex()); vm()->fiber_wait_condition().notify_one(); } } while(!vm()->running_p()) { ; // spin wait } }
void FinalizerThread::extension_finalizer(STATE, Object* obj, FinalizerFunction func) { if(finishing_) return; UnmanagedPhase unmanaged(state); std::lock_guard<std::mutex> guard(list_mutex()); add_finalizer(state, new ExtensionFinalizer(state, obj, func)); }
void FinalizerThread::wakeup(STATE) { MachineThread::wakeup(state); while(thread_running_p()) { UnmanagedPhase unmanaged(state); std::lock_guard<std::mutex> guard(list_mutex()); list_condition().notify_one(); } }
void Response::run(STATE) { size_t pending_requests = 0; char* request = NULL; Channel* inbox = inbox_.get(); Channel* outbox = outbox_.get(); String* response = 0; OnStack<3> os(state, inbox, outbox, response); while(!thread_exit_) { { utilities::thread::SpinLock::LockGuard guard(list_lock_); if(request_list_->size() > 0) { request = request_list_->back(); request_list_->pop_back(); } } if(thread_exit_) break; if(request) { ManagedPhase managed(state); pending_requests++; inbox->send(state, String::create(state, request)); request = NULL; } if(pending_requests > 0) { if((response = try_as<String>(outbox->try_receive(state)))) { write_response(state, reinterpret_cast<const char*>(response->byte_address()), response->byte_size()); pending_requests--; continue; } } { UnmanagedPhase unmanaged(state); utilities::thread::Mutex::LockGuard guard(response_lock_); if(thread_exit_) break; response_cond_.wait(response_lock_); } } }
void LLVMState::compile(STATE, CompiledCode* code, Class* receiver_class, BlockEnvironment* block_env, bool is_block) { if(!enabled_) return; // TODO: Fix compile policy checks if(!code->keywords()->nil_p()) { vm()->metrics().jit.methods_failed++; return; } // In case the method hasn't been internalized yet if(!code->machine_code()) { code->internalize(state); } JITCompileRequest* req = JITCompileRequest::create(state, code, receiver_class, 0, block_env, is_block); wait_mutex.lock(); req->waiter(&wait_cond); add(state, req); { UnmanagedPhase unmanaged(state); wait_cond.wait(wait_mutex); } wait_mutex.unlock(); if(state->shared().config.jit_show_compiling) { llvm::outs() << "[[[ JIT compiled " << enclosure_name(code) << "#" << symbol_debug_str(code->name()) << (req->is_block() ? " (block) " : " (method) ") << " ]]]\n"; } }
Object* IO::recv_fd(STATE) { #ifdef _WIN32 return Primitives::failure(); #else struct msghdr msg; struct iovec vec[1]; char buf[1]; struct cmsghdr *cmsg; char cmsg_buf[cmsg_space]; msg.msg_name = NULL; msg.msg_namelen = 0; /* Linux and Solaris doesn't work if msg_iov is NULL. */ buf[0] = '\0'; vec[0].iov_base = buf; vec[0].iov_len = 1; msg.msg_iov = vec; msg.msg_iovlen = 1; msg.msg_control = (caddr_t)cmsg_buf; msg.msg_controllen = sizeof(cmsg_buf); msg.msg_flags = 0; cmsg = CMSG_FIRSTHDR(&msg); memset(cmsg_buf, 0, sizeof(cmsg_buf)); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; // Workaround for GCC's broken strict-aliasing checks. int* fd_data = (int *)CMSG_DATA(cmsg); *fd_data = -1; int read_fd = descriptor(state); int code = -1; retry: state->vm()->interrupt_with_signal(); state->vm()->thread()->sleep(state, cTrue); { UnmanagedPhase unmanaged(state); code = recvmsg(read_fd, &msg, 0); } state->vm()->thread()->sleep(state, cFalse); state->vm()->clear_waiter(); if(code == -1) { if(errno == EAGAIN || errno == EINTR) { if(state->vm()->thread_interrupted_p(state)) return NULL; ensure_open(state); goto retry; } return Primitives::failure(); } if(msg.msg_controllen != CMSG_SPACE(sizeof(int)) || cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { return Primitives::failure(); } // Workaround for GCC's broken strict-aliasing checks. fd_data = (int *)CMSG_DATA(cmsg); return Fixnum::from(*fd_data); #endif }
Object* IO::socket_read(STATE, Fixnum* bytes, Fixnum* flags, Fixnum* type) { char buf[1024]; socklen_t alen = sizeof(buf); size_t size = (size_t)bytes->to_native(); String* buffer = String::create_pinned(state, bytes); OnStack<1> variables(state, buffer); ssize_t bytes_read; native_int t = type->to_native(); retry: state->vm()->interrupt_with_signal(); state->vm()->thread()->sleep(state, cTrue); { UnmanagedPhase unmanaged(state); bytes_read = recvfrom(descriptor(state), (char*)buffer->byte_address(), size, flags->to_native(), (struct sockaddr*)buf, &alen); } state->vm()->thread()->sleep(state, cFalse); state->vm()->clear_waiter(); buffer->unpin(); if(bytes_read == -1) { if(errno == EINTR) { if(state->vm()->thread_interrupted_p(state)) return NULL; ensure_open(state); goto retry; } else { Exception::raise_errno_error(state, "read(2) failed"); } return NULL; } buffer->num_bytes(state, Fixnum::from(bytes_read)); if(t == 0) return buffer; // none Array* ary = Array::create(state, 2); ary->set(state, 0, buffer); switch(type->to_native()) { case 1: // ip // Hack from MRI: // OSX doesn't return a 'from' result from recvfrom for connection-oriented sockets if(alen && alen != sizeof(buf)) { ary->set(state, 1, ipaddr(state, (struct sockaddr*)buf, alen)); } else { ary->set(state, 1, cNil); } break; #ifndef RBX_WINDOWS case 2: // unix ary->set(state, 1, unixaddr(state, (struct sockaddr_un*)buf, alen)); break; #endif default: ary->set(state, 1, String::create(state, buf, alen)); } return ary; }
void Session::logout( String* reason ) { QF_STACK_TRY unmanaged().logout( convertString(reason) ); QF_STACK_CATCH }
void Session::logout() { QF_STACK_TRY unmanaged().logout(); QF_STACK_CATCH }
void LLVMState::compile_soon(STATE, CompiledCode* code, Class* receiver_class, BlockEnvironment* block_env, bool is_block) { bool wait = config().jit_sync; if(!enabled_) return; // TODO: Fix compile policy checks if(!code->keywords()->nil_p()) { vm()->metrics().jit.methods_failed++; return; } if(code->machine_code()->call_count <= 1) { return; } if(code->machine_code()->compiling_p()) { return; } int hits = code->machine_code()->method_call_count(); code->machine_code()->set_compiling(); JITCompileRequest* req = JITCompileRequest::create(state, code, receiver_class, hits, block_env, is_block); if(wait) { wait_mutex.lock(); req->waiter(&wait_cond); add(state, req); bool req_block = req->is_block(); { UnmanagedPhase unmanaged(state); wait_cond.wait(wait_mutex); } wait_mutex.unlock(); if(state->shared().config.jit_show_compiling) { llvm::outs() << "[[[ JIT compiled " << enclosure_name(code) << "#" << symbol_debug_str(code->name()) << (req_block ? " (block) " : " (method) ") << " (" << hits << ") " << " ]]]\n"; } } else { add(state, req); if(state->shared().config.jit_show_compiling) { llvm::outs() << "[[[ JIT queued " << enclosure_name(code) << "#" << symbol_debug_str(code->name()) << (req->is_block() ? " (block) " : " (method) ") << " (" << hits << ") " << " ]]]\n"; } } }
void LLVMState::run(STATE) { state_ = state; JITCompileRequest* compile_request = nil<JITCompileRequest>(); OnStack<1> os(state, compile_request); state->vm()->become_managed(); bool show_machine_code_ = jit_dump_code() & cMachineCode; while(!thread_exit_) { current_compiler_ = 0; { UnmanagedPhase unmanaged(state); { utilities::thread::Mutex::LockGuard lg(compile_lock_); while(compile_list_.get()->empty_p()) { compile_cond_.wait(compile_lock_); if(thread_exit_) break; } } } if(thread_exit_) break; { utilities::thread::Mutex::LockGuard guard(request_lock_); compile_request = try_as<JITCompileRequest>(compile_list_.get()->shift(state)); if(!compile_request || compile_request->nil_p()) continue; } utilities::thread::Condition* cond = compile_request->waiter(); // Don't proceed until requester has reached the wait_cond if(cond) wait_mutex.lock(); Context ctx(this); jit::Compiler jit(&ctx); current_compiler_ = &jit; uint32_t class_id = 0; uint32_t serial_id = 0; void* func = 0; try { if(compile_request->receiver_class() && !compile_request->receiver_class()->nil_p()) { // Apparently already compiled, probably some race if(compile_request->method()->find_specialized( compile_request->receiver_class())) { if(config().jit_show_compiling) { CompiledCode* code = compile_request->method(); llvm::outs() << "[[[ JIT already compiled " << enclosure_name(code) << "#" << symbol_debug_str(code->name()) << (compile_request->is_block() ? " (block)" : " (method)") << " ]]]\n"; } // If someone was waiting on this, wake them up. if(cond) { wait_mutex.unlock(); cond->signal(); } current_compiler_ = 0; continue; } class_id = compile_request->receiver_class()->class_id(); serial_id = compile_request->receiver_class()->serial_id(); } { timer::StopWatch<timer::microseconds> timer( vm()->metrics().jit.compile_time_us); jit.compile(compile_request); bool indy = !config().jit_sync; func = jit.generate_function(indy); } // We were unable to compile this function, likely // because it's got something we don't support. if(!func) { if(config().jit_show_compiling) { CompiledCode* code = compile_request->method(); llvm::outs() << "[[[ JIT error background compiling " << enclosure_name(code) << "#" << symbol_debug_str(code->name()) << (compile_request->is_block() ? " (block)" : " (method)") << " ]]]\n"; } // If someone was waiting on this, wake them up. if(cond) { wait_mutex.unlock(); cond->signal(); } current_compiler_ = 0; continue; } } catch(LLVMState::CompileError& e) { logger::info("JIT: compile error: %s", e.error()); vm()->metrics().jit.methods_failed++; // If someone was waiting on this, wake them up. if(cond) { wait_mutex.unlock(); cond->signal(); } current_compiler_ = 0; continue; } if(show_machine_code_) { jit.show_machine_code(); } // If the method has had jit'ing request disabled since we started // JIT'ing it, discard our work. if(!compile_request->machine_code()->jit_disabled()) { jit::RuntimeDataHolder* rd = ctx.runtime_data_holder(); atomic::memory_barrier(); start_method_update(); if(!compile_request->is_block()) { if(class_id) { compile_request->method()->add_specialized(state, class_id, serial_id, reinterpret_cast<executor>(func), rd); } else { compile_request->method()->set_unspecialized(reinterpret_cast<executor>(func), rd); } } else { compile_request->method()->set_unspecialized(reinterpret_cast<executor>(func), rd); } compile_request->machine_code()->clear_compiling(); end_method_update(); rd->run_write_barrier(shared().om, compile_request->method()); if(config().jit_show_compiling) { CompiledCode* code = compile_request->method(); llvm::outs() << "[[[ JIT finished background compiling " << enclosure_name(code) << "#" << symbol_debug_str(code->name()) << (compile_request->is_block() ? " (block)" : " (method)") << " ]]]\n"; } } // If someone was waiting on this, wake them up. if(cond) { wait_mutex.unlock(); cond->signal(); } current_compiler_ = 0; vm()->metrics().jit.methods_compiled++; } }