xref: /netbsd-src/external/mit/libuv/dist/docs/src/guide/processes.rst (revision 5f2f42719cd62ff11fd913b40b7ce19f07c4fd25)
10e552da7SchristosProcesses
20e552da7Schristos=========
30e552da7Schristos
40e552da7Schristoslibuv offers considerable child process management, abstracting the platform
50e552da7Schristosdifferences and allowing communication with the child process using streams or
60e552da7Schristosnamed pipes.
70e552da7Schristos
80e552da7SchristosA common idiom in Unix is for every process to do one thing and do it well. In
90e552da7Schristossuch a case, a process often uses multiple child processes to achieve tasks
100e552da7Schristos(similar to using pipes in shells). A multi-process model with messages
110e552da7Schristosmay also be easier to reason about compared to one with threads and shared
120e552da7Schristosmemory.
130e552da7Schristos
140e552da7SchristosA common refrain against event-based programs is that they cannot take
150e552da7Schristosadvantage of multiple cores in modern computers. In a multi-threaded program
160e552da7Schristosthe kernel can perform scheduling and assign different threads to different
170e552da7Schristoscores, improving performance. But an event loop has only one thread.  The
180e552da7Schristosworkaround can be to launch multiple processes instead, with each process
190e552da7Schristosrunning an event loop, and each process getting assigned to a separate CPU
200e552da7Schristoscore.
210e552da7Schristos
220e552da7SchristosSpawning child processes
230e552da7Schristos------------------------
240e552da7Schristos
250e552da7SchristosThe simplest case is when you simply want to launch a process and know when it
260e552da7Schristosexits. This is achieved using ``uv_spawn``.
270e552da7Schristos
280e552da7Schristos.. rubric:: spawn/main.c
290e552da7Schristos.. literalinclude:: ../../code/spawn/main.c
30*5f2f4271Schristos    :language: c
310e552da7Schristos    :linenos:
320e552da7Schristos    :lines: 6-8,15-
330e552da7Schristos    :emphasize-lines: 11,13-17
340e552da7Schristos
350e552da7Schristos.. NOTE::
360e552da7Schristos
370e552da7Schristos    ``options`` is implicitly initialized with zeros since it is a global
380e552da7Schristos    variable.  If you change ``options`` to a local variable, remember to
390e552da7Schristos    initialize it to null out all unused fields::
400e552da7Schristos
410e552da7Schristos        uv_process_options_t options = {0};
420e552da7Schristos
430e552da7SchristosThe ``uv_process_t`` struct only acts as the handle, all options are set via
440e552da7Schristos``uv_process_options_t``. To simply launch a process, you need to set only the
450e552da7Schristos``file`` and ``args`` fields. ``file`` is the program to execute. Since
460e552da7Schristos``uv_spawn`` uses :man:`execvp(3)` internally, there is no need to supply the full
470e552da7Schristospath. Finally as per underlying conventions, **the arguments array has to be
480e552da7Schristosone larger than the number of arguments, with the last element being NULL**.
490e552da7Schristos
500e552da7SchristosAfter the call to ``uv_spawn``, ``uv_process_t.pid`` will contain the process
510e552da7SchristosID of the child process.
520e552da7Schristos
530e552da7SchristosThe exit callback will be invoked with the *exit status* and the type of *signal*
540e552da7Schristoswhich caused the exit.
550e552da7Schristos
560e552da7Schristos.. rubric:: spawn/main.c
570e552da7Schristos.. literalinclude:: ../../code/spawn/main.c
58*5f2f4271Schristos    :language: c
590e552da7Schristos    :linenos:
600e552da7Schristos    :lines: 9-12
610e552da7Schristos    :emphasize-lines: 3
620e552da7Schristos
630e552da7SchristosIt is **required** to close the process watcher after the process exits.
640e552da7Schristos
650e552da7SchristosChanging process parameters
660e552da7Schristos---------------------------
670e552da7Schristos
680e552da7SchristosBefore the child process is launched you can control the execution environment
690e552da7Schristosusing fields in ``uv_process_options_t``.
700e552da7Schristos
710e552da7SchristosChange execution directory
720e552da7Schristos++++++++++++++++++++++++++
730e552da7Schristos
740e552da7SchristosSet ``uv_process_options_t.cwd`` to the corresponding directory.
750e552da7Schristos
760e552da7SchristosSet environment variables
770e552da7Schristos+++++++++++++++++++++++++
780e552da7Schristos
790e552da7Schristos``uv_process_options_t.env`` is a null-terminated array of strings, each of the
800e552da7Schristosform ``VAR=VALUE`` used to set up the environment variables for the process. Set
810e552da7Schristosthis to ``NULL`` to inherit the environment from the parent (this) process.
820e552da7Schristos
830e552da7SchristosOption flags
840e552da7Schristos++++++++++++
850e552da7Schristos
860e552da7SchristosSetting ``uv_process_options_t.flags`` to a bitwise OR of the following flags,
870e552da7Schristosmodifies the child process behaviour:
880e552da7Schristos
890e552da7Schristos* ``UV_PROCESS_SETUID`` - sets the child's execution user ID to ``uv_process_options_t.uid``.
900e552da7Schristos* ``UV_PROCESS_SETGID`` - sets the child's execution group ID to ``uv_process_options_t.gid``.
910e552da7Schristos
920e552da7SchristosChanging the UID/GID is only supported on Unix, ``uv_spawn`` will fail on
930e552da7SchristosWindows with ``UV_ENOTSUP``.
940e552da7Schristos
950e552da7Schristos* ``UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS`` - No quoting or escaping of
960e552da7Schristos  ``uv_process_options_t.args`` is done on Windows. Ignored on Unix.
970e552da7Schristos* ``UV_PROCESS_DETACHED`` - Starts the child process in a new session, which
980e552da7Schristos  will keep running after the parent process exits. See example below.
990e552da7Schristos
1000e552da7SchristosDetaching processes
1010e552da7Schristos-------------------
1020e552da7Schristos
1030e552da7SchristosPassing the flag ``UV_PROCESS_DETACHED`` can be used to launch daemons, or
1040e552da7Schristoschild processes which are independent of the parent so that the parent exiting
1050e552da7Schristosdoes not affect it.
1060e552da7Schristos
1070e552da7Schristos.. rubric:: detach/main.c
1080e552da7Schristos.. literalinclude:: ../../code/detach/main.c
109*5f2f4271Schristos    :language: c
1100e552da7Schristos    :linenos:
1110e552da7Schristos    :lines: 9-30
1120e552da7Schristos    :emphasize-lines: 12,19
1130e552da7Schristos
1140e552da7SchristosJust remember that the handle is still monitoring the child, so your program
1150e552da7Schristoswon't exit. Use ``uv_unref()`` if you want to be more *fire-and-forget*.
1160e552da7Schristos
1170e552da7SchristosSending signals to processes
1180e552da7Schristos----------------------------
1190e552da7Schristos
1200e552da7Schristoslibuv wraps the standard ``kill(2)`` system call on Unix and implements one
1210e552da7Schristoswith similar semantics on Windows, with *one caveat*: all of ``SIGTERM``,
1220e552da7Schristos``SIGINT`` and ``SIGKILL``, lead to termination of the process. The signature
1230e552da7Schristosof ``uv_kill`` is::
1240e552da7Schristos
1250e552da7Schristos    uv_err_t uv_kill(int pid, int signum);
1260e552da7Schristos
1270e552da7SchristosFor processes started using libuv, you may use ``uv_process_kill`` instead,
1280e552da7Schristoswhich accepts the ``uv_process_t`` watcher as the first argument, rather than
1290e552da7Schristosthe pid. In this case, **remember to call** ``uv_close`` on the watcher.
1300e552da7Schristos
1310e552da7SchristosSignals
1320e552da7Schristos-------
1330e552da7Schristos
1340e552da7Schristoslibuv provides wrappers around Unix signals with `some Windows support
1350e552da7Schristos<http://docs.libuv.org/en/v1.x/signal.html#signal>`_ as well.
1360e552da7Schristos
1370e552da7SchristosUse ``uv_signal_init()`` to initialize
1380e552da7Schristosa handle and associate it with a loop. To listen for particular signals on
1390e552da7Schristosthat handler, use ``uv_signal_start()`` with the handler function. Each handler
1400e552da7Schristoscan only be associated with one signal number, with subsequent calls to
1410e552da7Schristos``uv_signal_start()`` overwriting earlier associations. Use ``uv_signal_stop()`` to
1420e552da7Schristosstop watching. Here is a small example demonstrating the various possibilities:
1430e552da7Schristos
1440e552da7Schristos.. rubric:: signal/main.c
1450e552da7Schristos.. literalinclude:: ../../code/signal/main.c
146*5f2f4271Schristos    :language: c
1470e552da7Schristos    :linenos:
1480e552da7Schristos    :emphasize-lines: 17-18,27-28
1490e552da7Schristos
1500e552da7Schristos.. NOTE::
1510e552da7Schristos
1520e552da7Schristos    ``uv_run(loop, UV_RUN_NOWAIT)`` is similar to ``uv_run(loop, UV_RUN_ONCE)``
1530e552da7Schristos    in that it will process only one event. UV_RUN_ONCE blocks if there are no
1540e552da7Schristos    pending events, while UV_RUN_NOWAIT will return immediately. We use NOWAIT
1550e552da7Schristos    so that one of the loops isn't starved because the other one has no pending
1560e552da7Schristos    activity.
1570e552da7Schristos
1580e552da7SchristosSend ``SIGUSR1`` to the process, and you'll find the handler being invoked
1590e552da7Schristos4 times, one for each ``uv_signal_t``. The handler just stops each handle,
1600e552da7Schristosso that the program exits. This sort of dispatch to all handlers is very
1610e552da7Schristosuseful. A server using multiple event loops could ensure that all data was
1620e552da7Schristossafely saved before termination, simply by every loop adding a watcher for
1630e552da7Schristos``SIGINT``.
1640e552da7Schristos
1650e552da7SchristosChild Process I/O
1660e552da7Schristos-----------------
1670e552da7Schristos
1680e552da7SchristosA normal, newly spawned process has its own set of file descriptors, with 0,
1690e552da7Schristos1 and 2 being ``stdin``, ``stdout`` and ``stderr`` respectively. Sometimes you
1700e552da7Schristosmay want to share file descriptors with the child. For example, perhaps your
1710e552da7Schristosapplications launches a sub-command and you want any errors to go in the log
1720e552da7Schristosfile, but ignore ``stdout``. For this you'd like to have ``stderr`` of the
1730e552da7Schristoschild be the same as the stderr of the parent. In this case, libuv supports
1740e552da7Schristos*inheriting* file descriptors. In this sample, we invoke the test program,
1750e552da7Schristoswhich is:
1760e552da7Schristos
1770e552da7Schristos.. rubric:: proc-streams/test.c
1780e552da7Schristos.. literalinclude:: ../../code/proc-streams/test.c
179*5f2f4271Schristos    :language: c
1800e552da7Schristos
1810e552da7SchristosThe actual program ``proc-streams`` runs this while sharing only ``stderr``.
1820e552da7SchristosThe file descriptors of the child process are set using the ``stdio`` field in
1830e552da7Schristos``uv_process_options_t``. First set the ``stdio_count`` field to the number of
1840e552da7Schristosfile descriptors being set. ``uv_process_options_t.stdio`` is an array of
1850e552da7Schristos``uv_stdio_container_t``, which is:
1860e552da7Schristos
1870e552da7Schristos.. code-block:: c
1880e552da7Schristos
1890e552da7Schristos    typedef struct uv_stdio_container_s {
1900e552da7Schristos        uv_stdio_flags flags;
1910e552da7Schristos
1920e552da7Schristos        union {
1930e552da7Schristos            uv_stream_t* stream;
1940e552da7Schristos            int fd;
1950e552da7Schristos        } data;
1960e552da7Schristos    } uv_stdio_container_t;
1970e552da7Schristos
1980e552da7Schristoswhere flags can have several values. Use ``UV_IGNORE`` if it isn't going to be
1990e552da7Schristosused. If the first three ``stdio`` fields are marked as ``UV_IGNORE`` they'll
2000e552da7Schristosredirect to ``/dev/null``.
2010e552da7Schristos
2020e552da7SchristosSince we want to pass on an existing descriptor, we'll use ``UV_INHERIT_FD``.
2030e552da7SchristosThen we set the ``fd`` to ``stderr``.
2040e552da7Schristos
2050e552da7Schristos.. rubric:: proc-streams/main.c
2060e552da7Schristos.. literalinclude:: ../../code/proc-streams/main.c
207*5f2f4271Schristos    :language: c
2080e552da7Schristos    :linenos:
2090e552da7Schristos    :lines: 15-17,27-
2100e552da7Schristos    :emphasize-lines: 6,10,11,12
2110e552da7Schristos
2120e552da7SchristosIf you run ``proc-stream`` you'll see that only the line "This is stderr" will
2130e552da7Schristosbe displayed. Try marking ``stdout`` as being inherited and see the output.
2140e552da7Schristos
2150e552da7SchristosIt is dead simple to apply this redirection to streams.  By setting ``flags``
2160e552da7Schristosto ``UV_INHERIT_STREAM`` and setting ``data.stream`` to the stream in the
2170e552da7Schristosparent process, the child process can treat that stream as standard I/O. This
2180e552da7Schristoscan be used to implement something like CGI_.
2190e552da7Schristos
2200e552da7Schristos.. _CGI: https://en.wikipedia.org/wiki/Common_Gateway_Interface
2210e552da7Schristos
2220e552da7SchristosA sample CGI script/executable is:
2230e552da7Schristos
2240e552da7Schristos.. rubric:: cgi/tick.c
2250e552da7Schristos.. literalinclude:: ../../code/cgi/tick.c
226*5f2f4271Schristos    :language: c
2270e552da7Schristos
2280e552da7SchristosThe CGI server combines the concepts from this chapter and :doc:`networking` so
2290e552da7Schristosthat every client is sent ten ticks after which that connection is closed.
2300e552da7Schristos
2310e552da7Schristos.. rubric:: cgi/main.c
2320e552da7Schristos.. literalinclude:: ../../code/cgi/main.c
233*5f2f4271Schristos    :language: c
2340e552da7Schristos    :linenos:
2350e552da7Schristos    :lines: 49-63
2360e552da7Schristos    :emphasize-lines: 10
2370e552da7Schristos
2380e552da7SchristosHere we simply accept the TCP connection and pass on the socket (*stream*) to
2390e552da7Schristos``invoke_cgi_script``.
2400e552da7Schristos
2410e552da7Schristos.. rubric:: cgi/main.c
2420e552da7Schristos.. literalinclude:: ../../code/cgi/main.c
243*5f2f4271Schristos    :language: c
2440e552da7Schristos    :linenos:
2450e552da7Schristos    :lines: 16, 25-45
2460e552da7Schristos    :emphasize-lines: 8-9,18,20
2470e552da7Schristos
2480e552da7SchristosThe ``stdout`` of the CGI script is set to the socket so that whatever our tick
2490e552da7Schristosscript prints, gets sent to the client. By using processes, we can offload the
2500e552da7Schristosread/write buffering to the operating system, so in terms of convenience this
2510e552da7Schristosis great. Just be warned that creating processes is a costly task.
2520e552da7Schristos
2530e552da7Schristos.. _pipes:
2540e552da7Schristos
2550e552da7SchristosParent-child IPC
2560e552da7Schristos----------------
2570e552da7Schristos
2580e552da7SchristosA parent and child can have one or two way communication over a pipe created by
2590e552da7Schristossettings ``uv_stdio_container_t.flags`` to a bit-wise combination of
2600e552da7Schristos``UV_CREATE_PIPE`` and ``UV_READABLE_PIPE`` or ``UV_WRITABLE_PIPE``. The
2610e552da7Schristosread/write flag is from the perspective of the child process.  In this case,
2620e552da7Schristosthe ``uv_stream_t* stream`` field must be set to point to an initialized,
2630e552da7Schristosunopened ``uv_pipe_t`` instance.
2640e552da7Schristos
2650e552da7SchristosNew stdio Pipes
2660e552da7Schristos+++++++++++++++
2670e552da7Schristos
2680e552da7SchristosThe ``uv_pipe_t`` structure represents more than just `pipe(7)`_ (or ``|``),
2690e552da7Schristosbut supports any streaming file-like objects. On Windows, the only object of
2700e552da7Schristosthat description is the `Named Pipe`_.  On Unix, this could be any of `Unix
2710e552da7SchristosDomain Socket`_, or derived from `mkfifo(1)`_, or it could actually be a
2720e552da7Schristos`pipe(7)`_.  When ``uv_spawn`` initializes a ``uv_pipe_t`` due to the
2730e552da7Schristos`UV_CREATE_PIPE` flag, it opts for creating a `socketpair(2)`_.
2740e552da7Schristos
2750e552da7SchristosThis is intended for the purpose of allowing multiple libuv processes to
2760e552da7Schristoscommunicate with IPC. This is discussed below.
2770e552da7Schristos
278*5f2f4271Schristos.. _pipe(7): https://man7.org/linux/man-pages/man7/pipe.7.html
279*5f2f4271Schristos.. _mkfifo(1): https://man7.org/linux/man-pages/man1/mkfifo.1.html
280*5f2f4271Schristos.. _socketpair(2): https://man7.org/linux/man-pages/man2/socketpair.2.html
281*5f2f4271Schristos.. _Unix Domain Socket: https://man7.org/linux/man-pages/man7/unix.7.html
2820e552da7Schristos.. _Named Pipe: https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipes
2830e552da7Schristos
2840e552da7Schristos
2850e552da7SchristosArbitrary process IPC
2860e552da7Schristos+++++++++++++++++++++
2870e552da7Schristos
2880e552da7SchristosSince domain sockets [#]_ can have a well known name and a location in the
2890e552da7Schristosfile-system they can be used for IPC between unrelated processes. The D-BUS_
2900e552da7Schristossystem used by open source desktop environments uses domain sockets for event
2910e552da7Schristosnotification. Various applications can then react when a contact comes online
2920e552da7Schristosor new hardware is detected. The MySQL server also runs a domain socket on
2930e552da7Schristoswhich clients can interact with it.
2940e552da7Schristos
2950e552da7Schristos.. _D-BUS: https://www.freedesktop.org/wiki/Software/dbus
2960e552da7Schristos
2970e552da7SchristosWhen using domain sockets, a client-server pattern is usually followed with the
2980e552da7Schristoscreator/owner of the socket acting as the server. After the initial setup,
2990e552da7Schristosmessaging is no different from TCP, so we'll re-use the echo server example.
3000e552da7Schristos
3010e552da7Schristos.. rubric:: pipe-echo-server/main.c
3020e552da7Schristos.. literalinclude:: ../../code/pipe-echo-server/main.c
303*5f2f4271Schristos    :language: c
3040e552da7Schristos    :linenos:
3050e552da7Schristos    :lines: 70-
3060e552da7Schristos    :emphasize-lines: 5,10,14
3070e552da7Schristos
3080e552da7SchristosWe name the socket ``echo.sock`` which means it will be created in the local
3090e552da7Schristosdirectory. This socket now behaves no different from TCP sockets as far as
3100e552da7Schristosthe stream API is concerned. You can test this server using `socat`_::
3110e552da7Schristos
3120e552da7Schristos    $ socat - /path/to/socket
3130e552da7Schristos
3140e552da7SchristosA client which wants to connect to a domain socket will use::
3150e552da7Schristos
3160e552da7Schristos    void uv_pipe_connect(uv_connect_t *req, uv_pipe_t *handle, const char *name, uv_connect_cb cb);
3170e552da7Schristos
3180e552da7Schristoswhere ``name`` will be ``echo.sock`` or similar. On Unix systems, ``name`` must
3190e552da7Schristospoint to a valid file (e.g. ``/tmp/echo.sock``). On Windows, ``name`` follows a
3200e552da7Schristos``\\?\pipe\echo.sock`` format.
3210e552da7Schristos
3220e552da7Schristos.. _socat: http://www.dest-unreach.org/socat/
3230e552da7Schristos
3240e552da7SchristosSending file descriptors over pipes
3250e552da7Schristos+++++++++++++++++++++++++++++++++++
3260e552da7Schristos
3270e552da7SchristosThe cool thing about domain sockets is that file descriptors can be exchanged
3280e552da7Schristosbetween processes by sending them over a domain socket. This allows processes
3290e552da7Schristosto hand off their I/O to other processes. Applications include load-balancing
3300e552da7Schristosservers, worker processes and other ways to make optimum use of CPU. libuv only
3310e552da7Schristossupports sending **TCP sockets or other pipes** over pipes for now.
3320e552da7Schristos
3330e552da7SchristosTo demonstrate, we will look at a echo server implementation that hands of
3340e552da7Schristosclients to worker processes in a round-robin fashion. This program is a bit
3350e552da7Schristosinvolved, and while only snippets are included in the book, it is recommended
3360e552da7Schristosto read the full code to really understand it.
3370e552da7Schristos
3380e552da7SchristosThe worker process is quite simple, since the file-descriptor is handed over to
3390e552da7Schristosit by the master.
3400e552da7Schristos
3410e552da7Schristos.. rubric:: multi-echo-server/worker.c
3420e552da7Schristos.. literalinclude:: ../../code/multi-echo-server/worker.c
343*5f2f4271Schristos    :language: c
3440e552da7Schristos    :linenos:
3450e552da7Schristos    :lines: 7-9,81-
3460e552da7Schristos    :emphasize-lines: 6-8
3470e552da7Schristos
3480e552da7Schristos``queue`` is the pipe connected to the master process on the other end, along
3490e552da7Schristoswhich new file descriptors get sent. It is important to set the ``ipc``
3500e552da7Schristosargument of ``uv_pipe_init`` to 1 to indicate this pipe will be used for
3510e552da7Schristosinter-process communication! Since the master will write the file handle to the
3520e552da7Schristosstandard input of the worker, we connect the pipe to ``stdin`` using
3530e552da7Schristos``uv_pipe_open``.
3540e552da7Schristos
3550e552da7Schristos.. rubric:: multi-echo-server/worker.c
3560e552da7Schristos.. literalinclude:: ../../code/multi-echo-server/worker.c
357*5f2f4271Schristos    :language: c
3580e552da7Schristos    :linenos:
3590e552da7Schristos    :lines: 51-79
3600e552da7Schristos    :emphasize-lines: 10,15,20
3610e552da7Schristos
3620e552da7SchristosFirst we call ``uv_pipe_pending_count()`` to ensure that a handle is available
3630e552da7Schristosto read out. If your program could deal with different types of handles,
3640e552da7Schristos``uv_pipe_pending_type()`` can be used to determine the type.
3650e552da7SchristosAlthough ``accept`` seems odd in this code, it actually makes sense. What
3660e552da7Schristos``accept`` traditionally does is get a file descriptor (the client) from
3670e552da7Schristosanother file descriptor (The listening socket). Which is exactly what we do
3680e552da7Schristoshere. Fetch the file descriptor (``client``) from ``queue``. From this point
3690e552da7Schristosthe worker does standard echo server stuff.
3700e552da7Schristos
3710e552da7SchristosTurning now to the master, let's take a look at how the workers are launched to
3720e552da7Schristosallow load balancing.
3730e552da7Schristos
3740e552da7Schristos.. rubric:: multi-echo-server/main.c
3750e552da7Schristos.. literalinclude:: ../../code/multi-echo-server/main.c
376*5f2f4271Schristos    :language: c
3770e552da7Schristos    :linenos:
3780e552da7Schristos    :lines: 9-13
3790e552da7Schristos
3800e552da7SchristosThe ``child_worker`` structure wraps the process, and the pipe between the
3810e552da7Schristosmaster and the individual process.
3820e552da7Schristos
3830e552da7Schristos.. rubric:: multi-echo-server/main.c
3840e552da7Schristos.. literalinclude:: ../../code/multi-echo-server/main.c
385*5f2f4271Schristos    :language: c
3860e552da7Schristos    :linenos:
3870e552da7Schristos    :lines: 51,61-95
3880e552da7Schristos    :emphasize-lines: 17,20-21
3890e552da7Schristos
3900e552da7SchristosIn setting up the workers, we use the nifty libuv function ``uv_cpu_info`` to
3910e552da7Schristosget the number of CPUs so we can launch an equal number of workers. Again it is
3920e552da7Schristosimportant to initialize the pipe acting as the IPC channel with the third
3930e552da7Schristosargument as 1. We then indicate that the child process' ``stdin`` is to be
3940e552da7Schristosa readable pipe (from the point of view of the child). Everything is
3950e552da7Schristosstraightforward till here. The workers are launched and waiting for file
3960e552da7Schristosdescriptors to be written to their standard input.
3970e552da7Schristos
3980e552da7SchristosIt is in ``on_new_connection`` (the TCP infrastructure is initialized in
3990e552da7Schristos``main()``), that we accept the client socket and pass it along to the next
4000e552da7Schristosworker in the round-robin.
4010e552da7Schristos
4020e552da7Schristos.. rubric:: multi-echo-server/main.c
4030e552da7Schristos.. literalinclude:: ../../code/multi-echo-server/main.c
404*5f2f4271Schristos    :language: c
4050e552da7Schristos    :linenos:
4060e552da7Schristos    :lines: 31-49
4070e552da7Schristos    :emphasize-lines: 9,12-13
4080e552da7Schristos
4090e552da7SchristosThe ``uv_write2`` call handles all the abstraction and it is simply a matter of
4100e552da7Schristospassing in the handle (``client``) as the right argument. With this our
4110e552da7Schristosmulti-process echo server is operational.
4120e552da7Schristos
4130e552da7SchristosThanks to Kyle for `pointing out`_ that ``uv_write2()`` requires a non-empty
4140e552da7Schristosbuffer even when sending handles.
4150e552da7Schristos
4160e552da7Schristos.. _pointing out: https://github.com/nikhilm/uvbook/issues/56
4170e552da7Schristos
4180e552da7Schristos----
4190e552da7Schristos
4200e552da7Schristos.. [#] In this section domain sockets stands in for named pipes on Windows as
4210e552da7Schristos    well.
422