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