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