{"id":13484421,"url":"https://github.com/rtomayko/posix-spawn","last_synced_at":"2025-05-14T20:09:08.133Z","repository":{"id":56888554,"uuid":"1416811","full_name":"rtomayko/posix-spawn","owner":"rtomayko","description":"Ruby process spawning library","archived":false,"fork":false,"pushed_at":"2024-03-19T15:24:11.000Z","size":269,"stargazers_count":522,"open_issues_count":15,"forks_count":56,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-05-14T01:31:02.194Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rtomayko.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2011-02-27T03:05:07.000Z","updated_at":"2025-04-19T14:49:35.000Z","dependencies_parsed_at":"2024-05-01T11:01:06.568Z","dependency_job_id":null,"html_url":"https://github.com/rtomayko/posix-spawn","commit_stats":{"total_commits":238,"total_committers":30,"mean_commits":7.933333333333334,"dds":0.5882352941176471,"last_synced_commit":"313f2abd4b9b5e737615178e0b353114481b9ab8"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rtomayko%2Fposix-spawn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rtomayko%2Fposix-spawn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rtomayko%2Fposix-spawn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rtomayko%2Fposix-spawn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rtomayko","download_url":"https://codeload.github.com/rtomayko/posix-spawn/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254219373,"owners_count":22034397,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T17:01:24.162Z","updated_at":"2025-05-14T20:09:08.116Z","avatar_url":"https://github.com/rtomayko.png","language":"Ruby","readme":"# posix-spawn\n\n`fork(2)` calls slow down as the parent process uses more memory due to the need\nto copy page tables. In many common uses of fork(), where it is followed by one\nof the exec family of functions to spawn child processes (`Kernel#system`,\n`IO::popen`, `Process::spawn`, etc.), it's possible to remove this overhead by using\nspecial process spawning interfaces (`posix_spawn()`, `vfork()`, etc.)\n\nThe posix-spawn library aims to implement a subset of the Ruby 1.9 `Process::spawn`\ninterface in a way that takes advantage of fast process spawning interfaces when\navailable and provides sane fallbacks on systems that do not.\n\n### FEATURES\n\n - Fast, constant-time spawn times across a variety of platforms.\n - A largish compatible subset of Ruby 1.9's `Process::spawn` interface and\n   enhanced versions of `Kernel#system`, \u003ccode\u003eKernel#`\u003c/code\u003e, etc. under\n   Ruby \u003e= 1.8.7 (currently MRI only).\n - High level `POSIX::Spawn::Child` class for quick (but correct!)\n   non-streaming IPC scenarios.\n\n## BENCHMARKS\n\nThe following benchmarks illustrate time needed to fork/exec a child process at\nincreasing resident memory sizes on Linux 2.6 and MacOS X. Tests were run using\nthe [`posix-spawn-benchmark`][pb] program included with the package.\n\n[pb]: https://github.com/rtomayko/posix-spawn/tree/master/bin\n\n### Linux\n\n![](https://chart.googleapis.com/chart?chbh=a,5,25\u0026chxr=1,0,36,7\u0026chd=t:5.77,10.37,15.72,18.31,19.73,25.13,26.70,29.31,31.44,35.49|0.86,0.82,1.06,0.99,0.79,1.06,0.84,0.79,0.93,0.94\u0026chxs=1N**%20secs\u0026chs=900x200\u0026chds=0,36\u0026chxl=0:|50%20MB|100%20MB|150%20MB|200%20MB|250%20MB|300%20MB|350%20MB|400%20MB|450%20MB|500%20MB\u0026cht=bvg\u0026chdl=fspawn%20%28fork%2Bexec%29|pspawn%20%28posix_spawn%29\u0026chtt=posix-spawn-benchmark%20--graph%20--count%20500%20--mem-size%20500%20%28x86_64-linux%29\u0026chco=1f77b4,ff7f0e\u0026chf=bg,s,f8f8f8\u0026chxt=x,y#.png)\n\n`posix_spawn` is faster than `fork+exec`, and executes in constant time when\nused with `POSIX_SPAWN_USEVFORK`.\n\n`fork+exec` is extremely slow for large parent processes.\n\n### OSX\n\n![](https://chart.googleapis.com/chart?chxl=0:|50%20MB|100%20MB|150%20MB|200%20MB|250%20MB|300%20MB|350%20MB|400%20MB|450%20MB|500%20MB\u0026cht=bvg\u0026chdl=fspawn%20%28fork%2Bexec%29|pspawn%20%28posix_spawn%29\u0026chtt=posix-spawn-benchmark%20--graph%20--count%20500%20--mem-size%20500%20%28i686-darwin10.5.0%29\u0026chco=1f77b4,ff7f0e\u0026chf=bg,s,f8f8f8\u0026chxt=x,y\u0026chbh=a,5,25\u0026chxr=1,0,3,0\u0026chd=t:1.95,2.07,2.56,2.29,2.21,2.32,2.15,2.25,1.96,2.02|0.84,0.97,0.89,0.82,1.13,0.89,0.93,0.81,0.83,0.81\u0026chxs=1N**%20secs\u0026chs=900x200\u0026chds=0,3#.png)\n\n`posix_spawn` is faster than `fork+exec`, but neither is affected by the size of\nthe parent process.\n\n## USAGE\n\nThis library includes two distinct interfaces: `POSIX::Spawn::spawn`, a lower\nlevel process spawning interface based on the new Ruby 1.9 `Process::spawn`\nmethod, and `POSIX::Spawn::Child`, a higher level class geared toward easy\nspawning of processes with simple string based standard input/output/error\nstream handling. The former is much more versatile, the latter requires much\nless code for certain common scenarios.\n\n### POSIX::Spawn::spawn\n\nThe `POSIX::Spawn` module (with help from the accompanying C extension)\nimplements a subset of the [Ruby 1.9 Process::spawn][ps] interface, largely\nthrough the use of the [IEEE Std 1003.1 `posix_spawn(2)` systems interfaces][po].\nThese are widely supported by various UNIX operating systems.\n\n[ps]: http://www.ruby-doc.org/core-1.9/classes/Process.html#M002230\n[po]: http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_spawn.html\n\nIn its simplest form, the `POSIX::Spawn::spawn` method can be used to execute a\nchild process similar to `Kernel#system`:\n\n    require 'posix/spawn'\n    pid  = POSIX::Spawn::spawn('echo', 'hello world')\n    stat = Process::waitpid(pid)\n\nThe first line executes `echo` with a single argument and immediately returns\nthe new process's `pid`. The second line waits for the process to complete and\nreturns a `Process::Status` object. Note that `spawn` *does not* wait for the\nprocess to finish execution like `system` and does not reap the child's exit\nstatus -- you must call `Process::waitpid` (or equivalent) or the process will\nbecome a zombie.\n\nThe `spawn` method is capable of performing a large number of additional\noperations, from setting up the new process's environment, to changing the\nchild's working directory, to redirecting arbitrary file descriptors.\n\nSee the Ruby 1.9 [`Process::spawn` documentation][ps] for details and the\n`STATUS` section below for a full account of the various `Process::spawn`\nfeatures supported by `POSIX::Spawn::spawn`.\n\n### `system`, `popen4`, and \u003ccode\u003e`\u003c/code\u003e\n\nIn addition to the `spawn` method, Ruby 1.9 compatible implementations of\n`Kernel#system` and \u003ccode\u003eKernel#\\`\u003c/code\u003e are provided in the `POSIX::Spawn`\nmodule. The `popen4` method can be used to spawn a process with redirected\nstdin, stdout, and stderr objects.\n\n### POSIX::Spawn as a Mixin\n\nThe `POSIX::Spawn` module can also be mixed in to classes and modules to include\n`spawn` and all utility methods in that namespace:\n\n    require 'posix/spawn'\n\n    class YourGreatClass\n      include POSIX::Spawn\n\n      def speak(message)\n        pid = spawn('echo', message)\n        Process::waitpid(pid)\n      end\n\n      def calculate(expression)\n        pid, in, out, err = popen4('bc')\n        in.write(expression)\n        in.close\n        out.read\n      ensure\n        [in, out, err].each { |io| io.close if !io.closed? }\n        Process::waitpid(pid)\n      end\n    end\n\n### POSIX::Spawn::Child\n\nThe `POSIX::Spawn::Child` class includes logic for executing child processes and\nreading/writing from their standard input, output, and error streams. It's\ndesigned to take all input in a single string and provides all output as single\nstrings and is therefore not well-suited to streaming large quantities of data\nin and out of commands. That said, it has some benefits:\n\n - **Simple** - requires little code for simple stream input and capture.\n - **Internally non-blocking** (using `select(2)`) - handles all pipe hang cases\n   due to exceeding `PIPE_BUF` limits on one or more streams.\n - **Potentially portable** - abstracts lower-level process and stream\n   management APIs so the class can be made to work on platforms like Java and\n   Windows where UNIX process spawning and stream APIs are not supported.\n\n`POSIX::Spawn::Child` takes the standard `spawn` arguments when instantiated,\nand runs the process to completion after writing all input and reading all\noutput:\n\n    \u003e\u003e require 'posix/spawn'\n    \u003e\u003e child = POSIX::Spawn::Child.new('git', '--help')\n\nRetrieve process output written to stdout / stderr, or inspect the process's\nexit status:\n\n    \u003e\u003e child.out\n    =\u003e \"usage: git [--version] [--exec-path[=GIT_EXEC_PATH]]\\n ...\"\n    \u003e\u003e child.err\n    =\u003e \"\"\n    \u003e\u003e child.status\n    =\u003e #\u003cProcess::Status: pid=80718,exited(0)\u003e\n\nUse the `:input` option to write data on the new process's stdin immediately\nafter spawning:\n\n    \u003e\u003e child = POSIX::Spawn::Child.new('bc', :input =\u003e '40 + 2')\n    \u003e\u003e child.out\n    \"42\\n\"\n\nAdditional options can be used to specify the maximum output size (`:max`) and\ntime of execution (`:timeout`) before the child process is aborted. See the\n`POSIX::Spawn::Child` docs for more info.\n\n#### Reading Partial Results\n\n`POSIX::Spawn::Child.new` spawns the process immediately when instantiated.\nAs a result, if it is interrupted by an exception (either from reaching the\nmaximum output size, the time limit, or another factor), it is not possible to\naccess the `out` or `err` results because the constructor did not complete.\n\nIf you want to get the `out` and `err` data was available when the process\nwas interrupted, use the `POSIX::Spawn::Child.build` alternate form to\ncreate the child without immediately spawning the process.  Call `exec!`\nto run the command at a place where you can catch any exceptions:\n\n    \u003e\u003e child = POSIX::Spawn::Child.build('git', 'log', :max =\u003e 100)\n    \u003e\u003e begin\n    ?\u003e   child.exec!\n    ?\u003e rescue POSIX::Spawn::MaximumOutputExceeded\n    ?\u003e   # limit was reached\n    ?\u003e end\n    \u003e\u003e child.out\n    \"commit fa54abe139fd045bf6dc1cc259c0f4c06a9285bb\\n...\"\n\nPlease note that when the `MaximumOutputExceeded` exception is raised, the\nactual combined `out` and `err` data may be a bit longer than the `:max`\nvalue due to internal buffering.\n\n## STATUS\n\nThe `POSIX::Spawn::spawn` method is designed to be as compatible with Ruby 1.9's\n`Process::spawn` as possible. Right now, it is a compatible subset.\n\nThese `Process::spawn` arguments are currently supported to any of\n`Spawn::spawn`, `Spawn::system`, `Spawn::popen4`, and `Spawn::Child.new`:\n\n    env: hash\n      name =\u003e val : set the environment variable\n      name =\u003e nil : unset the environment variable\n    command...:\n      commandline                 : command line string which is passed to a shell\n      cmdname, arg1, ...          : command name and one or more arguments (no shell)\n      [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)\n    options: hash\n      clearing environment variables:\n        :unsetenv_others =\u003e true   : clear environment variables except specified by env\n        :unsetenv_others =\u003e false  : don't clear (default)\n      current directory:\n        :chdir =\u003e str : Not thread-safe when using posix_spawn (see below)\n      process group:\n        :pgroup =\u003e true or 0 : make a new process group\n        :pgroup =\u003e pgid      : join to specified process group\n        :pgroup =\u003e nil       : don't change the process group (default)\n      redirection:\n        key:\n          FD              : single file descriptor in child process\n          [FD, FD, ...]   : multiple file descriptor in child process\n        value:\n          FD                        : redirect to the file descriptor in parent process\n          :close                    : close the file descriptor in child process\n          string                    : redirect to file with open(string, \"r\" or \"w\")\n          [string]                  : redirect to file with open(string, File::RDONLY)\n          [string, open_mode]       : redirect to file with open(string, open_mode, 0644)\n          [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)\n        FD is one of follows\n          :in     : the file descriptor 0 which is the standard input\n          :out    : the file descriptor 1 which is the standard output\n          :err    : the file descriptor 2 which is the standard error\n          integer : the file descriptor of specified the integer\n          io      : the file descriptor specified as io.fileno\n\nThese options are currently NOT supported:\n\n    options: hash\n      resource limit: resourcename is core, cpu, data, etc.  See Process.setrlimit.\n        :rlimit_resourcename =\u003e limit\n        :rlimit_resourcename =\u003e [cur_limit, max_limit]\n      umask:\n        :umask =\u003e int\n      redirection:\n        value:\n          [:child, FD]              : redirect to the redirected file descriptor\n      file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not\n        :close_others =\u003e false : inherit fds (default for system and exec)\n        :close_others =\u003e true  : don't inherit (default for spawn and IO.popen)\n\nThe `:chdir` option provided by Posix::Spawn::Child, Posix::Spawn#spawn,\nPosix::Spawn#system and Posix::Spawn#popen4 is not thread-safe because\nprocesses spawned with the posix_spawn(2) system call inherit the working\ndirectory of the calling process. The posix-spawn gem works around this\nlimitation in the system call by changing the working directory of the calling\nprocess immediately before and after spawning the child process.\n\n## ACKNOWLEDGEMENTS\n\nCopyright (c) by\n[Ryan Tomayko](http://tomayko.com/about)\nand\n[Aman Gupta](https://github.com/tmm1).\n\nSee the `COPYING` file for more information on license and redistribution.\n","funding_links":[],"categories":["Processes and Threads","Processes"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frtomayko%2Fposix-spawn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frtomayko%2Fposix-spawn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frtomayko%2Fposix-spawn/lists"}