Permalink
Browse files

process, bugfix: SubProcess.wait return wrong status some times on li…

…nux.
  • Loading branch information...
xicilion committed Nov 15, 2017
1 parent 3f19c1f commit 1aa840c663e43bcb652511344cdf9596b0fdd5bc
@@ -71,6 +71,8 @@ class AsyncIO {
static result_t waitpid(intptr_t pid, int32_t& retVal, AsyncEvent* ac);
static void run(void (*proc)(void*));
public:
intptr_t m_fd;
int32_t m_family;
@@ -130,6 +130,10 @@ class SubProcess : public SubProcess_base {
static void wrap_pipe(intptr_t fd, obj_ptr<BufferedStream_base>& bs);
public:
exlib::Event m_exit;
int32_t m_status;
private:
obj_ptr<BufferedStream_base> m_stdin;
obj_ptr<BufferedStream_base> m_stdout;
@@ -31,6 +31,7 @@ void init_fs();
void init_fiber();
void init_signal();
void init_color();
void init_process();
void options(int32_t& pos, char* argv[]);
result_t ifZipFile(exlib::string filename, bool& retVal);
@@ -62,6 +63,7 @@ void init()
init_fiber();
init_signal();
init_color();
init_process();
srand((unsigned int)time(0));
@@ -204,6 +204,7 @@ class _acIO : public exlib::OSThread {
public:
_acIO()
{
m_lock.lock();
s_loop = EV_DEFAULT;
}
@@ -214,6 +215,7 @@ class _acIO : public exlib::OSThread {
ev_async_init(&s_asEvent, as_cb);
ev_async_start(s_loop, &s_asEvent);
m_lock.unlock();
ev_run(s_loop, 0);
}
@@ -229,12 +231,17 @@ class _acIO : public exlib::OSThread {
while ((p1 = jobs.getHead()) != 0)
p1->start();
}
public:
exlib::spinlock m_lock;
};
void init_aio()
{
static _acIO s_acIO;
s_acIO.start();
s_acIO.m_lock.lock();
}
result_t AsyncIO::close(AsyncEvent* ac)
@@ -655,50 +662,26 @@ result_t AsyncIO::recvfrom(int32_t bytes, obj_ptr<NObject>& retVal,
return (new asyncRecvFrom(m_fd, bytes, retVal, ac, m_lockRecv, m_RecvOpt))->call();
}
result_t AsyncIO::waitpid(intptr_t pid, int32_t& retVal, AsyncEvent* ac)
void AsyncIO::run(void (*proc)(void*))
{
class asyncWaitPid : public asyncEv {
class asyncRun : public asyncEv {
public:
asyncWaitPid(intptr_t pid, int32_t& retVal, AsyncEvent* ac)
: m_ac(ac)
, m_pid(pid)
, m_retVal(retVal)
asyncRun(void (*proc)(void*))
: m_proc(proc)
{
}
virtual void start()
{
ev_child_init(&cw, child_cb, m_pid, 0);
ev_child_start(s_loop, &cw);
cw.rstatus = 0;
pid_t pid1 = ::waitpid(m_pid, &cw.rstatus, WNOHANG);
if (pid1 == -1 || pid1 == m_pid)
child_cb(s_loop, &cw, 0);
}
private:
static void child_cb(struct ev_loop* loop, struct ev_child* w, int revents)
{
asyncWaitPid* pThis = NULL;
pThis = (asyncWaitPid*)((intptr_t)w - (intptr_t)&pThis->cw);
pThis->m_retVal = w->rstatus;
ev_child_stop(loop, w);
pThis->m_ac->apost(0);
delete pThis;
m_proc(s_loop);
delete this;
}
public:
AsyncEvent* m_ac;
intptr_t m_pid;
int32_t& m_retVal;
ev_child cw;
void (*m_proc)(void*);
};
(new asyncWaitPid(pid, retVal, ac))->post();
return CALL_E_PENDDING;
(new asyncRun(proc))->post();
}
}
@@ -15,9 +15,53 @@
#include <vector>
#include <sys/wait.h>
#include <signal.h>
#include <ev/ev.h>
namespace fibjs {
static exlib::spinlock s_lock;
static std::map<pid_t, obj_ptr<SubProcess>> s_ids;
static result_t async_signal_handler(int32_t n)
{
int32_t status = 0;
pid_t pid;
s_lock.lock();
while ((pid = waitpid(0, &status, WNOHANG | WUNTRACED | WCONTINUED)) > 0) {
std::map<pid_t, obj_ptr<SubProcess>>::iterator it = s_ids.find(pid);
if (it != s_ids.end()) {
it->second->m_status = status;
it->second->m_exit.set();
s_ids.erase(it);
}
}
s_lock.unlock();
return 0;
}
static void signal_handler(struct ev_loop* main_loop, ev_signal* signal_w, int e)
{
asyncCall(async_signal_handler, 0);
}
static void async_init_sprocess(void* v)
{
struct ev_loop* s_loop = (struct ev_loop*)v;
static ev_signal signal_chld;
ev_init(&signal_chld, signal_handler);
ev_signal_set(&signal_chld, SIGCHLD);
ev_signal_start(s_loop, &signal_chld);
}
void init_process()
{
AsyncIO::run(async_init_sprocess);
}
class PSTimer : public Timer {
public:
PSTimer(int32_t timeout, intptr_t pid)
@@ -140,6 +184,7 @@ result_t SubProcess::create(exlib::string command, v8::Local<v8::Array> args, v8
envp.push_back(NULL);
errno = 0;
s_lock.lock();
err = posix_spawnp(&pid, command.c_str(), redirect ? &fops : NULL,
NULL, _args.data(), &envp[0]);
@@ -157,12 +202,14 @@ result_t SubProcess::create(exlib::string command, v8::Local<v8::Array> args, v8
if (WIFEXITED(status))
status = WEXITSTATUS(status);
if (pid1 == -1 || status == 127)
if (status == 127)
err = 2;
}
#endif
if (err != 0) {
s_lock.unlock();
if (redirect) {
::close(cin_pipe[1]);
::close(cout_pipe[0]);
@@ -172,6 +219,10 @@ result_t SubProcess::create(exlib::string command, v8::Local<v8::Array> args, v8
}
obj_ptr<SubProcess> sub = new SubProcess(pid);
s_ids.insert(std::pair<pid_t, obj_ptr<SubProcess>>(pid, sub));
s_lock.unlock();
if (redirect) {
wrap_pipe(cin_pipe[1], sub->m_stdin);
wrap_pipe(cout_pipe[0], sub->m_stdout);
@@ -206,49 +257,45 @@ result_t SubProcess::kill(int32_t signal)
result_t SubProcess::wait(int32_t& retVal, AsyncEvent* ac)
{
class asyncWaitPid : public AsyncState {
class asyncWaitPid : public exlib::Task_base {
public:
asyncWaitPid(intptr_t pid, Timer* timer, int32_t& retVal, AsyncEvent* ac)
: AsyncState(ac)
, m_pid(pid)
, m_timer(timer)
asyncWaitPid(SubProcess* sub, int32_t& retVal, AsyncEvent* ac)
: m_sub(sub)
, m_retVal(retVal)
, m_ac(ac)
{
set(wait);
}
public:
static int32_t wait(AsyncState* pState, int32_t n)
virtual void resume()
{
asyncWaitPid* pThis = (asyncWaitPid*)pState;
if (WIFEXITED(m_sub->m_status))
m_retVal = WEXITSTATUS(m_sub->m_status);
else
m_retVal = m_sub->m_status;
pThis->set(result);
return AsyncIO::waitpid(pThis->m_pid, pThis->m_retVal, pThis);
}
if (m_sub->m_timer)
m_sub->m_timer->clear();
static int32_t result(AsyncState* pState, int32_t n)
{
asyncWaitPid* pThis = (asyncWaitPid*)pState;
m_ac->apost(0);
if (WIFEXITED(pThis->m_retVal))
pThis->m_retVal = WEXITSTATUS(pThis->m_retVal);
if (pThis->m_timer)
pThis->m_timer->clear();
return pThis->done();
delete this;
}
private:
intptr_t m_pid;
obj_ptr<Timer> m_timer;
obj_ptr<SubProcess> m_sub;
int32_t& m_retVal;
AsyncEvent* m_ac;
};
if (ac->isSync())
return CHECK_ERROR(CALL_E_NOSYNC);
return (new asyncWaitPid(m_pid, m_timer, retVal, ac))->post(0);
asyncWaitPid* awp = new asyncWaitPid(this, retVal, ac);
if (m_exit.wait(awp))
awp->resume();
return CALL_E_PENDDING;
}
result_t SubProcess::findWindow(exlib::string name, v8::Local<v8::Value>& retVal)
@@ -17,6 +17,10 @@
namespace fibjs {
void init_process()
{
}
class PSTimer : public Timer {
public:
PSTimer(int32_t timeout, HANDLE pid)
@@ -35,7 +35,7 @@ static void _InterruptCallback(v8::Isolate* v8_isolate, void* data)
process_base::exit(1);
}
result_t async_signal(const char* name)
static result_t async_signal(const char* name)
{
Isolate* isolate = s_isolates.head();
2 vender

0 comments on commit 1aa840c

Please sign in to comment.