xref: /libuv/docs/src/migration_010_100.rst (revision 45c7ccce)
1
2.. _migration_010_100:
3
4libuv 0.10 -> 1.0.0 migration guide
5===================================
6
7Some APIs changed quite a bit throughout the 1.0.0 development process. Here
8is a migration guide for the most significant changes that happened after 0.10
9was released.
10
11
12Loop initialization and closing
13~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
14
15In libuv 0.10 (and previous versions), loops were created with `uv_loop_new`, which
16allocated memory for a new loop and initialized it; and destroyed with `uv_loop_delete`,
17which destroyed the loop and freed the memory. Starting with 1.0, those are deprecated
18and the user is responsible for allocating the memory and then initializing the loop.
19
20libuv 0.10
21
22::
23
24    uv_loop_t* loop = uv_loop_new();
25    ...
26    uv_loop_delete(loop);
27
28libuv 1.0
29
30::
31
32    uv_loop_t* loop = malloc(sizeof *loop);
33    uv_loop_init(loop);
34    ...
35    uv_loop_close(loop);
36    free(loop);
37
38.. note::
39    Error handling was omitted for brevity. Check the documentation for :c:func:`uv_loop_init`
40    and :c:func:`uv_loop_close`.
41
42
43Error handling
44~~~~~~~~~~~~~~
45
46Error handling had a major overhaul in libuv 1.0. In general, functions and status parameters
47would get 0 for success and -1 for failure on libuv 0.10, and the user had to use `uv_last_error`
48to fetch the error code, which was a positive number.
49
50In 1.0, functions and status parameters contain the actual error code, which is 0 for success, or
51a negative number in case of error.
52
53libuv 0.10
54
55::
56
57    ... assume 'server' is a TCP server which is already listening
58    r = uv_listen((uv_stream_t*) server, 511, NULL);
59    if (r == -1) {
60      uv_err_t err = uv_last_error(uv_default_loop());
61      /* err.code contains UV_EADDRINUSE */
62    }
63
64libuv 1.0
65
66::
67
68    ... assume 'server' is a TCP server which is already listening
69    r = uv_listen((uv_stream_t*) server, 511, NULL);
70    if (r < 0) {
71      /* r contains UV_EADDRINUSE */
72    }
73
74
75Threadpool changes
76~~~~~~~~~~~~~~~~~~
77
78In libuv 0.10 Unix used a threadpool which defaulted to 4 threads, while Windows used the
79`QueueUserWorkItem` API, which uses a Windows internal threadpool, which defaults to 512
80threads per process.
81
82In 1.0, we unified both implementations, so Windows now uses the same implementation Unix
83does. The threadpool size can be set by exporting the ``UV_THREADPOOL_SIZE`` environment
84variable. See :c:ref:`threadpool`.
85
86
87Allocation callback API change
88~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
89
90In libuv 0.10 the callback had to return a filled :c:type:`uv_buf_t` by value:
91
92::
93
94    uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) {
95        return uv_buf_init(malloc(size), size);
96    }
97
98In libuv 1.0 a pointer to a buffer is passed to the callback, which the user
99needs to fill:
100
101::
102
103    void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
104        buf->base = malloc(size);
105        buf->len = size;
106    }
107
108
109Unification of IPv4 / IPv6 APIs
110~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
111
112libuv 1.0 unified the IPv4 and IPv6 APIS. There is no longer a `uv_tcp_bind` and `uv_tcp_bind6`
113duality, there is only :c:func:`uv_tcp_bind` now.
114
115IPv4 functions took ``struct sockaddr_in`` structures by value, and IPv6 functions took
116``struct sockaddr_in6``. Now functions take a ``struct sockaddr*`` (note it's a pointer).
117It can be stack allocated.
118
119libuv 0.10
120
121::
122
123    struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", 1234);
124    ...
125    uv_tcp_bind(&server, addr)
126
127libuv 1.0
128
129::
130
131    struct sockaddr_in addr;
132    uv_ip4_addr("0.0.0.0", 1234, &addr)
133    ...
134    uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
135
136The IPv4 and IPv6 struct creating functions (:c:func:`uv_ip4_addr` and :c:func:`uv_ip6_addr`)
137have also changed, make sure you check the documentation.
138
139..note::
140    This change applies to all functions that made a distinction between IPv4 and IPv6
141    addresses.
142
143
144Streams / UDP  data receive callback API change
145~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
146
147The streams and UDP data receive callbacks now get a pointer to a :c:type:`uv_buf_t` buffer,
148not a structure by value.
149
150libuv 0.10
151
152::
153
154    void on_read(uv_stream_t* handle,
155                 ssize_t nread,
156                 uv_buf_t buf) {
157        ...
158    }
159
160    void recv_cb(uv_udp_t* handle,
161                 ssize_t nread,
162                 uv_buf_t buf,
163                 struct sockaddr* addr,
164                 unsigned flags) {
165        ...
166    }
167
168libuv 1.0
169
170::
171
172    void on_read(uv_stream_t* handle,
173                 ssize_t nread,
174                 const uv_buf_t* buf) {
175        ...
176    }
177
178    void recv_cb(uv_udp_t* handle,
179                 ssize_t nread,
180                 const uv_buf_t* buf,
181                 const struct sockaddr* addr,
182                 unsigned flags) {
183        ...
184    }
185
186
187Receiving handles over pipes API change
188~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
189
190In libuv 0.10 (and earlier versions) the `uv_read2_start` function was used to start reading
191data on a pipe, which could also result in the reception of handles over it. The callback
192for such function looked like this:
193
194::
195
196    void on_read(uv_pipe_t* pipe,
197                 ssize_t nread,
198                 uv_buf_t buf,
199                 uv_handle_type pending) {
200        ...
201    }
202
203In libuv 1.0, `uv_read2_start` was removed, and the user needs to check if there are pending
204handles using :c:func:`uv_pipe_pending_count` and :c:func:`uv_pipe_pending_type` while in
205the read callback:
206
207::
208
209    void on_read(uv_stream_t* handle,
210                 ssize_t nread,
211                 const uv_buf_t* buf) {
212        ...
213        while (uv_pipe_pending_count((uv_pipe_t*) handle) != 0) {
214            pending = uv_pipe_pending_type((uv_pipe_t*) handle);
215            ...
216        }
217        ...
218    }
219
220
221Extracting the file descriptor out of a handle
222~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
223
224While it wasn't supported by the API, users often accessed the libuv internals in
225order to get access to the file descriptor of a TCP handle, for example.
226
227::
228
229    fd = handle->io_watcher.fd;
230
231This is now properly exposed through the :c:func:`uv_fileno` function.
232
233
234uv_fs_readdir rename and API change
235~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
236
237`uv_fs_readdir` returned a list of strings in the `req->ptr` field upon completion in
238libuv 0.10. In 1.0, this function got renamed to :c:func:`uv_fs_scandir`, since it's
239actually implemented using ``scandir(3)``.
240
241In addition, instead of allocating a full list strings, the user is able to get one
242result at a time by using the :c:func:`uv_fs_scandir_next` function. This function
243does not need to make a roundtrip to the threadpool, because libuv will keep the
244list of *dents* returned by ``scandir(3)`` around.
245