Alien-uv
view release on metacpan or search on metacpan
libuv/docs/src/guide/utilities.rst view on Meta::CPAN
``uv_work_t.data`` to point to it. A slight variation is to have the
``uv_work_t`` itself as the first member of this struct (called a baton [#]_).
This allows cleaning up the work request and all the data in one free call.
.. code-block:: c
:linenos:
:emphasize-lines: 2
struct ftp_baton {
uv_work_t req;
char *host;
int port;
char *username;
char *password;
}
.. code-block:: c
:linenos:
:emphasize-lines: 2
ftp_baton *baton = (ftp_baton*) malloc(sizeof(ftp_baton));
baton->req.data = (void*) baton;
baton->host = strdup("my.webhost.com");
baton->port = 21;
// ...
uv_queue_work(loop, &baton->req, ftp_session, ftp_cleanup);
Here we create the baton and queue the task.
Now the task function can extract the data it needs:
.. code-block:: c
:linenos:
:emphasize-lines: 2, 12
void ftp_session(uv_work_t *req) {
ftp_baton *baton = (ftp_baton*) req->data;
fprintf(stderr, "Connecting to %s\n", baton->host);
}
void ftp_cleanup(uv_work_t *req) {
ftp_baton *baton = (ftp_baton*) req->data;
free(baton->host);
// ...
free(baton);
}
We then free the baton which also frees the watcher.
External I/O with polling
-------------------------
Usually third-party libraries will handle their own I/O, and keep track of
their sockets and other files internally. In this case it isn't possible to use
the standard stream I/O operations, but the library can still be integrated
into the libuv event loop. All that is required is that the library allow you
to access the underlying file descriptors and provide functions that process
tasks in small increments as decided by your application. Some libraries though
will not allow such access, providing only a standard blocking function which
will perform the entire I/O transaction and only then return. It is unwise to
use these in the event loop thread, use the :ref:`libuv-work-queue` instead. Of
course, this will also mean losing granular control on the library.
The ``uv_poll`` section of libuv simply watches file descriptors using the
operating system notification mechanism. In some sense, all the I/O operations
that libuv implements itself are also backed by ``uv_poll`` like code. Whenever
the OS notices a change of state in file descriptors being polled, libuv will
invoke the associated callback.
Here we will walk through a simple download manager that will use libcurl_ to
download files. Rather than give all control to libcurl, we'll instead be
using the libuv event loop, and use the non-blocking, async multi_ interface to
progress with the download whenever libuv notifies of I/O readiness.
.. _libcurl: http://curl.haxx.se/libcurl/
.. _multi: http://curl.haxx.se/libcurl/c/libcurl-multi.html
.. rubric:: uvwget/main.c - The setup
.. literalinclude:: ../../code/uvwget/main.c
:linenos:
:lines: 1-9,140-
:emphasize-lines: 7,21,24-25
The way each library is integrated with libuv will vary. In the case of
libcurl, we can register two callbacks. The socket callback ``handle_socket``
is invoked whenever the state of a socket changes and we have to start polling
it. ``start_timeout`` is called by libcurl to notify us of the next timeout
interval, after which we should drive libcurl forward regardless of I/O status.
This is so that libcurl can handle errors or do whatever else is required to
get the download moving.
Our downloader is to be invoked as::
$ ./uvwget [url1] [url2] ...
So we add each argument as an URL
.. rubric:: uvwget/main.c - Adding urls
.. literalinclude:: ../../code/uvwget/main.c
:linenos:
:lines: 39-56
:emphasize-lines: 13-14
We let libcurl directly write the data to a file, but much more is possible if
you so desire.
``start_timeout`` will be called immediately the first time by libcurl, so
things are set in motion. This simply starts a libuv `timer <Timers>`_ which
drives ``curl_multi_socket_action`` with ``CURL_SOCKET_TIMEOUT`` whenever it
times out. ``curl_multi_socket_action`` is what drives libcurl, and what we
call whenever sockets change state. But before we go into that, we need to poll
on sockets whenever ``handle_socket`` is called.
.. rubric:: uvwget/main.c - Setting up polling
.. literalinclude:: ../../code/uvwget/main.c
:linenos:
:lines: 102-140
:emphasize-lines: 9,11,15,21,24
( run in 0.508 second using v1.01-cache-2.11-cpan-13bb782fe5a )