Пример #1
0
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);
    }
}
Пример #2
0
    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);
            }
        }
    }
Пример #3
0
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);
    }
}
Пример #4
0
	static void doAsync()
	{
		exlib::List<asyncEv> jobs;
		asyncEv *p1;

		s_evWait.getList(jobs);

		while ((p1 = jobs.getHead()) != 0)
			p1->start();
	}
Пример #5
0
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);
}
Пример #6
0
	void post()
	{
		s_evWait.putTail(this);
		ev_async_send(s_loop, &s_asEvent);
	}
Пример #7
0
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();
}

}
Пример #8
0
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 */
Пример #9
0
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();
}
Пример #10
0
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

}