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