Skip to content
This repository has been archived by the owner on May 4, 2018. It is now read-only.

abort() when uv_signal_start() after fork() #1405

Open
ibc opened this issue Aug 7, 2014 · 11 comments
Open

abort() when uv_signal_start() after fork() #1405

ibc opened this issue Aug 7, 2014 · 11 comments

Comments

@ibc
Copy link
Contributor

ibc commented Aug 7, 2014

libuv master. This crash happens in OSX (in Linux it gets frozen). My code does the following:

    1. Run the following code:
uv_loop_t loop;
int err;

err = uv_loop_init(&loop);
if (err)
    exit(1);

err = uv_run(&loop, UV_RUN_NOWAIT);
if (err)
    exit(1);

err = uv_loop_close(&loop);
if (err)
    exit(1);
    1. The typical double fork() to become a daemon.
    1. Init a new UV loop, init a uv_signal handler and call uv_signal_start().

It crashes as shown below. It works perfectly if I don't fork.

lldb output in OSX:

(lldb) bt all
* thread #1: tid = 0x0000, 0x00007fff894fc866 libsystem_kernel.dylib`__pthread_kill + 10, stop reason = signal SIGSTOP
  * frame #0: 0x00007fff894fc866 libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x00007fff8687535c libsystem_pthread.dylib`pthread_kill + 92
    frame #2: 0x00007fff854a3b1a libsystem_c.dylib`abort + 125
    frame #3: 0x0000000101b52716 libuv.11.dylib`uv_signal_start [inlined] uv__signal_block_and_lock(saved_sigmask=0xffffffff00000000) + 182 at signal.c:106
    frame #4: 0x0000000101b526b8 libuv.11.dylib`uv_signal_start(handle=0x00007ffa43404e10, signal_cb=0x0000000101ac01b0, signum=30) + 88 at signal.c:315

The UV code calling abort() is in src/unix/signal.c line 106:

static void uv__signal_block_and_lock(sigset_t* saved_sigmask) {
  sigset_t new_mask;

  if (sigfillset(&new_mask))
    abort();

  if (pthread_sigmask(SIG_SETMASK, &new_mask, saved_sigmask))
    abort();

  if (uv__signal_lock())
    abort();           // <----- HERE
}

So uv__signal_lock() returns != 0:

static int uv__signal_lock(void) {
  int r;
  char data;

  do {
    r = read(uv__signal_lock_pipefd[0], &data, sizeof data);
  } while (r < 0 && errno == EINTR);

  return (r < 0) ? -1 : 0;
}

Can not I run (and close) a UV loop before forking and then run other after forking??

@saghul
Copy link
Contributor

saghul commented Aug 7, 2014

There is some global state associated with signal handling, so I wouldn't do that. We don't currently have a good story for forking scenarios, I'm afraid.

@ibc
Copy link
Contributor Author

ibc commented Aug 7, 2014

Opps, and let me know: such a "global state" (which I assume is the static Unix sockets for firing signal events to each loop) is created upon initiation of the first UV loop, right?

@saghul
Copy link
Contributor

saghul commented Aug 7, 2014

@ibc
Copy link
Contributor Author

ibc commented Aug 7, 2014

So no imminent fix, right?

@saghul
Copy link
Contributor

saghul commented Aug 7, 2014

Nope, I'm afraid.

@ibc
Copy link
Contributor Author

ibc commented Aug 7, 2014

Afraid of what?

@saghul
Copy link
Contributor

saghul commented Aug 7, 2014

It's not happening any time soon, I mean.

@mmalecki
Copy link

Could we possibly have a uv_fork function which would properly set up uv's global state after forking?

@saghul
Copy link
Contributor

saghul commented Aug 10, 2014

Ideally it would be nice to make it automagic. Maybe we can use pthread_atfork for resetting global state in the child.

I don't think we can support all cases, so I'd say that creating an eventloop in the parent and then trying to use in the child would be unsupported. This should make things easier, though I haven't really sat down to think this all the way through.

You are welcome to work on this and come up with a design which we can discuss :-)

@ibc
Copy link
Contributor Author

ibc commented Aug 10, 2014

2014-08-10 21:28 GMT+02:00 Saúl Ibarra Corretgé [email protected]:

I don't think we can support all cases, so I'd say that creating an
eventloop in the parent and then trying to use in the child would be
unsupported. This should make things easier, though I haven't really sat
down to think this all the way through.

BTW my use-case was not su hard:

  • Create UV loop in the parent.
  • Run it and properly stop and close it.
  • Fork.
  • Create another loop.

I was never trying to reuse the same loop.

Iñaki Baz Castillo
[email protected]

@saghul
Copy link
Contributor

saghul commented Aug 10, 2014

@ibc yeah, your use case would be supported. But we would need to reinitialize some stuff like the signal handlers thing and probably something in the threadpool as well.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants