xref: /libuv/docs/src/guide/processes.rst (revision 520eb622)
1Processes
2=========
3
4libuv offers considerable child process management, abstracting the platform
5differences and allowing communication with the child process using streams or
6named pipes.
7
8A common idiom in Unix is for every process to do one thing and do it well. In
9such a case, a process often uses multiple child processes to achieve tasks
10(similar to using pipes in shells). A multi-process model with messages
11may also be easier to reason about compared to one with threads and shared
12memory.
13
14A common refrain against event-based programs is that they cannot take
15advantage of multiple cores in modern computers. In a multi-threaded program
16the kernel can perform scheduling and assign different threads to different
17cores, improving performance. But an event loop has only one thread.  The
18workaround can be to launch multiple processes instead, with each process
19running an event loop, and each process getting assigned to a separate CPU
20core.
21
22Spawning child processes
23------------------------
24
25The simplest case is when you simply want to launch a process and know when it
26exits. This is achieved using ``uv_spawn``.
27
28.. rubric:: spawn/main.c
29.. literalinclude:: ../../code/spawn/main.c
30    :language: c
31    :linenos:
32    :lines: 6-8,15-
33    :emphasize-lines: 11,13-17
34
35.. NOTE::
36
37    ``options`` is implicitly initialized with zeros since it is a global
38    variable.  If you change ``options`` to a local variable, remember to
39    initialize it to null out all unused fields::
40
41        uv_process_options_t options = {0};
42
43The ``uv_process_t`` struct only acts as the handle, all options are set via
44``uv_process_options_t``. To simply launch a process, you need to set only the
45``file`` and ``args`` fields. ``file`` is the program to execute. Since
46``uv_spawn`` uses :man:`execvp(3)` internally, there is no need to supply the full
47path. Finally as per underlying conventions, **the arguments array has to be
48one larger than the number of arguments, with the last element being NULL**.
49
50After the call to ``uv_spawn``, ``uv_process_t.pid`` will contain the process
51ID of the child process.
52
53The exit callback will be invoked with the *exit status* and the type of *signal*
54which caused the exit.
55
56Note that it is important **not** to call ``uv_close`` before the exit callback.
57
58.. rubric:: spawn/main.c
59.. literalinclude:: ../../code/spawn/main.c
60    :language: c
61    :linenos:
62    :lines: 9-12
63    :emphasize-lines: 3
64
65It is **required** to close the process watcher after the process exits.
66
67Changing process parameters
68---------------------------
69
70Before the child process is launched you can control the execution environment
71using fields in ``uv_process_options_t``.
72
73Change execution directory
74++++++++++++++++++++++++++
75
76Set ``uv_process_options_t.cwd`` to the corresponding directory.
77
78Set environment variables
79+++++++++++++++++++++++++
80
81``uv_process_options_t.env`` is a null-terminated array of strings, each of the
82form ``VAR=VALUE`` used to set up the environment variables for the process. Set
83this to ``NULL`` to inherit the environment from the parent (this) process.
84
85Option flags
86++++++++++++
87
88Setting ``uv_process_options_t.flags`` to a bitwise OR of the following flags,
89modifies the child process behaviour:
90
91* ``UV_PROCESS_SETUID`` - sets the child's execution user ID to ``uv_process_options_t.uid``.
92* ``UV_PROCESS_SETGID`` - sets the child's execution group ID to ``uv_process_options_t.gid``.
93
94Changing the UID/GID is only supported on Unix, ``uv_spawn`` will fail on
95Windows with ``UV_ENOTSUP``.
96
97* ``UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS`` - No quoting or escaping of
98  ``uv_process_options_t.args`` is done on Windows. Ignored on Unix.
99* ``UV_PROCESS_DETACHED`` - Starts the child process in a new session, which
100  will keep running after the parent process exits. See example below.
101
102Detaching processes
103-------------------
104
105Passing the flag ``UV_PROCESS_DETACHED`` can be used to launch daemons, or
106child processes which are independent of the parent so that the parent exiting
107does not affect it.
108
109.. rubric:: detach/main.c
110.. literalinclude:: ../../code/detach/main.c
111    :language: c
112    :linenos:
113    :lines: 9-30
114    :emphasize-lines: 12,19
115
116Just remember that the handle is still monitoring the child, so your program
117won't exit. Use ``uv_unref()`` if you want to be more *fire-and-forget*.
118
119Sending signals to processes
120----------------------------
121
122libuv wraps the standard ``kill(2)`` system call on Unix and implements one
123with similar semantics on Windows, with *one caveat*: all of ``SIGTERM``,
124``SIGINT`` and ``SIGKILL``, lead to termination of the process. The signature
125of ``uv_kill`` is::
126
127    uv_err_t uv_kill(int pid, int signum);
128
129For processes started using libuv, you may use ``uv_process_kill`` instead,
130which accepts the ``uv_process_t`` watcher as the first argument, rather than
131the pid. In this case, **remember to call** ``uv_close`` on the watcher _after_
132the exit callback has been called.
133
134Signals
135-------
136
137libuv provides wrappers around Unix signals with `some Windows support
138<http://docs.libuv.org/en/v1.x/signal.html#signal>`_ as well.
139
140Use ``uv_signal_init()`` to initialize
141a handle and associate it with a loop. To listen for particular signals on
142that handler, use ``uv_signal_start()`` with the handler function. Each handler
143can only be associated with one signal number, with subsequent calls to
144``uv_signal_start()`` overwriting earlier associations. Use ``uv_signal_stop()`` to
145stop watching. Here is a small example demonstrating the various possibilities:
146
147.. rubric:: signal/main.c
148.. literalinclude:: ../../code/signal/main.c
149    :language: c
150    :linenos:
151    :emphasize-lines: 17-18,27-28
152
153.. NOTE::
154
155    ``uv_run(loop, UV_RUN_NOWAIT)`` is similar to ``uv_run(loop, UV_RUN_ONCE)``
156    in that it will process only one event. UV_RUN_ONCE blocks if there are no
157    pending events, while UV_RUN_NOWAIT will return immediately. We use NOWAIT
158    so that one of the loops isn't starved because the other one has no pending
159    activity.
160
161Send ``SIGUSR1`` to the process, and you'll find the handler being invoked
1624 times, one for each ``uv_signal_t``. The handler just stops each handle,
163so that the program exits. This sort of dispatch to all handlers is very
164useful. A server using multiple event loops could ensure that all data was
165safely saved before termination, simply by every loop adding a watcher for
166``SIGINT``.
167
168Child Process I/O
169-----------------
170
171A normal, newly spawned process has its own set of file descriptors, with 0,
1721 and 2 being ``stdin``, ``stdout`` and ``stderr`` respectively. Sometimes you
173may want to share file descriptors with the child. For example, perhaps your
174applications launches a sub-command and you want any errors to go in the log
175file, but ignore ``stdout``. For this you'd like to have ``stderr`` of the
176child be the same as the stderr of the parent. In this case, libuv supports
177*inheriting* file descriptors. In this sample, we invoke the test program,
178which is:
179
180.. rubric:: proc-streams/test.c
181.. literalinclude:: ../../code/proc-streams/test.c
182    :language: c
183
184The actual program ``proc-streams`` runs this while sharing only ``stderr``.
185The file descriptors of the child process are set using the ``stdio`` field in
186``uv_process_options_t``. First set the ``stdio_count`` field to the number of
187file descriptors being set. ``uv_process_options_t.stdio`` is an array of
188``uv_stdio_container_t``, which is:
189
190.. code-block:: c
191
192    typedef struct uv_stdio_container_s {
193        uv_stdio_flags flags;
194
195        union {
196            uv_stream_t* stream;
197            int fd;
198        } data;
199    } uv_stdio_container_t;
200
201where flags can have several values. Use ``UV_IGNORE`` if it isn't going to be
202used. If the first three ``stdio`` fields are marked as ``UV_IGNORE`` they'll
203redirect to ``/dev/null``.
204
205Since we want to pass on an existing descriptor, we'll use ``UV_INHERIT_FD``.
206Then we set the ``fd`` to ``stderr``.
207
208.. rubric:: proc-streams/main.c
209.. literalinclude:: ../../code/proc-streams/main.c
210    :language: c
211    :linenos:
212    :lines: 15-17,27-
213    :emphasize-lines: 6,10,11,12
214
215If you run ``proc-stream`` you'll see that only the line "This is stderr" will
216be displayed. Try marking ``stdout`` as being inherited and see the output.
217
218It is dead simple to apply this redirection to streams.  By setting ``flags``
219to ``UV_INHERIT_STREAM`` and setting ``data.stream`` to the stream in the
220parent process, the child process can treat that stream as standard I/O. This
221can be used to implement something like CGI_.
222
223.. _CGI: https://en.wikipedia.org/wiki/Common_Gateway_Interface
224
225A sample CGI script/executable is:
226
227.. rubric:: cgi/tick.c
228.. literalinclude:: ../../code/cgi/tick.c
229    :language: c
230
231The CGI server combines the concepts from this chapter and :doc:`networking` so
232that every client is sent ten ticks after which that connection is closed.
233
234.. rubric:: cgi/main.c
235.. literalinclude:: ../../code/cgi/main.c
236    :language: c
237    :linenos:
238    :lines: 49-63
239    :emphasize-lines: 10
240
241Here we simply accept the TCP connection and pass on the socket (*stream*) to
242``invoke_cgi_script``.
243
244.. rubric:: cgi/main.c
245.. literalinclude:: ../../code/cgi/main.c
246    :language: c
247    :linenos:
248    :lines: 16, 25-45
249    :emphasize-lines: 8-9,18,20
250
251The ``stdout`` of the CGI script is set to the socket so that whatever our tick
252script prints, gets sent to the client. By using processes, we can offload the
253read/write buffering to the operating system, so in terms of convenience this
254is great. Just be warned that creating processes is a costly task.
255
256.. _pipes:
257
258Parent-child IPC
259----------------
260
261A parent and child can have one or two way communication over a pipe created by
262settings ``uv_stdio_container_t.flags`` to a bit-wise combination of
263``UV_CREATE_PIPE`` and ``UV_READABLE_PIPE`` or ``UV_WRITABLE_PIPE``. The
264read/write flag is from the perspective of the child process.  In this case,
265the ``uv_stream_t* stream`` field must be set to point to an initialized,
266unopened ``uv_pipe_t`` instance.
267
268New stdio Pipes
269+++++++++++++++
270
271The ``uv_pipe_t`` structure represents more than just `pipe(7)`_ (or ``|``),
272but supports any streaming file-like objects. On Windows, the only object of
273that description is the `Named Pipe`_.  On Unix, this could be any of `Unix
274Domain Socket`_, or derived from `mkfifo(1)`_, or it could actually be a
275`pipe(7)`_.  When ``uv_spawn`` initializes a ``uv_pipe_t`` due to the
276`UV_CREATE_PIPE` flag, it opts for creating a `socketpair(2)`_.
277
278This is intended for the purpose of allowing multiple libuv processes to
279communicate with IPC. This is discussed below.
280
281.. _pipe(7): https://man7.org/linux/man-pages/man7/pipe.7.html
282.. _mkfifo(1): https://man7.org/linux/man-pages/man1/mkfifo.1.html
283.. _socketpair(2): https://man7.org/linux/man-pages/man2/socketpair.2.html
284.. _Unix Domain Socket: https://man7.org/linux/man-pages/man7/unix.7.html
285.. _Named Pipe: https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipes
286
287
288Arbitrary process IPC
289+++++++++++++++++++++
290
291Since domain sockets [#]_ can have a well known name and a location in the
292file-system they can be used for IPC between unrelated processes. The D-BUS_
293system used by open source desktop environments uses domain sockets for event
294notification. Various applications can then react when a contact comes online
295or new hardware is detected. The MySQL server also runs a domain socket on
296which clients can interact with it.
297
298.. _D-BUS: https://www.freedesktop.org/wiki/Software/dbus
299
300When using domain sockets, a client-server pattern is usually followed with the
301creator/owner of the socket acting as the server. After the initial setup,
302messaging is no different from TCP, so we'll re-use the echo server example.
303
304.. rubric:: pipe-echo-server/main.c
305.. literalinclude:: ../../code/pipe-echo-server/main.c
306    :language: c
307    :linenos:
308    :lines: 70-
309    :emphasize-lines: 5,10,14
310
311We name the socket ``echo.sock`` which means it will be created in the local
312directory. This socket now behaves no different from TCP sockets as far as
313the stream API is concerned. You can test this server using `socat`_::
314
315    $ socat - /path/to/socket
316
317A client which wants to connect to a domain socket will use::
318
319    void uv_pipe_connect(uv_connect_t *req, uv_pipe_t *handle, const char *name, uv_connect_cb cb);
320
321where ``name`` will be ``echo.sock`` or similar. On Unix systems, ``name`` must
322point to a valid file (e.g. ``/tmp/echo.sock``). On Windows, ``name`` follows a
323``\\?\pipe\echo.sock`` format.
324
325.. _socat: http://www.dest-unreach.org/socat/
326
327Sending file descriptors over pipes
328+++++++++++++++++++++++++++++++++++
329
330The cool thing about domain sockets is that file descriptors can be exchanged
331between processes by sending them over a domain socket. This allows processes
332to hand off their I/O to other processes. Applications include load-balancing
333servers, worker processes and other ways to make optimum use of CPU. libuv only
334supports sending **TCP sockets or other pipes** over pipes for now.
335
336To demonstrate, we will look at an echo server implementation that hands off
337clients to worker processes in a round-robin fashion. This program is a bit
338involved, and while only snippets are included in the book, it is recommended
339to read the full code to really understand it.
340
341The worker process is quite simple, since the file-descriptor is handed over to
342it by the master.
343
344.. rubric:: multi-echo-server/worker.c
345.. literalinclude:: ../../code/multi-echo-server/worker.c
346    :language: c
347    :linenos:
348    :lines: 7-9,81-
349    :emphasize-lines: 6-8
350
351``queue`` is the pipe connected to the master process on the other end, along
352which new file descriptors get sent. It is important to set the ``ipc``
353argument of ``uv_pipe_init`` to 1 to indicate this pipe will be used for
354inter-process communication! Since the master will write the file handle to the
355standard input of the worker, we connect the pipe to ``stdin`` using
356``uv_pipe_open``.
357
358.. rubric:: multi-echo-server/worker.c
359.. literalinclude:: ../../code/multi-echo-server/worker.c
360    :language: c
361    :linenos:
362    :lines: 51-79
363    :emphasize-lines: 10,15,20
364
365First we call ``uv_pipe_pending_count()`` to ensure that a handle is available
366to read out. If your program could deal with different types of handles,
367``uv_pipe_pending_type()`` can be used to determine the type.
368Although ``accept`` seems odd in this code, it actually makes sense. What
369``accept`` traditionally does is get a file descriptor (the client) from
370another file descriptor (The listening socket). Which is exactly what we do
371here. Fetch the file descriptor (``client``) from ``queue``. From this point
372the worker does standard echo server stuff.
373
374Turning now to the master, let's take a look at how the workers are launched to
375allow load balancing.
376
377.. rubric:: multi-echo-server/main.c
378.. literalinclude:: ../../code/multi-echo-server/main.c
379    :language: c
380    :linenos:
381    :lines: 9-13
382
383The ``child_worker`` structure wraps the process, and the pipe between the
384master and the individual process.
385
386.. rubric:: multi-echo-server/main.c
387.. literalinclude:: ../../code/multi-echo-server/main.c
388    :language: c
389    :linenos:
390    :lines: 51,61-95
391    :emphasize-lines: 17,20-21
392
393In setting up the workers, we use the nifty libuv function ``uv_cpu_info`` to
394get the number of CPUs so we can launch an equal number of workers. Again it is
395important to initialize the pipe acting as the IPC channel with the third
396argument as 1. We then indicate that the child process' ``stdin`` is to be
397a readable pipe (from the point of view of the child). Everything is
398straightforward till here. The workers are launched and waiting for file
399descriptors to be written to their standard input.
400
401It is in ``on_new_connection`` (the TCP infrastructure is initialized in
402``main()``), that we accept the client socket and pass it along to the next
403worker in the round-robin.
404
405.. rubric:: multi-echo-server/main.c
406.. literalinclude:: ../../code/multi-echo-server/main.c
407    :language: c
408    :linenos:
409    :lines: 31-49
410    :emphasize-lines: 9,12-13
411
412The ``uv_write2`` call handles all the abstraction and it is simply a matter of
413passing in the handle (``client``) as the right argument. With this our
414multi-process echo server is operational.
415
416Thanks to Kyle for `pointing out`_ that ``uv_write2()`` requires a non-empty
417buffer even when sending handles.
418
419.. _pointing out: https://github.com/nikhilm/uvbook/issues/56
420
421----
422
423.. [#] In this section domain sockets stands in for named pipes on Windows as
424    well.
425