Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unix: add support for PR_SET_PDEATHSIG #10515

Closed
recoules opened this issue Jul 15, 2021 · 5 comments
Closed

Unix: add support for PR_SET_PDEATHSIG #10515

recoules opened this issue Jul 15, 2021 · 5 comments

Comments

@recoules
Copy link
Contributor

Hi,

I'll take the example of binsec that often call external SMT solver session with pipe communication (e.g. Unix.open_process).
After long running sessions, the main process may be killed by the OOM Process Killer, leaving the waiting or running SMT solver sessions open.

On linux, the problem can be addressed by sending a signal to the child process on the parent death (e.g. prctl(PR_SET_PDEATHSIG, SIGKILL);).

However, to make it work in OCaml, we need both to write a C stub and to manually rewrite all the spawning function to execute prctl after the fork but before the exec*. This shares all but few lines of unix.ml code and it is not a good development practice (moreover, I am not really sure how the license act in such case).

Thus, I think it is preferable that the Unix module offers some facilities for the open_process_* functions to set this signal, either by:

  • adding an optional argument ?pdeathsig:int (principled solution);
  • allowing an arbitrary closure to run after the fork, but before the exec* (generic approach).

Do you think such thing can be added?

Regards,

@xavierleroy
Copy link
Contributor

Note: the prctl system call mentioned here is specific to Linux and not standardized in any way.

Since 4.12, Unix.create_process and related functions use posix_spawn whenever possible, see #9573. Can this feature wish be implemented with posix_spawn? If not, that's a blocker.

@recoules
Copy link
Contributor Author

recoules commented Jul 16, 2021

Hi @xavierleroy, as far as I understand, the pre-exec() step: housekeeping step of the posix_spawn man is exactly what we need.

The OCaml function can expose an additional (optional) argument, a unit -> unit closure that will be registered with posix_spawn_file_actions_add and thus be called between fork and exec.

This way we will have all the keys to easily define our own initialization function and call prctl with a C binding if we want and are on linux.

I can take a closer look and open a merge request if you want?

@xavierleroy
Copy link
Contributor

Maybe there's a misunderstanding or two.

First, the posix_spawn API gives no way to call back a user-provided function at any point in the process. It supports a predefined set of actions over signals and over file descriptors, but is not extensible. This is on purpose, I believe, so that it can be implemented efficiently even on systems where fork is not available.

For the Glibc/Linux implementation of posix_spawn, it might make sense to support some of the prctl operations as additional, nonportable, predefined actions. But that's for the Glibc developers to decide.

The other possible misunderstanding is the reasons why OCaml moved away from implementations of create_process based on fork thenexec in OCaml. It's not just for performance, but also because Multicore OCaml will not support fork in parallel programs. (The reason is that it's very hard to put the runtime system back in a working state after the fork, when all system threads except the one doing fork have been killed.) So, there cannot be a callback from C to OCaml in the forked child, before the exec.

@recoules
Copy link
Contributor Author

You are right, I should have read more carefully the man description.

it might make sense to support some of the prctl operations as additional, nonportable, predefined actions.

It would be nice, yeah. I think I will follow your advice and open a request to Glibc developers.

You can close this issue for now, I will come back to you if there are some interesting moves.
Thank you again,

@xavierleroy
Copy link
Contributor

You're welcome.

The traditional way to kill all child processes when the parent is killed relies on process groups and a monitoring program. See for example the timeout command from GNU coreutils. Maybe this would give a more portable solution to your problem.

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

No branches or pull requests

2 participants