void on_break(int32_t s) { puts(""); static bool s_double = false; if (s_double) { puts("User interrupt."); #ifdef DEBUG dump_memory(0); #endif _exit(1); } s_double = true; #ifdef WIN32 exlib::OSThread _thread; _thread.bindCurrent(); #endif Isolate *p = s_isolates.head(); while (p != 0) { p->m_isolate->RequestInterrupt(cb_interrupt, NULL); p->m_interrupt = true; // p->RequestInterrupt(InterruptCallbackEx); p = s_isolates.next(p); } }
virtual void Run() { Isolate* isolate = s_isolates.head(); intptr_t lastTimes = isolate->m_service->m_switchTimes; int32_t cnt = 0; while (true) { sleep(100); if (isolate->m_service->m_resume.empty()) { cnt = 0; continue; } if (lastTimes != isolate->m_service->m_switchTimes) { cnt = 0; lastTimes = isolate->m_service->m_switchTimes; continue; } cnt ++; if (cnt == 2) { cnt = 0; isolate->m_isolate->RequestInterrupt(InterruptCallback, NULL); } } }
void Isolate::Unref(int32_t hr) { if (s_iso_ref.dec() == 0) { Isolate* isolate = s_isolates.head(); isolate->m_hr = hr; syncCall(isolate, syncExit, isolate); } }
static void doAsync() { exlib::List<asyncEv> jobs; asyncEv *p1; s_evWait.getList(jobs); while ((p1 = jobs.getHead()) != 0) p1->start(); }
void Isolate::init() { s_isolates.putTail(this); v8::Locker locker(m_isolate); v8::Isolate::Scope isolate_scope(m_isolate); v8::HandleScope handle_scope(m_isolate); JSFiber::scope s; v8::Local<v8::Context> _context = v8::Context::New(m_isolate); m_context.Reset(m_isolate, _context); v8::Context::Scope context_scope(_context); if (g_cov && m_id == 1) beginCoverage(m_isolate); _context->SetEmbedderData(1, v8::Object::New(m_isolate)->GetPrototype()); static const char* skips[] = { "Master", "repl", "argv", "__filename", "__dirname", NULL }; global_base::class_info().Attach(this, _context->Global(), skips); m_topSandbox = new SandBox(); m_topSandbox->initRoot(); auto assertion_error = "class AssertionError extends Error {" " constructor(options) {" " var { actual, expected, message, operator } = options;" " if (message) {" " super(message);" " } else {" " if (actual && actual.stack && actual instanceof Error)" " actual = `${actual.name}: ${actual.message}`;" " if (expected && expected.stack && expected instanceof Error)" " expected = `${expected.name}: ${expected.message}`;" " super(`${JSON.stringify(actual).slice(0, 128)} ` +" " `${operator} ${JSON.stringify(expected).slice(0, 128)}`);" " }" " this.generatedMessage = !message;" " this.name = 'AssertionError [ERR_ASSERTION]';" " this.code = 'ERR_ASSERTION';" " this.actual = actual;" " this.expected = expected;" " this.operator = operator;" " }" "}" "AssertionError;"; v8::Local<v8::Script> script = v8::Script::Compile(NewString(assertion_error)); v8::Local<v8::Object> AssertionError = script->Run().As<v8::Object>(); m_AssertionError.Reset(m_isolate, AssertionError); }
void post() { s_evWait.putTail(this); ev_async_send(s_loop, &s_asEvent); }
namespace fibjs { void setOption(intptr_t s) { int32_t keepAlive = 1; setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *) &keepAlive, sizeof(keepAlive)); #ifdef TCP_KEEPIDLE int32_t keepIdle = KEEPALIVE_TIMEOUT; setsockopt(s, SOL_TCP, TCP_KEEPIDLE, (void *) &keepIdle, sizeof(keepIdle)); #endif #ifdef TCP_KEEPINTVL int32_t keepInterval = 20; int32_t keepCount = 10; setsockopt(s, SOL_TCP, TCP_KEEPINTVL, (void *) &keepInterval, sizeof(keepInterval)); setsockopt(s, SOL_TCP, TCP_KEEPCNT, (void *) &keepCount, sizeof(keepCount)); #endif int32_t noDelay = 1; setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &noDelay, sizeof(noDelay)); } static struct ev_loop *s_loop; result_t net_base::backend(std::string &retVal) { switch (ev_backend(s_loop)) { case EVBACKEND_SELECT: retVal = "Select"; break; case EVBACKEND_POLL: retVal = "Poll"; break; case EVBACKEND_EPOLL: retVal = "EPoll"; break; case EVBACKEND_KQUEUE: retVal = "KQueue"; break; case EVBACKEND_DEVPOLL: retVal = "DevPoll"; break; case EVBACKEND_PORT: retVal = "Port"; break; } return 0; } class asyncEv; static ev_async s_asEvent; static exlib::LockedList<asyncEv> s_evWait; class asyncEv: public ev_io, public exlib::linkitem { public: virtual ~asyncEv() { } void post() { s_evWait.putTail(this); ev_async_send(s_loop, &s_asEvent); } virtual void start() { } }; class asyncProc: public asyncEv { public: asyncProc(intptr_t s, int32_t op, AsyncEvent *ac, intptr_t &guard, void *&opt) : m_s(s), m_op(op), m_ac(ac), m_guard(guard), m_opt(opt) { } virtual void start() { m_opt = this; ev_io *io = (ev_io *) this; ev_io_init(io, io_cb, m_s, m_op); ev_io_start(s_loop, this); } result_t call() { result_t hr = process(); if (hr == CALL_E_PENDDING) post(); else { m_guard = 0; delete this; } return hr; } virtual result_t process() { return 0; } virtual void proc() { ready(process()); } void ready(int32_t v) { m_opt = NULL; m_guard = 0; m_ac->apost(v); delete this; } void onready() { ev_io_stop(s_loop, this); proc(); } public: intptr_t m_s; int32_t m_op; AsyncEvent *m_ac; intptr_t &m_guard; void *&m_opt; private: static void io_cb(struct ev_loop *loop, struct ev_io *watcher, int32_t revents) { ((asyncProc *) watcher)->onready(); } }; static class _acIO: public exlib::OSThread { public: _acIO() { s_loop = EV_DEFAULT; } virtual void Run() { ev_async_init(&s_asEvent, as_cb); ev_async_start(s_loop, &s_asEvent); ev_timer tm; tm_cb(s_loop, &tm, 0); Runtime rt(NULL); ev_run(s_loop, 0); } private: static void doAsync() { exlib::List<asyncEv> jobs; asyncEv *p1; s_evWait.getList(jobs); while ((p1 = jobs.getHead()) != 0) p1->start(); } static void tm_cb(struct ev_loop *loop, struct ev_timer *watcher, int32_t revents) { ev_timer_init(watcher, tm_cb, 10, 0); ev_timer_start(s_loop, watcher); doAsync(); } static void as_cb(struct ev_loop *loop, struct ev_async *watcher, int32_t revents) { doAsync(); } } s_acIO; void init_aio() { s_acIO.start(); } result_t AsyncIO::cancel(AsyncEvent *ac) { class asyncCancel: public asyncEv { public: asyncCancel(void *&opt1, void *&opt2, AsyncEvent *ac) : m_ac(ac), m_opt1(opt1), m_opt2(opt2) { } virtual void start() { if (m_opt1) ((asyncProc *) m_opt1)->onready(); if (m_opt2) ((asyncProc *) m_opt2)->onready(); m_ac->apost(0); delete this; } public: AsyncEvent *m_ac; void *&m_opt1; void *&m_opt2; }; if (m_inRecv || m_inSend) { (new asyncCancel(m_RecvOpt, m_SendOpt, ac))->post(); return CHECK_ERROR(CALL_E_PENDDING); } return 0; } result_t AsyncIO::connect(const char *host, int32_t port, AsyncEvent *ac) { class asyncConnect: public asyncProc { public: asyncConnect(intptr_t s, inetAddr &ai, AsyncEvent *ac, intptr_t &guard, void *&opt) : asyncProc(s, EV_WRITE, ac, guard, opt), m_ai(ai) { } virtual result_t process() { int32_t n = ::connect(m_s, (struct sockaddr *) &m_ai, m_ai.size()); if (n == SOCKET_ERROR) { int32_t nError = errno; return CHECK_ERROR((nError == EINPROGRESS) ? CALL_E_PENDDING : -nError); } return 0; } virtual void proc() { inetAddr addr_info; socklen_t sz1 = sizeof(addr_info); if (::getpeername(m_s, (sockaddr *) &addr_info, &sz1) == SOCKET_ERROR) ready(-ECONNREFUSED); else { setOption(m_s); ready(0); } } public: inetAddr m_ai; }; if (m_fd == INVALID_SOCKET) return CHECK_ERROR(CALL_E_INVALID_CALL); if (!ac) return CHECK_ERROR(CALL_E_NOSYNC); inetAddr addr_info; addr_info.init(m_family); addr_info.setPort(port); if (addr_info.addr(host) < 0) { std::string strAddr; result_t hr = net_base::cc_resolve(host, m_family, strAddr); if (hr < 0) return hr; if (addr_info.addr(strAddr.c_str()) < 0) return CHECK_ERROR(CALL_E_INVALIDARG); } if (exlib::CompareAndSwap(&m_inRecv, 0, 1)) return CHECK_ERROR(CALL_E_REENTRANT); return (new asyncConnect(m_fd, addr_info, ac, m_inRecv, m_RecvOpt))->call(); } result_t AsyncIO::accept(obj_ptr<Socket_base> &retVal, AsyncEvent *ac) { class asyncAccept: public asyncProc { public: asyncAccept(intptr_t s, obj_ptr<Socket_base> &retVal, AsyncEvent *ac, intptr_t &guard, void *&opt) : asyncProc(s, EV_READ, ac, guard, opt), m_retVal(retVal) { } virtual result_t process() { inetAddr ai; socklen_t sz = sizeof(ai); intptr_t c = ::accept(m_s, (sockaddr *) &ai, &sz); if (c == INVALID_SOCKET) { int32_t nError = errno; return CHECK_ERROR((nError == EWOULDBLOCK) ? CALL_E_PENDDING : -nError); } fcntl(c, F_SETFL, fcntl(c, F_GETFL, 0) | O_NONBLOCK); fcntl(c, F_SETFD, FD_CLOEXEC); #ifdef MacOS int32_t set_option = 1; setsockopt(c, SOL_SOCKET, SO_NOSIGPIPE, &set_option, sizeof(set_option)); #endif setOption(c); obj_ptr<Socket> sock = new Socket(c, ai.family(), net_base::_SOCK_STREAM); m_retVal = sock; return 0; } public: obj_ptr<Socket_base> &m_retVal; }; if (m_fd == INVALID_SOCKET) return CHECK_ERROR(CALL_E_INVALID_CALL); if (!ac) return CHECK_ERROR(CALL_E_NOSYNC); if (exlib::CompareAndSwap(&m_inRecv, 0, 1)) return CHECK_ERROR(CALL_E_REENTRANT); return (new asyncAccept(m_fd, retVal, ac, m_inRecv, m_RecvOpt))->call(); } result_t AsyncIO::read(int32_t bytes, obj_ptr<Buffer_base> &retVal, AsyncEvent *ac, bool bRead) { class asyncRecv: public asyncProc { public: asyncRecv(intptr_t s, int32_t bytes, obj_ptr<Buffer_base> &retVal, AsyncEvent *ac, int32_t family, bool bRead, intptr_t &guard, void *&opt) : asyncProc(s, EV_READ, ac, guard, opt), m_retVal(retVal), m_pos(0), m_bytes(bytes > 0 ? bytes : SOCKET_BUFF_SIZE), m_family(family), m_bRead(bRead) { } virtual result_t process() { if (m_buf.empty()) m_buf.resize(m_bytes); do { int32_t n; if (m_family) n = (int32_t) ::recv(m_s, &m_buf[m_pos], m_buf.length() - m_pos, MSG_NOSIGNAL); else n = (int32_t) ::read(m_s, &m_buf[m_pos], m_buf.length() - m_pos); if (n == SOCKET_ERROR) { int32_t nError = errno; if (nError == ECONNRESET) n = 0; else { if (m_pos == 0) m_buf = std::string(); return CHECK_ERROR((nError == EWOULDBLOCK) ? CALL_E_PENDDING : -nError); } } if (n == 0) m_bRead = false; m_pos += n; if (m_pos == 0) return CALL_RETURN_NULL; } while (m_bRead && m_pos < (int32_t) m_buf.length()); m_buf.resize(m_pos); m_retVal = new Buffer(m_buf); return 0; } virtual void proc() { result_t hr = process(); if (hr == CALL_E_PENDDING) post(); else ready(hr); } public: obj_ptr<Buffer_base> &m_retVal; int32_t m_pos; int32_t m_bytes; int32_t m_family; bool m_bRead; std::string m_buf; }; if (m_fd == INVALID_SOCKET) return CHECK_ERROR(CALL_E_INVALID_CALL); if (!ac) return CHECK_ERROR(CALL_E_NOSYNC); if (exlib::CompareAndSwap(&m_inRecv, 0, 1)) return CHECK_ERROR(CALL_E_REENTRANT); return (new asyncRecv(m_fd, bytes, retVal, ac, m_family, bRead, m_inRecv, m_RecvOpt))->call(); } result_t AsyncIO::write(Buffer_base *data, AsyncEvent *ac) { class asyncSend: public asyncProc { public: asyncSend(intptr_t s, Buffer_base *data, AsyncEvent *ac, int32_t family, intptr_t &guard, void *&opt) : asyncProc(s, EV_WRITE, ac, guard, opt), m_family(family) { data->toString(m_buf); m_p = m_buf.c_str(); m_sz = m_buf.length(); } virtual result_t process() { while (m_sz) { int32_t n; if (m_family) n = (int32_t) ::send(m_s, m_p, m_sz, MSG_NOSIGNAL); else n = (int32_t) ::write(m_s, m_p, m_sz); if (n == SOCKET_ERROR) { int32_t nError = errno; return CHECK_ERROR((nError == EWOULDBLOCK) ? CALL_E_PENDDING : -nError); } m_sz -= n; m_p += n; } return 0; } virtual void proc() { result_t hr = process(); if (hr == CALL_E_PENDDING) post(); else ready(hr); } public: std::string m_buf; const char *m_p; int32_t m_sz; int32_t m_family; }; if (m_fd == INVALID_SOCKET) return CHECK_ERROR(CALL_E_INVALID_CALL); if (!ac) return CHECK_ERROR(CALL_E_NOSYNC); if (exlib::CompareAndSwap(&m_inSend, 0, 1)) return CHECK_ERROR(CALL_E_REENTRANT); return (new asyncSend(m_fd, data, ac, m_family, m_inSend, m_SendOpt))->call(); } }
namespace fibjs { extern int32_t stack_size; extern bool g_preemptive; #define MAX_FIBER 10000 #define MAX_IDLE 256 static exlib::Queue<AsyncEvent> g_jobs; static exlib::IDLE_PROC s_oldIdle; static int32_t s_fibers; static int32_t s_idleFibers; int32_t g_spareFibers; static int32_t g_tlsCurrent; DateCache FiberBase::g_dc; static class null_fiber_data: public Fiber_base { public: null_fiber_data() { Ref(); } virtual result_t join() { return 0; } virtual result_t get_traceInfo(std::string& retVal) { return 0; } virtual result_t get_caller(obj_ptr<Fiber_base> &retVal) { return CHECK_ERROR(CALL_E_INVALID_CALL); } } *s_null; static void onIdle() { if (!g_jobs.empty() && (s_idleFibers == 0) && (s_fibers < MAX_FIBER)) { s_fibers++; s_idleFibers ++; exlib::Fiber::Create(FiberBase::fiber_proc, NULL, stack_size * 1024); } if (s_oldIdle) s_oldIdle(); } extern exlib::LockedList<Isolate> s_isolates; class _preemptThread: public exlib::OSThread { public: virtual void Run() { Isolate* isolate = s_isolates.head(); intptr_t lastTimes = isolate->m_service->m_switchTimes; int32_t cnt = 0; while (true) { sleep(100); if (isolate->m_service->m_resume.empty()) { cnt = 0; continue; } if (lastTimes != isolate->m_service->m_switchTimes) { cnt = 0; lastTimes = isolate->m_service->m_switchTimes; continue; } cnt ++; if (cnt == 2) { cnt = 0; isolate->m_isolate->RequestInterrupt(InterruptCallback, NULL); } } } private: static void InterruptCallback(v8::Isolate *isolate, void *data) { coroutine_base::ac_sleep(0); } } s_preemptThread; void init_fiber() { g_spareFibers = MAX_IDLE; s_null = new null_fiber_data(); s_fibers = 0; s_idleFibers = 0; g_tlsCurrent = exlib::Fiber::tlsAlloc(); s_oldIdle = exlib::Service::current()->onIdle(onIdle); if (g_preemptive) s_preemptThread.start(); } void *FiberBase::fiber_proc(void *p) { Isolate* isolate = Isolate::now(); v8::Locker locker(isolate->m_isolate); v8::Isolate::Scope isolate_scope(isolate->m_isolate); v8::HandleScope handle_scope(isolate->m_isolate); v8::Context::Scope context_scope( v8::Local<v8::Context>::New(isolate->m_isolate, isolate->m_context)); s_idleFibers --; while (1) { AsyncEvent *ae; if ((ae = g_jobs.tryget()) == NULL) { s_idleFibers ++; if (s_idleFibers > g_spareFibers) { s_idleFibers --; break; } { v8::Unlocker unlocker(isolate->m_isolate); ae = g_jobs.get(); } s_idleFibers --; } { v8::HandleScope handle_scope(isolate->m_isolate); ae->js_invoke(); } } s_fibers --; return NULL; } void FiberBase::set_caller(Fiber_base* caller) { m_caller = caller; if (m_caller) { v8::Local<v8::Object> co = m_caller->wrap(); v8::Local<v8::Object> o = wrap(); v8::Local<v8::Array> ks = co->GetOwnPropertyNames(); int32_t len = ks->Length(); int32_t i; for (i = 0; i < len; i++) { v8::Local<v8::Value> k = ks->Get(i); o->Set(k, co->Get(k)); } } } void FiberBase::start() { set_caller(JSFiber::current()); g_jobs.put(this); Ref(); } result_t FiberBase::join() { if (!m_quit.isSet()) { Isolate::rt _rt; m_quit.wait(); } return 0; } result_t FiberBase::get_traceInfo(std::string& retVal) { if (JSFiber::current() == this) retVal = traceInfo(300); else retVal = m_traceInfo; return 0; } result_t FiberBase::get_caller(obj_ptr<Fiber_base> &retVal) { if (m_caller == NULL) return CALL_RETURN_NULL; retVal = m_caller; return 0; } JSFiber *JSFiber::current() { return (JSFiber *)exlib::Fiber::tlsGet(g_tlsCurrent); } void JSFiber::js_invoke() { scope s(this); v8::Local<v8::Value> retVal; size_t i; Isolate* isolate = Isolate::now(); std::vector<v8::Local<v8::Value> > argv; v8::Local<v8::Function> func = v8::Local<v8::Function>::New(isolate->m_isolate, m_func); argv.resize(m_argv.size()); for (i = 0; i < m_argv.size(); i++) argv[i] = v8::Local<v8::Value>::New(isolate->m_isolate, m_argv[i]); clear(); retVal = func->Call(wrap(), (int32_t) argv.size(), argv.data()); if (!IsEmpty(retVal)) m_result.Reset(isolate->m_isolate, retVal); Unref(); } JSFiber::scope::scope(JSFiber *fb) : m_hr(0), m_pFiber(fb) { if (fb == NULL) m_pFiber = new JSFiber(); exlib::Fiber::tlsPut(g_tlsCurrent, m_pFiber); Isolate::now()->m_fibers.putTail(m_pFiber); } JSFiber::scope::~scope() { v8::Local<v8::Object> o = m_pFiber->wrap(); m_pFiber->m_quit.set(); m_pFiber->dispose(); s_null->Ref(); o->SetAlignedPointerInInternalField(0, s_null); ReportException(try_catch, m_hr); Isolate::now()->m_fibers.remove(m_pFiber); exlib::Fiber::tlsPut(g_tlsCurrent, 0); } void AsyncEvent::sync() { g_jobs.put(this); } } /* namespace fibjs */
void start(int32_t argc, char** argv, result_t (*main)(Isolate*)) { class MainThread : public exlib::OSThread { public: MainThread(int32_t argc, char** argv, result_t (*main)(Isolate*)) : m_argc(argc) , m_argv(argv) , m_main(main) { } public: static void start_fiber(void* p) { MainThread* th = (MainThread*)p; Isolate* isolate = new Isolate(th->m_start); syncCall(isolate, th->m_main, isolate); } virtual void Run() { int32_t argc = m_argc; char** argv = m_argv; exlib::string exePath; std::vector<char*> ptrArg; process_base::get_execPath(exePath); bool bZip; ifZipFile(exePath, bZip); if (bZip) { exePath.append(1, '$'); ptrArg.resize(argc + 1); ptrArg[0] = argv[0]; ptrArg[1] = exePath.c_buffer(); int32_t i; for (i = 1; i < argc; i++) ptrArg[i + 1] = argv[i]; argv = &ptrArg[0]; argc++; } init_start_argv(argc, argv); int32_t pos = argc; options(pos, argv); init(); if (pos < argc) { if (argv[pos][0] == '-') m_start = argv[pos]; else { m_start = s_root; resolvePath(m_start, argv[pos]); } if (pos != 1) { int32_t p = 1; for (; pos < argc; pos++) argv[p++] = argv[pos]; argc = p; } } init_argv(argc, argv); exlib::Service::Create(start_fiber, this, 256 * 1024, "start"); m_sem.Post(); exlib::Service::dispatch(); } public: exlib::OSSemaphore m_sem; private: int32_t m_argc; char** m_argv; exlib::string m_start; result_t (*m_main)(Isolate*); }; MainThread* main_thread = new MainThread(argc, argv, main); main_thread->start(); main_thread->m_sem.Wait(); }
namespace fibjs { extern exlib::LockedList<Isolate> s_isolates; extern bool g_perf; static std::string traceFiber() { std::string msg; exlib::linkitem* p = Isolate::current()->m_fibers.head(); char buf[128]; int32_t n = 0; while (p) { JSFiber* fb = (JSFiber*)p; sprintf(buf, "\nFiber %d:", n++); msg.append(buf); msg.append(fb->m_traceInfo); p = p->m_next; } return msg; } void dump_memory(int32_t serial); static void dumpFibers() { std::string msg; msg.append(COLOR_LIGHTRED "User interrupt."); if (Isolate::rt::g_trace) msg.append(traceFiber()); else if (JSFiber::current()) msg.append(traceInfo(300)); msg.append(COLOR_RESET "\n"); std_logger::out(msg.c_str()); #ifdef DEBUG dump_memory(0); #endif _exit(1); } static void cb_interrupt(v8::Isolate *isolate, void *data) { dumpFibers(); } void Isolate::InterruptCallback() { cb_interrupt(m_isolate, NULL); } void on_break(int32_t s) { puts(""); static bool s_double = false; if (s_double) { puts("User interrupt."); #ifdef DEBUG dump_memory(0); #endif _exit(1); } s_double = true; #ifdef WIN32 exlib::OSThread _thread; _thread.bindCurrent(); #endif Isolate *p = s_isolates.head(); while (p != 0) { p->m_isolate->RequestInterrupt(cb_interrupt, NULL); p->m_interrupt = true; // p->RequestInterrupt(InterruptCallbackEx); p = s_isolates.next(p); } } #ifdef _WIN32 typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType, CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam); static MINIDUMPWRITEDUMP s_pDump; HANDLE CreateUniqueDumpFile() { char fname[MAX_PATH]; int32_t l, i; HANDLE hFile; puts("core dump...."); l = GetCurrentDirectory(MAX_PATH, fname); memcpy(fname + l, "\\core.", 6); l += 6; for (i = 0; i < 104; i++) { _itoa_s(i, fname + l, 10, 10); memcpy(fname + l + (i > 999 ? 4 : (i > 99 ? 3 : (i > 9 ? 2 : 1))), ".dmp", 5); hFile = CreateFile(fname, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) return hFile; if (GetLastError() != ERROR_FILE_EXISTS) return INVALID_HANDLE_VALUE; }; return INVALID_HANDLE_VALUE; } static void CreateMiniDump(LPEXCEPTION_POINTERS lpExceptionInfo) { HANDLE hFile = CreateUniqueDumpFile(); if (hFile != NULL && hFile != INVALID_HANDLE_VALUE) { MINIDUMP_EXCEPTION_INFORMATION mdei; mdei.ThreadId = GetCurrentThreadId(); mdei.ExceptionPointers = lpExceptionInfo; mdei.ClientPointers = FALSE; MINIDUMP_TYPE mdt = MiniDumpNormal; BOOL retv = s_pDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, mdt, (lpExceptionInfo != 0) ? &mdei : 0, 0, 0); CloseHandle(hFile); } } static LONG WINAPI GPTUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo) { CreateMiniDump(pExceptionInfo); exit(pExceptionInfo->ExceptionRecord->ExceptionCode); return EXCEPTION_EXECUTE_HANDLER; } BOOL WINAPI win_breakEvent(DWORD dwCtrlType) { on_break(0); return TRUE; } void init_prof() { #ifndef DEBUG HMODULE hDll; if (hDll = ::LoadLibrary("DBGHELP.DLL")) { s_pDump = (MINIDUMPWRITEDUMP) ::GetProcAddress(hDll, "MiniDumpWriteDump"); if (s_pDump) SetUnhandledExceptionFilter (GPTUnhandledExceptionFilter); } #endif SetConsoleCtrlHandler(win_breakEvent, TRUE); } #else void init_prof() { struct rlimit corelimit = { RLIM_INFINITY, RLIM_INFINITY }; struct sigaction sigIntHandler; setrlimit(RLIMIT_CORE, &corelimit); sigIntHandler.sa_handler = on_break; sigemptyset(&sigIntHandler.sa_mask); sigIntHandler.sa_flags = 0; sigaction(SIGINT, &sigIntHandler, NULL); sigaction(SIGTERM, &sigIntHandler, NULL); } #endif }