Merge tag 'upstream/1.8.0' into debian/sid
Upstream version 1.8.0
Luca Bruno
8 years ago
21 | 21 | Marc Schlaich <marc.schlaich@googlemail.com> <marc.schlaich@gmail.com> |
22 | 22 | Michael <michael_dawson@ca.ibm.com> |
23 | 23 | Michael Neumann <mneumann@think.localnet> <mneumann@ntecs.de> |
24 | Nicholas Vavilov <vvnicholas@gmail.com> | |
24 | 25 | Rasmus Christian Pedersen <zerhacken@yahoo.com> |
25 | 26 | Rasmus Christian Pedersen <zerhacken@yahoo.com> <ruysch@outlook.com> |
26 | 27 | Robert Mustacchi <rm@joyent.com> <rm@fingolfin.org> |
224 | 224 | Sakthipriyan Vairamani <thechargingvolcano@gmail.com> |
225 | 225 | Eli Skeggs <skeggse@gmail.com> |
226 | 226 | nmushell <nmushell@bloomberg.net> |
227 | Gireesh Punathil <gpunathi@in.ibm.com> | |
228 | Ryan Johnston <ryan@mediapixel.co.nz> | |
229 | Adam Stylinski <stylinae@mail.uc.edu> | |
230 | Nathan Corvino <nathan@corvino.com> | |
231 | Wink Saville <wink@saville.com> | |
232 | Angel Leon <gubatron@gmail.com> | |
233 | Louis DeJardin <lodejard@microsoft.com> | |
234 | Imran Iqbal <imrani@ca.ibm.com> | |
235 | Petka Antonov <petka_antonov@hotmail.com> | |
236 | Ian Kronquist <iankronquist@teleport.com> | |
237 | kkdaemon <kkdaemon@gmail.com> | |
238 | Yuval Brik <yuval@brik.org.il> | |
239 | Joran Dirk Greef <joran@ronomon.com> | |
240 | Andrey Mazo <andrey.mazo@fidelissecurity.com> | |
241 | sztomi <hello.sztomi@gmail.com> |
0 | 2015.09.23, Version 1.7.5 (Stable) | |
0 | 2015.12.15, Version 1.8.0 (Stable) | |
1 | ||
2 | Changes since version 1.7.5: | |
3 | ||
4 | * unix: fix memory leak in uv_interface_addresses (Jianghua Yang) | |
5 | ||
6 | * unix: make uv_guess_handle work properly for AIX (Gireesh Punathil) | |
7 | ||
8 | * fs: undo uv__req_init when uv__malloc failed (Jianghua Yang) | |
9 | ||
10 | * build: remove unused 'component' GYP option (Saúl Ibarra Corretgé) | |
11 | ||
12 | * include: remove duplicate extern declaration (Jianghua Yang) | |
13 | ||
14 | * win: use the MSVC provided snprintf where possible (Jason Williams) | |
15 | ||
16 | * win, test: fix compilation warning (Saúl Ibarra Corretgé) | |
17 | ||
18 | * win: fix compilation with VS < 2012 (Ryan Johnston) | |
19 | ||
20 | * stream: support empty uv_try_write on unix (Fedor Indutny) | |
21 | ||
22 | * unix: fix request handle leak in uv__udp_send (Jianghua Yang) | |
23 | ||
24 | * src: replace QUEUE_SPLIT with QUEUE_MOVE (Ben Noordhuis) | |
25 | ||
26 | * unix: use QUEUE_MOVE when iterating over lists (Ben Noordhuis) | |
27 | ||
28 | * unix: squelch harmless valgrind warning (Ben Noordhuis) | |
29 | ||
30 | * test: don't abort on setrlimit() failure (Ben Noordhuis) | |
31 | ||
32 | * unix: only undo fs req registration in async mode (Ben Noordhuis) | |
33 | ||
34 | * unix: fix uv__getiovmax return value (HungMingWu) | |
35 | ||
36 | * unix: make work with Solaris Studio. (Adam Stylinski) | |
37 | ||
38 | * test: fix fs_event_watch_file_currentdir flakiness (Santiago Gimeno) | |
39 | ||
40 | * unix: skip prohibited syscalls on tvOS and watchOS (Nathan Corvino) | |
41 | ||
42 | * test: use FQDN in getaddrinfo_fail test (Wink Saville) | |
43 | ||
44 | * docs: clarify documentation of uv_tcp_init_ex (Andrius Bentkus) | |
45 | ||
46 | * win: fix comment (Miodrag Milanovic) | |
47 | ||
48 | * doc: fix typo in README (Angel Leon) | |
49 | ||
50 | * darwin: abort() if (un)locking fs mutex fails (Ben Noordhuis) | |
51 | ||
52 | * pipe: enable inprocess uv_write2 on Windows (Louis DeJardin) | |
53 | ||
54 | * win: properly return UV_EBADF when _close() fails (Nicholas Vavilov) | |
55 | ||
56 | * test: skip process_title for AIX (Imran Iqbal) | |
57 | ||
58 | * misc: expose handle print APIs (Petka Antonov) | |
59 | ||
60 | * include: add stdio.h to uv.h (Saúl Ibarra Corretgé) | |
61 | ||
62 | * misc: remove unnecessary null pointer checks (Ian Kronquist) | |
63 | ||
64 | * test,freebsd: skip udp_dual_stack if not supported (Santiago Gimeno) | |
65 | ||
66 | * linux: don't retry dup2/dup3 on EINTR (Ben Noordhuis) | |
67 | ||
68 | * unix: don't retry dup2/dup3 on EINTR (Ben Noordhuis) | |
69 | ||
70 | * test: fix -Wtautological-pointer-compare warnings (Saúl Ibarra Corretgé) | |
71 | ||
72 | * win: map ERROR_BAD_PATHNAME to UV_ENOENT (Tony Kelman) | |
73 | ||
74 | * test: fix test/test-tty.c for AIX (Imran Iqbal) | |
75 | ||
76 | * android: support api level less than 21 (kkdaemon) | |
77 | ||
78 | * fsevents: fix race on simultaneous init+close (Fedor Indutny) | |
79 | ||
80 | * linux,fs: fix p{read,write}v with a 64bit offset (Saúl Ibarra Corretgé) | |
81 | ||
82 | * fs: add uv_fs_realpath() (Yuval Brik) | |
83 | ||
84 | * win: fix path for removed and renamed fs events (Joran Dirk Greef) | |
85 | ||
86 | * win: do not read more from stream than available (Jeremy Whitlock) | |
87 | ||
88 | * test: test that uv_close() doesn't corrupt QUEUE (Andrey Mazo) | |
89 | ||
90 | * unix: fix uv_fs_event_stop() from fs_event_cb (Andrey Mazo) | |
91 | ||
92 | * test: fix self-deadlocks in thread_rwlock_trylock (Ben Noordhuis) | |
93 | ||
94 | * src: remove non ascii character (sztomi) | |
95 | ||
96 | * test: fix test udp_multicast_join6 for AIX (Imran Iqbal) | |
97 | ||
98 | ||
99 | 2015.09.23, Version 1.7.5 (Stable), a8c1136de2cabf25b143021488cbaab05834daa8 | |
1 | 100 | |
2 | 101 | Changes since version 1.7.4: |
3 | 102 |
199 | 199 | test/test-poll-closesocket.c \ |
200 | 200 | test/test-poll.c \ |
201 | 201 | test/test-process-title.c \ |
202 | test/test-queue-foreach-delete.c \ | |
202 | 203 | test/test-ref.c \ |
203 | 204 | test/test-run-nowait.c \ |
204 | 205 | test/test-run-once.c \ |
118 | 118 | $ git verify-tag v1.6.1 |
119 | 119 | |
120 | 120 | Starting with libuv 1.7.0, the tarballs stored in the |
121 | [downloads site](http://dist.libuv.org/dist/) are signed and an accomanying | |
121 | [downloads site](http://dist.libuv.org/dist/) are signed and an accompanying | |
122 | 122 | signature file sit alongside each. Once both the release tarball and the |
123 | 123 | signature file are downloaded, the file can be verified as follows: |
124 | 124 |
3 | 3 | 'target_arch%': 'ia32', # set v8's target architecture |
4 | 4 | 'host_arch%': 'ia32', # set v8's host architecture |
5 | 5 | 'uv_library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds |
6 | 'component%': 'static_library', # NB. these names match with what V8 expects | |
7 | 6 | 'msvs_multi_core_compile': '0', # we do enable multicore compiles, but not using the V8 way |
8 | 7 | }, |
9 | 8 |
12 | 12 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
13 | 13 | |
14 | 14 | AC_PREREQ(2.57) |
15 | AC_INIT([libuv], [1.7.5], [https://github.com/libuv/libuv/issues]) | |
15 | AC_INIT([libuv], [1.8.0], [https://github.com/libuv/libuv/issues]) | |
16 | 16 | AC_CONFIG_MACRO_DIR([m4]) |
17 | 17 | m4_include([m4/libuv-extra-automake-flags.m4]) |
18 | 18 | m4_include([m4/as_case.m4]) |
278 | 278 | |
279 | 279 | Equivalent to :man:`readlink(2)`. |
280 | 280 | |
281 | .. c:function:: int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) | |
282 | ||
283 | Equivalent to :man:`realpath(3)` on Unix. Windows uses ``GetFinalPathNameByHandle()``. | |
284 | ||
285 | .. note:: | |
286 | This function is not implemented on Windows XP and Windows Server 2003. | |
287 | On these systems, UV_ENOSYS is returned. | |
288 | ||
289 | .. versionadded:: 1.8.0 | |
290 | ||
281 | 291 | .. c:function:: int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) |
282 | 292 | .. c:function:: int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) |
283 | 293 |
287 | 287 | .. note:: |
288 | 288 | Not every platform can support nanosecond resolution; however, this value will always |
289 | 289 | be in nanoseconds. |
290 | ||
291 | .. c:function:: void uv_print_all_handles(uv_loop_t* loop, FILE* stream) | |
292 | ||
293 | Prints all handles associated with the given `loop` to the given `stream`. | |
294 | ||
295 | Example: | |
296 | ||
297 | :: | |
298 | ||
299 | uv_print_all_handles(uv_default_loop(), stderr); | |
300 | /* | |
301 | [--I] signal 0x1a25ea8 | |
302 | [-AI] async 0x1a25cf0 | |
303 | [R--] idle 0x1a7a8c8 | |
304 | */ | |
305 | ||
306 | The format is `[flags] handle-type handle-address`. For `flags`: | |
307 | ||
308 | - `R` is printed for a handle that is referenced | |
309 | - `A` is printed for a handle that is active | |
310 | - `I` is printed for a handle that is internal | |
311 | ||
312 | .. warning:: | |
313 | This function is meant for ad hoc debugging, there is no API/ABI | |
314 | stability guarantees. | |
315 | ||
316 | .. versionadded:: 1.8.0 | |
317 | ||
318 | .. c:function:: void uv_print_active_handles(uv_loop_t* loop, FILE* stream) | |
319 | ||
320 | This is the same as :c:func:`uv_print_all_handles` except only active handles | |
321 | are printed. | |
322 | ||
323 | .. warning:: | |
324 | This function is meant for ad hoc debugging, there is no API/ABI | |
325 | stability guarantees. | |
326 | ||
327 | .. versionadded:: 1.8.0 |
33 | 33 | |
34 | 34 | .. c:function:: int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) |
35 | 35 | |
36 | Initialize the handle with the specified flags. At the moment the lower 8 bits | |
36 | Initialize the handle with the specified flags. At the moment only the lower 8 bits | |
37 | 37 | of the `flags` parameter are used as the socket domain. A socket will be created |
38 | 38 | for the given domain. If the specified domain is ``AF_UNSPEC`` no socket is created, |
39 | 39 | just like :c:func:`uv_tcp_init`. |
82 | 82 | if not any(a.startswith('-Duv_library=') for a in args): |
83 | 83 | args.append('-Duv_library=static_library') |
84 | 84 | |
85 | if not any(a.startswith('-Dcomponent=') for a in args): | |
86 | args.append('-Dcomponent=static_library') | |
87 | ||
88 | 85 | # Some platforms (OpenBSD for example) don't have multiprocessing.synchronize |
89 | 86 | # so gyp must be run with --no-parallel |
90 | 87 | if not gyp_parallel_support: |
30 | 30 | */ |
31 | 31 | |
32 | 32 | #define UV_VERSION_MAJOR 1 |
33 | #define UV_VERSION_MINOR 7 | |
34 | #define UV_VERSION_PATCH 5 | |
33 | #define UV_VERSION_MINOR 8 | |
34 | #define UV_VERSION_PATCH 0 | |
35 | 35 | #define UV_VERSION_IS_RELEASE 1 |
36 | 36 | #define UV_VERSION_SUFFIX "" |
37 | 37 |
47 | 47 | #include "uv-errno.h" |
48 | 48 | #include "uv-version.h" |
49 | 49 | #include <stddef.h> |
50 | #include <stdio.h> | |
50 | 51 | |
51 | 52 | #if defined(_MSC_VER) && _MSC_VER < 1600 |
52 | 53 | # include "stdint-msvc2008.h" |
423 | 424 | |
424 | 425 | UV_EXTERN void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg); |
425 | 426 | |
427 | /* Helpers for ad hoc debugging, no API/ABI stability guaranteed. */ | |
428 | UV_EXTERN void uv_print_all_handles(uv_loop_t* loop, FILE* stream); | |
429 | UV_EXTERN void uv_print_active_handles(uv_loop_t* loop, FILE* stream); | |
430 | ||
426 | 431 | UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb); |
427 | 432 | |
428 | 433 | UV_EXTERN int uv_send_buffer_size(uv_handle_t* handle, int* value); |
1082 | 1087 | UV_FS_SYMLINK, |
1083 | 1088 | UV_FS_READLINK, |
1084 | 1089 | UV_FS_CHOWN, |
1085 | UV_FS_FCHOWN | |
1090 | UV_FS_FCHOWN, | |
1091 | UV_FS_REALPATH | |
1086 | 1092 | } uv_fs_type; |
1087 | 1093 | |
1088 | 1094 | /* uv_fs_t is a subclass of uv_req_t. */ |
1234 | 1240 | uv_fs_t* req, |
1235 | 1241 | const char* path, |
1236 | 1242 | uv_fs_cb cb); |
1243 | UV_EXTERN int uv_fs_realpath(uv_loop_t* loop, | |
1244 | uv_fs_t* req, | |
1245 | const char* path, | |
1246 | uv_fs_cb cb); | |
1237 | 1247 | UV_EXTERN int uv_fs_fchmod(uv_loop_t* loop, |
1238 | 1248 | uv_fs_t* req, |
1239 | 1249 | uv_file file, |
1362 | 1372 | UV_EXTERN uint64_t uv_get_free_memory(void); |
1363 | 1373 | UV_EXTERN uint64_t uv_get_total_memory(void); |
1364 | 1374 | |
1365 | UV_EXTERN extern uint64_t uv_hrtime(void); | |
1375 | UV_EXTERN uint64_t uv_hrtime(void); | |
1366 | 1376 | |
1367 | 1377 | UV_EXTERN void uv_disable_stdio_inheritance(void); |
1368 | 1378 |
54 | 54 | char tmp[UV__INET_ADDRSTRLEN]; |
55 | 55 | int l; |
56 | 56 | |
57 | #ifndef _WIN32 | |
58 | 57 | l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); |
59 | #else | |
60 | l = _snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); | |
61 | #endif | |
62 | 58 | if (l <= 0 || (size_t) l >= size) { |
63 | 59 | return UV_ENOSPC; |
64 | 60 | } |
29 | 29 | #define QUEUE_DATA(ptr, type, field) \ |
30 | 30 | ((type *) ((char *) (ptr) - offsetof(type, field))) |
31 | 31 | |
32 | /* Important note: mutating the list while QUEUE_FOREACH is | |
33 | * iterating over its elements results in undefined behavior. | |
34 | */ | |
32 | 35 | #define QUEUE_FOREACH(q, h) \ |
33 | 36 | for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q)) |
34 | 37 | |
65 | 68 | } \ |
66 | 69 | while (0) |
67 | 70 | |
71 | #define QUEUE_MOVE(h, n) \ | |
72 | do { \ | |
73 | if (QUEUE_EMPTY(h)) \ | |
74 | QUEUE_INIT(n); \ | |
75 | else { \ | |
76 | QUEUE* q = QUEUE_HEAD(h); \ | |
77 | QUEUE_SPLIT(h, q, n); \ | |
78 | } \ | |
79 | } \ | |
80 | while (0) | |
81 | ||
68 | 82 | #define QUEUE_INSERT_HEAD(h, q) \ |
69 | 83 | do { \ |
70 | 84 | QUEUE_NEXT(q) = QUEUE_NEXT(h); \ |
222 | 222 | int err; |
223 | 223 | |
224 | 224 | loop = container_of(handle, uv_loop_t, wq_async); |
225 | QUEUE_INIT(&wq); | |
226 | ||
227 | 225 | uv_mutex_lock(&loop->wq_mutex); |
228 | if (!QUEUE_EMPTY(&loop->wq)) { | |
229 | q = QUEUE_HEAD(&loop->wq); | |
230 | QUEUE_SPLIT(&loop->wq, q, &wq); | |
231 | } | |
226 | QUEUE_MOVE(&loop->wq, &wq); | |
232 | 227 | uv_mutex_unlock(&loop->wq_mutex); |
233 | 228 | |
234 | 229 | while (!QUEUE_EMPTY(&wq)) { |
0 | 0 | /* |
1 | 1 | Copyright (c) 2013, Kenneth MacKay |
2 | Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement n° 289016) | |
2 | Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement #289016) | |
3 | 3 | All rights reserved. |
4 | 4 | |
5 | 5 | Redistribution and use in source and binary forms, with or without modification, |
77 | 77 | static void uv__async_event(uv_loop_t* loop, |
78 | 78 | struct uv__async* w, |
79 | 79 | unsigned int nevents) { |
80 | QUEUE queue; | |
80 | 81 | QUEUE* q; |
81 | 82 | uv_async_t* h; |
82 | 83 | |
83 | QUEUE_FOREACH(q, &loop->async_handles) { | |
84 | QUEUE_MOVE(&loop->async_handles, &queue); | |
85 | while (!QUEUE_EMPTY(&queue)) { | |
86 | q = QUEUE_HEAD(&queue); | |
84 | 87 | h = QUEUE_DATA(q, uv_async_t, queue); |
88 | ||
89 | QUEUE_REMOVE(q); | |
90 | QUEUE_INSERT_TAIL(&loop->async_handles, q); | |
85 | 91 | |
86 | 92 | if (cmpxchgi(&h->pending, 1, 0) == 0) |
87 | 93 | continue; |
16 | 16 | #define UV_ATOMIC_OPS_H_ |
17 | 17 | |
18 | 18 | #include "internal.h" /* UV_UNUSED */ |
19 | ||
20 | #if defined(__SUNPRO_C) || defined(__SUNPRO_CC) | |
21 | #include <atomic.h> | |
22 | #define __sync_val_compare_and_swap(p, o, n) atomic_cas_ptr(p, o, n) | |
23 | #endif | |
19 | 24 | |
20 | 25 | UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)); |
21 | 26 | UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)); |
74 | 74 | #include <sys/ioctl.h> |
75 | 75 | #endif |
76 | 76 | |
77 | #if defined(__ANDROID_API__) && __ANDROID_API__ < 21 | |
78 | # include <dlfcn.h> /* for dlsym */ | |
79 | #endif | |
80 | ||
77 | 81 | static int uv__run_pending(uv_loop_t* loop); |
78 | 82 | |
79 | 83 | /* Verify that uv_buf_t is ABI-compatible with struct iovec. */ |
203 | 207 | return IOV_MAX; |
204 | 208 | #elif defined(_SC_IOV_MAX) |
205 | 209 | static int iovmax = -1; |
206 | if (iovmax == -1) | |
210 | if (iovmax == -1) { | |
207 | 211 | iovmax = sysconf(_SC_IOV_MAX); |
212 | /* On some embedded devices (arm-linux-uclibc based ip camera), | |
213 | * sysconf(_SC_IOV_MAX) can not get the correct value. The return | |
214 | * value is -1 and the errno is EINPROGRESS. Degrade the value to 1. | |
215 | */ | |
216 | if (iovmax == -1) iovmax = 1; | |
217 | } | |
208 | 218 | return iovmax; |
209 | 219 | #else |
210 | 220 | return 1024; |
720 | 730 | if (QUEUE_EMPTY(&loop->pending_queue)) |
721 | 731 | return 0; |
722 | 732 | |
723 | QUEUE_INIT(&pq); | |
724 | q = QUEUE_HEAD(&loop->pending_queue); | |
725 | QUEUE_SPLIT(&loop->pending_queue, q, &pq); | |
733 | QUEUE_MOVE(&loop->pending_queue, &pq); | |
726 | 734 | |
727 | 735 | while (!QUEUE_EMPTY(&pq)) { |
728 | 736 | q = QUEUE_HEAD(&pq); |
955 | 963 | int uv__dup2_cloexec(int oldfd, int newfd) { |
956 | 964 | int r; |
957 | 965 | #if defined(__FreeBSD__) && __FreeBSD__ >= 10 |
958 | do | |
959 | r = dup3(oldfd, newfd, O_CLOEXEC); | |
960 | while (r == -1 && errno == EINTR); | |
966 | r = dup3(oldfd, newfd, O_CLOEXEC); | |
961 | 967 | if (r == -1) |
962 | 968 | return -errno; |
963 | 969 | return r; |
964 | 970 | #elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC) |
965 | do | |
966 | r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd); | |
967 | while (r == -1 && errno == EINTR); | |
971 | r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd); | |
968 | 972 | if (r != -1) |
969 | 973 | return r; |
970 | 974 | if (errno != EINVAL) |
975 | 979 | if (!no_dup3) { |
976 | 980 | do |
977 | 981 | r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC); |
978 | while (r == -1 && (errno == EINTR || errno == EBUSY)); | |
982 | while (r == -1 && errno == EBUSY); | |
979 | 983 | if (r != -1) |
980 | 984 | return r; |
981 | 985 | if (errno != ENOSYS) |
989 | 993 | do |
990 | 994 | r = dup2(oldfd, newfd); |
991 | 995 | #if defined(__linux__) |
992 | while (r == -1 && (errno == EINTR || errno == EBUSY)); | |
996 | while (r == -1 && errno == EBUSY); | |
993 | 997 | #else |
994 | while (r == -1 && errno == EINTR); | |
998 | while (0); /* Never retry. */ | |
995 | 999 | #endif |
996 | 1000 | |
997 | 1001 | if (r == -1) |
1017 | 1021 | size_t len; |
1018 | 1022 | long initsize; |
1019 | 1023 | int r; |
1024 | #if defined(__ANDROID_API__) && __ANDROID_API__ < 21 | |
1025 | int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**); | |
1026 | #endif | |
1020 | 1027 | |
1021 | 1028 | if (buffer == NULL || size == NULL || *size == 0) |
1022 | 1029 | return -EINVAL; |
1038 | 1045 | return 0; |
1039 | 1046 | } |
1040 | 1047 | |
1048 | #if defined(__ANDROID_API__) && __ANDROID_API__ < 21 | |
1049 | getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r"); | |
1050 | if (getpwuid_r == NULL) | |
1051 | return -ENOSYS; | |
1052 | #endif | |
1053 | ||
1041 | 1054 | /* HOME is not set, so call getpwuid() */ |
1042 | 1055 | initsize = sysconf(_SC_GETPW_R_SIZE_MAX); |
1043 | 1056 |
257 | 257 | } |
258 | 258 | |
259 | 259 | *addresses = uv__malloc(*count * sizeof(**addresses)); |
260 | if (!(*addresses)) | |
260 | if (!(*addresses)) { | |
261 | freeifaddrs(addrs); | |
261 | 262 | return -ENOMEM; |
263 | } | |
262 | 264 | |
263 | 265 | address = *addresses; |
264 | 266 |
38 | 38 | |
39 | 39 | |
40 | 40 | void uv_dlclose(uv_lib_t* lib) { |
41 | if (lib->errmsg) { | |
42 | uv__free(lib->errmsg); | |
43 | lib->errmsg = NULL; | |
44 | } | |
41 | uv__free(lib->errmsg); | |
42 | lib->errmsg = NULL; | |
45 | 43 | |
46 | 44 | if (lib->handle) { |
47 | 45 | /* Ignore errors. No good way to signal them without leaking memory. */ |
66 | 64 | static int uv__dlerror(uv_lib_t* lib) { |
67 | 65 | const char* errmsg; |
68 | 66 | |
69 | if (lib->errmsg) | |
70 | uv__free(lib->errmsg); | |
67 | uv__free(lib->errmsg); | |
71 | 68 | |
72 | 69 | errmsg = dlerror(); |
73 | 70 |
175 | 175 | int uv_set_process_title(const char* title) { |
176 | 176 | int oid[4]; |
177 | 177 | |
178 | if (process_title) uv__free(process_title); | |
178 | uv__free(process_title); | |
179 | 179 | process_title = uv__strdup(title); |
180 | 180 | |
181 | 181 | oid[0] = CTL_KERN; |
372 | 372 | } |
373 | 373 | |
374 | 374 | *addresses = uv__malloc(*count * sizeof(**addresses)); |
375 | if (!(*addresses)) | |
375 | if (!(*addresses)) { | |
376 | freeifaddrs(addrs); | |
376 | 377 | return -ENOMEM; |
378 | } | |
377 | 379 | |
378 | 380 | address = *addresses; |
379 | 381 |
79 | 79 | req->path = path; \ |
80 | 80 | } else { \ |
81 | 81 | req->path = uv__strdup(path); \ |
82 | if (req->path == NULL) \ | |
82 | if (req->path == NULL) { \ | |
83 | uv__req_unregister(loop, req); \ | |
83 | 84 | return -ENOMEM; \ |
85 | } \ | |
84 | 86 | } \ |
85 | 87 | } \ |
86 | 88 | while (0) |
96 | 98 | path_len = strlen(path) + 1; \ |
97 | 99 | new_path_len = strlen(new_path) + 1; \ |
98 | 100 | req->path = uv__malloc(path_len + new_path_len); \ |
99 | if (req->path == NULL) \ | |
101 | if (req->path == NULL) { \ | |
102 | uv__req_unregister(loop, req); \ | |
100 | 103 | return -ENOMEM; \ |
104 | } \ | |
101 | 105 | req->new_path = req->path + path_len; \ |
102 | 106 | memcpy((void*) req->path, path, path_len); \ |
103 | 107 | memcpy((void*) req->new_path, new_path, new_path_len); \ |
369 | 373 | } |
370 | 374 | |
371 | 375 | |
376 | static ssize_t uv__fs_pathmax_size(const char* path) { | |
377 | ssize_t pathmax; | |
378 | ||
379 | pathmax = pathconf(path, _PC_PATH_MAX); | |
380 | ||
381 | if (pathmax == -1) { | |
382 | #if defined(PATH_MAX) | |
383 | return PATH_MAX; | |
384 | #else | |
385 | return 4096; | |
386 | #endif | |
387 | } | |
388 | ||
389 | return pathmax; | |
390 | } | |
391 | ||
372 | 392 | static ssize_t uv__fs_readlink(uv_fs_t* req) { |
373 | 393 | ssize_t len; |
374 | 394 | char* buf; |
375 | 395 | |
376 | len = pathconf(req->path, _PC_PATH_MAX); | |
377 | ||
378 | if (len == -1) { | |
379 | #if defined(PATH_MAX) | |
380 | len = PATH_MAX; | |
381 | #else | |
382 | len = 4096; | |
383 | #endif | |
384 | } | |
385 | ||
396 | len = uv__fs_pathmax_size(req->path); | |
386 | 397 | buf = uv__malloc(len + 1); |
387 | 398 | |
388 | 399 | if (buf == NULL) { |
403 | 414 | return 0; |
404 | 415 | } |
405 | 416 | |
417 | static ssize_t uv__fs_realpath(uv_fs_t* req) { | |
418 | ssize_t len; | |
419 | char* buf; | |
420 | ||
421 | len = uv__fs_pathmax_size(req->path); | |
422 | buf = uv__malloc(len + 1); | |
423 | ||
424 | if (buf == NULL) { | |
425 | errno = ENOMEM; | |
426 | return -1; | |
427 | } | |
428 | ||
429 | if (realpath(req->path, buf) == NULL) { | |
430 | uv__free(buf); | |
431 | return -1; | |
432 | } | |
433 | ||
434 | req->ptr = buf; | |
435 | ||
436 | return 0; | |
437 | } | |
406 | 438 | |
407 | 439 | static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) { |
408 | 440 | struct pollfd pfd; |
625 | 657 | */ |
626 | 658 | #if defined(__APPLE__) |
627 | 659 | static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; |
628 | pthread_mutex_lock(&lock); | |
660 | ||
661 | if (pthread_mutex_lock(&lock)) | |
662 | abort(); | |
629 | 663 | #endif |
630 | 664 | |
631 | 665 | if (req->off < 0) { |
682 | 716 | |
683 | 717 | done: |
684 | 718 | #if defined(__APPLE__) |
685 | pthread_mutex_unlock(&lock); | |
719 | if (pthread_mutex_unlock(&lock)) | |
720 | abort(); | |
686 | 721 | #endif |
687 | 722 | |
688 | 723 | return r; |
866 | 901 | X(READ, uv__fs_buf_iter(req, uv__fs_read)); |
867 | 902 | X(SCANDIR, uv__fs_scandir(req)); |
868 | 903 | X(READLINK, uv__fs_readlink(req)); |
904 | X(REALPATH, uv__fs_realpath(req)); | |
869 | 905 | X(RENAME, rename(req->path, req->new_path)); |
870 | 906 | X(RMDIR, rmdir(req->path)); |
871 | 907 | X(SENDFILE, uv__fs_sendfile(req)); |
1061 | 1097 | uv_fs_cb cb) { |
1062 | 1098 | INIT(MKDTEMP); |
1063 | 1099 | req->path = uv__strdup(tpl); |
1064 | if (req->path == NULL) | |
1100 | if (req->path == NULL) { | |
1101 | if (cb != NULL) | |
1102 | uv__req_unregister(loop, req); | |
1065 | 1103 | return -ENOMEM; |
1104 | } | |
1066 | 1105 | POST; |
1067 | 1106 | } |
1068 | 1107 | |
1098 | 1137 | if (nbufs > ARRAY_SIZE(req->bufsml)) |
1099 | 1138 | req->bufs = uv__malloc(nbufs * sizeof(*bufs)); |
1100 | 1139 | |
1101 | if (req->bufs == NULL) | |
1140 | if (req->bufs == NULL) { | |
1141 | if (cb != NULL) | |
1142 | uv__req_unregister(loop, req); | |
1102 | 1143 | return -ENOMEM; |
1144 | } | |
1103 | 1145 | |
1104 | 1146 | memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); |
1105 | 1147 | |
1125 | 1167 | const char* path, |
1126 | 1168 | uv_fs_cb cb) { |
1127 | 1169 | INIT(READLINK); |
1170 | PATH; | |
1171 | POST; | |
1172 | } | |
1173 | ||
1174 | ||
1175 | int uv_fs_realpath(uv_loop_t* loop, | |
1176 | uv_fs_t* req, | |
1177 | const char * path, | |
1178 | uv_fs_cb cb) { | |
1179 | INIT(REALPATH); | |
1128 | 1180 | PATH; |
1129 | 1181 | POST; |
1130 | 1182 | } |
1223 | 1275 | if (nbufs > ARRAY_SIZE(req->bufsml)) |
1224 | 1276 | req->bufs = uv__malloc(nbufs * sizeof(*bufs)); |
1225 | 1277 | |
1226 | if (req->bufs == NULL) | |
1278 | if (req->bufs == NULL) { | |
1279 | if (cb != NULL) | |
1280 | uv__req_unregister(loop, req); | |
1227 | 1281 | return -ENOMEM; |
1282 | } | |
1228 | 1283 | |
1229 | 1284 | memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); |
1230 | 1285 |
72 | 72 | typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t; |
73 | 73 | typedef struct uv__cf_loop_state_s uv__cf_loop_state_t; |
74 | 74 | |
75 | enum uv__cf_loop_signal_type_e { | |
76 | kUVCFLoopSignalRegular, | |
77 | kUVCFLoopSignalClosing | |
78 | }; | |
79 | typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t; | |
80 | ||
75 | 81 | struct uv__cf_loop_signal_s { |
76 | 82 | QUEUE member; |
77 | 83 | uv_fs_event_t* handle; |
84 | uv__cf_loop_signal_type_t type; | |
78 | 85 | }; |
79 | 86 | |
80 | 87 | struct uv__fsevents_event_s { |
97 | 104 | /* Forward declarations */ |
98 | 105 | static void uv__cf_loop_cb(void* arg); |
99 | 106 | static void* uv__cf_loop_runner(void* arg); |
100 | static int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle); | |
107 | static int uv__cf_loop_signal(uv_loop_t* loop, | |
108 | uv_fs_event_t* handle, | |
109 | uv__cf_loop_signal_type_t type); | |
101 | 110 | |
102 | 111 | /* Lazy-loaded by uv__fsevents_global_init(). */ |
103 | 112 | static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef, |
148 | 157 | int err; \ |
149 | 158 | uv_mutex_lock(&(handle)->cf_mutex); \ |
150 | 159 | /* Split-off all events and empty original queue */ \ |
151 | QUEUE_INIT(&events); \ | |
152 | if (!QUEUE_EMPTY(&(handle)->cf_events)) { \ | |
153 | q = QUEUE_HEAD(&(handle)->cf_events); \ | |
154 | QUEUE_SPLIT(&(handle)->cf_events, q, &events); \ | |
155 | } \ | |
160 | QUEUE_MOVE(&(handle)->cf_events, &events); \ | |
156 | 161 | /* Get error (if any) and zero original one */ \ |
157 | 162 | err = (handle)->cf_error; \ |
158 | 163 | (handle)->cf_error = 0; \ |
386 | 391 | |
387 | 392 | |
388 | 393 | /* Runs in CF thread, when there're new fsevent handles to add to stream */ |
389 | static void uv__fsevents_reschedule(uv_fs_event_t* handle) { | |
394 | static void uv__fsevents_reschedule(uv_fs_event_t* handle, | |
395 | uv__cf_loop_signal_type_t type) { | |
390 | 396 | uv__cf_loop_state_t* state; |
391 | 397 | QUEUE* q; |
392 | 398 | uv_fs_event_t* curr; |
485 | 491 | * |
486 | 492 | * NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close` |
487 | 493 | */ |
488 | if (!uv__is_active(handle)) | |
494 | if (type == kUVCFLoopSignalClosing) | |
489 | 495 | uv_sem_post(&state->fsevent_sem); |
490 | 496 | } |
491 | 497 | |
675 | 681 | if (loop->cf_state == NULL) |
676 | 682 | return; |
677 | 683 | |
678 | if (uv__cf_loop_signal(loop, NULL) != 0) | |
684 | if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0) | |
679 | 685 | abort(); |
680 | 686 | |
681 | 687 | uv_thread_join(&loop->cf_thread); |
734 | 740 | |
735 | 741 | loop = arg; |
736 | 742 | state = loop->cf_state; |
737 | QUEUE_INIT(&split_head); | |
738 | 743 | |
739 | 744 | uv_mutex_lock(&loop->cf_mutex); |
740 | if (!QUEUE_EMPTY(&loop->cf_signals)) { | |
741 | QUEUE* split_pos = QUEUE_HEAD(&loop->cf_signals); | |
742 | QUEUE_SPLIT(&loop->cf_signals, split_pos, &split_head); | |
743 | } | |
745 | QUEUE_MOVE(&loop->cf_signals, &split_head); | |
744 | 746 | uv_mutex_unlock(&loop->cf_mutex); |
745 | 747 | |
746 | 748 | while (!QUEUE_EMPTY(&split_head)) { |
747 | 749 | item = QUEUE_HEAD(&split_head); |
750 | QUEUE_REMOVE(item); | |
748 | 751 | |
749 | 752 | s = QUEUE_DATA(item, uv__cf_loop_signal_t, member); |
750 | 753 | |
752 | 755 | if (s->handle == NULL) |
753 | 756 | pCFRunLoopStop(state->loop); |
754 | 757 | else |
755 | uv__fsevents_reschedule(s->handle); | |
756 | ||
757 | QUEUE_REMOVE(item); | |
758 | uv__fsevents_reschedule(s->handle, s->type); | |
759 | ||
758 | 760 | uv__free(s); |
759 | 761 | } |
760 | 762 | } |
761 | 763 | |
762 | 764 | |
763 | 765 | /* Runs in UV loop to notify CF thread */ |
764 | int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle) { | |
766 | int uv__cf_loop_signal(uv_loop_t* loop, | |
767 | uv_fs_event_t* handle, | |
768 | uv__cf_loop_signal_type_t type) { | |
765 | 769 | uv__cf_loop_signal_t* item; |
766 | 770 | uv__cf_loop_state_t* state; |
767 | 771 | |
770 | 774 | return -ENOMEM; |
771 | 775 | |
772 | 776 | item->handle = handle; |
777 | item->type = type; | |
773 | 778 | |
774 | 779 | uv_mutex_lock(&loop->cf_mutex); |
775 | 780 | QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member); |
832 | 837 | |
833 | 838 | /* Reschedule FSEventStream */ |
834 | 839 | assert(handle != NULL); |
835 | err = uv__cf_loop_signal(handle->loop, handle); | |
840 | err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular); | |
836 | 841 | if (err) |
837 | 842 | goto fail_loop_signal; |
838 | 843 | |
872 | 877 | |
873 | 878 | /* Reschedule FSEventStream */ |
874 | 879 | assert(handle != NULL); |
875 | err = uv__cf_loop_signal(handle->loop, handle); | |
880 | err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing); | |
876 | 881 | if (err) |
877 | 882 | return -err; |
878 | 883 |
813 | 813 | return 0; |
814 | 814 | |
815 | 815 | *addresses = uv__malloc(*count * sizeof(**addresses)); |
816 | if (!(*addresses)) | |
816 | if (!(*addresses)) { | |
817 | freeifaddrs(addrs); | |
817 | 818 | return -ENOMEM; |
819 | } | |
818 | 820 | |
819 | 821 | address = *addresses; |
820 | 822 |
34 | 34 | struct watcher_list { |
35 | 35 | RB_ENTRY(watcher_list) entry; |
36 | 36 | QUEUE watchers; |
37 | int iterating; | |
37 | 38 | char* path; |
38 | 39 | int wd; |
39 | 40 | }; |
112 | 113 | return RB_FIND(watcher_root, CAST(&loop->inotify_watchers), &w); |
113 | 114 | } |
114 | 115 | |
116 | static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) { | |
117 | /* if the watcher_list->watchers is being iterated over, we can't free it. */ | |
118 | if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) { | |
119 | /* No watchers left for this path. Clean up. */ | |
120 | RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w); | |
121 | uv__inotify_rm_watch(loop->inotify_fd, w->wd); | |
122 | uv__free(w); | |
123 | } | |
124 | } | |
115 | 125 | |
116 | 126 | static void uv__inotify_read(uv_loop_t* loop, |
117 | 127 | uv__io_t* dummy, |
119 | 129 | const struct uv__inotify_event* e; |
120 | 130 | struct watcher_list* w; |
121 | 131 | uv_fs_event_t* h; |
132 | QUEUE queue; | |
122 | 133 | QUEUE* q; |
123 | 134 | const char* path; |
124 | 135 | ssize_t size; |
158 | 169 | */ |
159 | 170 | path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path); |
160 | 171 | |
161 | QUEUE_FOREACH(q, &w->watchers) { | |
172 | /* We're about to iterate over the queue and call user's callbacks. | |
173 | * What can go wrong? | |
174 | * A callback could call uv_fs_event_stop() | |
175 | * and the queue can change under our feet. | |
176 | * So, we use QUEUE_MOVE() trick to safely iterate over the queue. | |
177 | * And we don't free the watcher_list until we're done iterating. | |
178 | * | |
179 | * First, | |
180 | * tell uv_fs_event_stop() (that could be called from a user's callback) | |
181 | * not to free watcher_list. | |
182 | */ | |
183 | w->iterating = 1; | |
184 | QUEUE_MOVE(&w->watchers, &queue); | |
185 | while (!QUEUE_EMPTY(&queue)) { | |
186 | q = QUEUE_HEAD(&queue); | |
162 | 187 | h = QUEUE_DATA(q, uv_fs_event_t, watchers); |
188 | ||
189 | QUEUE_REMOVE(q); | |
190 | QUEUE_INSERT_TAIL(&w->watchers, q); | |
191 | ||
163 | 192 | h->cb(h, path, events, 0); |
164 | 193 | } |
194 | /* done iterating, time to (maybe) free empty watcher_list */ | |
195 | w->iterating = 0; | |
196 | maybe_free_watcher_list(w, loop); | |
165 | 197 | } |
166 | 198 | } |
167 | 199 | } |
213 | 245 | w->wd = wd; |
214 | 246 | w->path = strcpy((char*)(w + 1), path); |
215 | 247 | QUEUE_INIT(&w->watchers); |
248 | w->iterating = 0; | |
216 | 249 | RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w); |
217 | 250 | |
218 | 251 | no_insert: |
240 | 273 | uv__handle_stop(handle); |
241 | 274 | QUEUE_REMOVE(&handle->watchers); |
242 | 275 | |
243 | if (QUEUE_EMPTY(&w->watchers)) { | |
244 | /* No watchers left for this path. Clean up. */ | |
245 | RB_REMOVE(watcher_root, CAST(&handle->loop->inotify_watchers), w); | |
246 | uv__inotify_rm_watch(handle->loop->inotify_fd, w->wd); | |
247 | uv__free(w); | |
248 | } | |
276 | maybe_free_watcher_list(w, handle->loop); | |
249 | 277 | |
250 | 278 | return 0; |
251 | 279 | } |
443 | 443 | } |
444 | 444 | |
445 | 445 | |
446 | ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) { | |
446 | ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) { | |
447 | 447 | #if defined(__NR_preadv) |
448 | return syscall(__NR_preadv, fd, iov, iovcnt, offset); | |
449 | #else | |
450 | return errno = ENOSYS, -1; | |
451 | #endif | |
452 | } | |
453 | ||
454 | ||
455 | ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) { | |
448 | return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32)); | |
449 | #else | |
450 | return errno = ENOSYS, -1; | |
451 | #endif | |
452 | } | |
453 | ||
454 | ||
455 | ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) { | |
456 | 456 | #if defined(__NR_pwritev) |
457 | return syscall(__NR_pwritev, fd, iov, iovcnt, offset); | |
457 | return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32)); | |
458 | 458 | #else |
459 | 459 | return errno = ENOSYS, -1; |
460 | 460 | #endif |
150 | 150 | const char* path, |
151 | 151 | const struct timespec times[2], |
152 | 152 | int flags); |
153 | ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset); | |
154 | ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); | |
153 | ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset); | |
154 | ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset); | |
155 | 155 | int uv__dup3(int oldfd, int newfd, int flags); |
156 | 156 | |
157 | 157 | #endif /* UV_LINUX_SYSCALL_H_ */ |
46 | 46 | \ |
47 | 47 | void uv__run_##name(uv_loop_t* loop) { \ |
48 | 48 | uv_##name##_t* h; \ |
49 | QUEUE queue; \ | |
49 | 50 | QUEUE* q; \ |
50 | QUEUE_FOREACH(q, &loop->name##_handles) { \ | |
51 | QUEUE_MOVE(&loop->name##_handles, &queue); \ | |
52 | while (!QUEUE_EMPTY(&queue)) { \ | |
53 | q = QUEUE_HEAD(&queue); \ | |
51 | 54 | h = QUEUE_DATA(q, uv_##name##_t, queue); \ |
55 | QUEUE_REMOVE(q); \ | |
56 | QUEUE_INSERT_TAIL(&loop->name##_handles, q); \ | |
52 | 57 | h->name##_cb(h); \ |
53 | 58 | } \ |
54 | 59 | } \ |
297 | 297 | |
298 | 298 | *addresses = uv__malloc(*count * sizeof(**addresses)); |
299 | 299 | |
300 | if (!(*addresses)) | |
300 | if (!(*addresses)) { | |
301 | freeifaddrs(addrs); | |
301 | 302 | return -ENOMEM; |
303 | } | |
302 | 304 | |
303 | 305 | address = *addresses; |
304 | 306 |
160 | 160 | |
161 | 161 | |
162 | 162 | int uv_set_process_title(const char* title) { |
163 | if (process_title) uv__free(process_title); | |
163 | uv__free(process_title); | |
164 | 164 | process_title = uv__strdup(title); |
165 | 165 | setproctitle(title); |
166 | 166 | return 0; |
312 | 312 | |
313 | 313 | *addresses = uv__malloc(*count * sizeof(**addresses)); |
314 | 314 | |
315 | if (!(*addresses)) | |
315 | if (!(*addresses)) { | |
316 | freeifaddrs(addrs); | |
316 | 317 | return -ENOMEM; |
318 | } | |
317 | 319 | |
318 | 320 | address = *addresses; |
319 | 321 |
269 | 269 | } |
270 | 270 | |
271 | 271 | |
272 | #if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)) | |
273 | /* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be | |
274 | * avoided. Since this isn't called on those targets, the function | |
275 | * doesn't even need to be defined for them. | |
276 | */ | |
272 | 277 | static void uv__process_child_init(const uv_process_options_t* options, |
273 | 278 | int stdio_count, |
274 | 279 | int (*pipes)[2], |
374 | 379 | uv__write_int(error_fd, -errno); |
375 | 380 | _exit(127); |
376 | 381 | } |
382 | #endif | |
377 | 383 | |
378 | 384 | |
379 | 385 | int uv_spawn(uv_loop_t* loop, |
380 | 386 | uv_process_t* process, |
381 | 387 | const uv_process_options_t* options) { |
388 | #if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) | |
389 | /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */ | |
390 | return -ENOSYS; | |
391 | #else | |
382 | 392 | int signal_pipe[2] = { -1, -1 }; |
383 | 393 | int (*pipes)[2]; |
384 | 394 | int stdio_count; |
527 | 537 | } |
528 | 538 | |
529 | 539 | return err; |
540 | #endif | |
530 | 541 | } |
531 | 542 | |
532 | 543 |
233 | 233 | /* Stop all the signal watchers that are still attached to this loop. This |
234 | 234 | * ensures that the (shared) signal tree doesn't contain any invalid entries |
235 | 235 | * entries, and that signal handlers are removed when appropriate. |
236 | * It's safe to use QUEUE_FOREACH here because the handles and the handle | |
237 | * queue are not modified by uv__signal_stop(). | |
236 | 238 | */ |
237 | 239 | QUEUE_FOREACH(q, &loop->handle_queue) { |
238 | 240 | uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue); |
778 | 778 | |
779 | 779 | if (req->send_handle) { |
780 | 780 | struct msghdr msg; |
781 | char scratch[64]; | |
782 | 781 | struct cmsghdr *cmsg; |
783 | 782 | int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle); |
783 | char scratch[64] = {0}; | |
784 | 784 | |
785 | 785 | assert(fd_to_send >= 0); |
786 | 786 | |
1470 | 1470 | uv__stream_osx_interrupt_select(stream); |
1471 | 1471 | } |
1472 | 1472 | |
1473 | if (written == 0) | |
1473 | if (written == 0 && req_size != 0) | |
1474 | 1474 | return -EAGAIN; |
1475 | 1475 | else |
1476 | 1476 | return written; |
692 | 692 | } |
693 | 693 | |
694 | 694 | *addresses = uv__malloc(*count * sizeof(**addresses)); |
695 | if (!(*addresses)) | |
695 | if (!(*addresses)) { | |
696 | freeifaddrs(addrs); | |
696 | 697 | return -ENOMEM; |
698 | } | |
697 | 699 | |
698 | 700 | address = *addresses; |
699 | 701 |
235 | 235 | return UV_UDP; |
236 | 236 | |
237 | 237 | if (type == SOCK_STREAM) { |
238 | #if defined(_AIX) | |
239 | /* on AIX the getsockname call returns an empty sa structure | |
240 | * for sockets of type AF_UNIX. For all other types it will | |
241 | * return a properly filled in structure. | |
242 | */ | |
243 | if (len == 0) | |
244 | return UV_NAMED_PIPE; | |
245 | #endif /* defined(_AIX) */ | |
246 | ||
238 | 247 | if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) |
239 | 248 | return UV_TCP; |
240 | 249 | if (sa.sa_family == AF_UNIX) |
409 | 409 | if (nbufs > ARRAY_SIZE(req->bufsml)) |
410 | 410 | req->bufs = uv__malloc(nbufs * sizeof(bufs[0])); |
411 | 411 | |
412 | if (req->bufs == NULL) | |
412 | if (req->bufs == NULL) { | |
413 | uv__req_unregister(handle->loop, req); | |
413 | 414 | return -ENOMEM; |
415 | } | |
414 | 416 | |
415 | 417 | memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); |
416 | 418 | handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs); |
140 | 140 | char buf[32]; |
141 | 141 | char* copy; |
142 | 142 | |
143 | #ifndef _WIN32 | |
144 | 143 | snprintf(buf, sizeof(buf), "Unknown system error %d", err); |
145 | #else | |
146 | _snprintf(buf, sizeof(buf), "Unknown system error %d", err); | |
147 | #endif | |
148 | 144 | copy = uv__strdup(buf); |
149 | 145 | |
150 | 146 | return copy != NULL ? copy : "Unknown system error"; |
340 | 336 | |
341 | 337 | |
342 | 338 | void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) { |
339 | QUEUE queue; | |
343 | 340 | QUEUE* q; |
344 | 341 | uv_handle_t* h; |
345 | 342 | |
346 | QUEUE_FOREACH(q, &loop->handle_queue) { | |
343 | QUEUE_MOVE(&loop->handle_queue, &queue); | |
344 | while (!QUEUE_EMPTY(&queue)) { | |
345 | q = QUEUE_HEAD(&queue); | |
347 | 346 | h = QUEUE_DATA(q, uv_handle_t, handle_queue); |
347 | ||
348 | QUEUE_REMOVE(q); | |
349 | QUEUE_INSERT_TAIL(&loop->handle_queue, q); | |
350 | ||
348 | 351 | if (h->flags & UV__HANDLE_INTERNAL) continue; |
349 | 352 | walk_cb(h, arg); |
350 | 353 | } |
351 | 354 | } |
352 | 355 | |
353 | 356 | |
354 | #ifndef NDEBUG | |
355 | static void uv__print_handles(uv_loop_t* loop, int only_active) { | |
357 | static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) { | |
356 | 358 | const char* type; |
357 | 359 | QUEUE* q; |
358 | 360 | uv_handle_t* h; |
373 | 375 | default: type = "<unknown>"; |
374 | 376 | } |
375 | 377 | |
376 | fprintf(stderr, | |
378 | fprintf(stream, | |
377 | 379 | "[%c%c%c] %-8s %p\n", |
378 | 380 | "R-"[!(h->flags & UV__HANDLE_REF)], |
379 | 381 | "A-"[!(h->flags & UV__HANDLE_ACTIVE)], |
384 | 386 | } |
385 | 387 | |
386 | 388 | |
387 | void uv_print_all_handles(uv_loop_t* loop) { | |
388 | uv__print_handles(loop, 0); | |
389 | } | |
390 | ||
391 | ||
392 | void uv_print_active_handles(uv_loop_t* loop) { | |
393 | uv__print_handles(loop, 1); | |
394 | } | |
395 | #endif | |
389 | void uv_print_all_handles(uv_loop_t* loop, FILE* stream) { | |
390 | uv__print_handles(loop, 0, stream); | |
391 | } | |
392 | ||
393 | ||
394 | void uv_print_active_handles(uv_loop_t* loop, FILE* stream) { | |
395 | uv__print_handles(loop, 1, stream); | |
396 | } | |
396 | 397 | |
397 | 398 | |
398 | 399 | void uv_ref(uv_handle_t* handle) { |
40 | 40 | #include "tree.h" |
41 | 41 | #include "queue.h" |
42 | 42 | |
43 | #if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900 | |
44 | extern int snprintf(char*, size_t, const char*, ...); | |
45 | #endif | |
46 | ||
43 | 47 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) |
44 | 48 | |
45 | 49 | #define container_of(ptr, type, member) \ |
128 | 128 | case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH; |
129 | 129 | case WSAENETUNREACH: return UV_ENETUNREACH; |
130 | 130 | case WSAENOBUFS: return UV_ENOBUFS; |
131 | case ERROR_BAD_PATHNAME: return UV_ENOENT; | |
131 | 132 | case ERROR_DIRECTORY: return UV_ENOENT; |
132 | 133 | case ERROR_FILE_NOT_FOUND: return UV_ENOENT; |
133 | 134 | case ERROR_INVALID_NAME: return UV_ENOENT; |
380 | 380 | |
381 | 381 | if (handle->dirw) { |
382 | 382 | /* |
383 | * We attempt to convert the file name to its long form for | |
384 | * events that still point to valid files on disk. | |
385 | * For removed and renamed events, we do not provide the file name. | |
383 | * We attempt to resolve the long form of the file name explicitly. | |
384 | * We only do this for file names that might still exist on disk. | |
385 | * If this fails, we use the name given by ReadDirectoryChangesW. | |
386 | * This may be the long form or the 8.3 short name in some cases. | |
386 | 387 | */ |
387 | 388 | if (file_info->Action != FILE_ACTION_REMOVED && |
388 | 389 | file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) { |
437 | 438 | } |
438 | 439 | |
439 | 440 | /* |
440 | * If we couldn't get the long name - just use the name | |
441 | * provided by ReadDirectoryChangesW. | |
441 | * We could not resolve the long form explicitly. | |
442 | * We therefore use the name given by ReadDirectoryChangesW. | |
443 | * This may be the long form or the 8.3 short name in some cases. | |
442 | 444 | */ |
443 | 445 | if (!long_filenamew) { |
444 | 446 | filenamew = file_info->FileName; |
445 | 447 | sizew = file_info->FileNameLength / sizeof(WCHAR); |
446 | 448 | } |
447 | 449 | } else { |
448 | /* Removed or renamed callbacks don't provide filename. */ | |
449 | filenamew = NULL; | |
450 | /* | |
451 | * Removed or renamed events cannot be resolved to the long form. | |
452 | * We therefore use the name given by ReadDirectoryChangesW. | |
453 | * This may be the long form or the 8.3 short name in some cases. | |
454 | */ | |
455 | if (!long_filenamew) { | |
456 | filenamew = file_info->FileName; | |
457 | sizew = file_info->FileNameLength / sizeof(WCHAR); | |
458 | } | |
450 | 459 | } |
451 | 460 | } else { |
452 | 461 | /* We already have the long name of the file, so just use it. */ |
109 | 109 | const WCHAR LONG_PATH_PREFIX[] = L"\\\\?\\"; |
110 | 110 | const WCHAR LONG_PATH_PREFIX_LEN = 4; |
111 | 111 | |
112 | const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\"; | |
113 | const WCHAR UNC_PATH_PREFIX_LEN = 8; | |
114 | ||
112 | 115 | |
113 | 116 | void uv_fs_init() { |
114 | 117 | _fmode = _O_BINARY; |
232 | 235 | } |
233 | 236 | |
234 | 237 | |
238 | static int fs__wide_to_utf8(WCHAR* w_source_ptr, | |
239 | DWORD w_source_len, | |
240 | char** target_ptr, | |
241 | uint64_t* target_len_ptr) { | |
242 | int r; | |
243 | int target_len; | |
244 | char* target; | |
245 | target_len = WideCharToMultiByte(CP_UTF8, | |
246 | 0, | |
247 | w_source_ptr, | |
248 | w_source_len, | |
249 | NULL, | |
250 | 0, | |
251 | NULL, | |
252 | NULL); | |
253 | ||
254 | if (target_len == 0) { | |
255 | return -1; | |
256 | } | |
257 | ||
258 | if (target_len_ptr != NULL) { | |
259 | *target_len_ptr = target_len; | |
260 | } | |
261 | ||
262 | if (target_ptr == NULL) { | |
263 | return 0; | |
264 | } | |
265 | ||
266 | target = uv__malloc(target_len + 1); | |
267 | if (target == NULL) { | |
268 | SetLastError(ERROR_OUTOFMEMORY); | |
269 | return -1; | |
270 | } | |
271 | ||
272 | r = WideCharToMultiByte(CP_UTF8, | |
273 | 0, | |
274 | w_source_ptr, | |
275 | w_source_len, | |
276 | target, | |
277 | target_len, | |
278 | NULL, | |
279 | NULL); | |
280 | assert(r == target_len); | |
281 | target[target_len] = '\0'; | |
282 | *target_ptr = target; | |
283 | return 0; | |
284 | } | |
285 | ||
286 | ||
235 | 287 | INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, |
236 | 288 | uint64_t* target_len_ptr) { |
237 | 289 | char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; |
238 | 290 | REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer; |
239 | WCHAR *w_target; | |
291 | WCHAR* w_target; | |
240 | 292 | DWORD w_target_len; |
241 | char* target; | |
242 | int target_len; | |
243 | 293 | DWORD bytes; |
244 | 294 | |
245 | 295 | if (!DeviceIoControl(handle, |
332 | 382 | return -1; |
333 | 383 | } |
334 | 384 | |
335 | /* If needed, compute the length of the target. */ | |
336 | if (target_ptr != NULL || target_len_ptr != NULL) { | |
337 | /* Compute the length of the target. */ | |
338 | target_len = WideCharToMultiByte(CP_UTF8, | |
339 | 0, | |
340 | w_target, | |
341 | w_target_len, | |
342 | NULL, | |
343 | 0, | |
344 | NULL, | |
345 | NULL); | |
346 | if (target_len == 0) { | |
347 | return -1; | |
348 | } | |
349 | } | |
350 | ||
351 | /* If requested, allocate memory and convert to UTF8. */ | |
352 | if (target_ptr != NULL) { | |
353 | int r; | |
354 | target = (char*) uv__malloc(target_len + 1); | |
355 | if (target == NULL) { | |
356 | SetLastError(ERROR_OUTOFMEMORY); | |
357 | return -1; | |
358 | } | |
359 | ||
360 | r = WideCharToMultiByte(CP_UTF8, | |
361 | 0, | |
362 | w_target, | |
363 | w_target_len, | |
364 | target, | |
365 | target_len, | |
366 | NULL, | |
367 | NULL); | |
368 | assert(r == target_len); | |
369 | target[target_len] = '\0'; | |
370 | ||
371 | *target_ptr = target; | |
372 | } | |
373 | ||
374 | if (target_len_ptr != NULL) { | |
375 | *target_len_ptr = target_len; | |
376 | } | |
377 | ||
378 | return 0; | |
385 | return fs__wide_to_utf8(w_target, w_target_len, target_ptr, target_len_ptr); | |
379 | 386 | } |
380 | 387 | |
381 | 388 | |
532 | 539 | else |
533 | 540 | result = 0; |
534 | 541 | |
535 | SET_REQ_RESULT(req, result); | |
542 | /* _close doesn't set _doserrno on failure, but it does always set errno | |
543 | * to EBADF on failure. | |
544 | */ | |
545 | if (result == -1) { | |
546 | assert(errno == EBADF); | |
547 | SET_REQ_UV_ERROR(req, UV_EBADF, ERROR_INVALID_HANDLE); | |
548 | } else { | |
549 | req->result = 0; | |
550 | } | |
536 | 551 | } |
537 | 552 | |
538 | 553 | |
1697 | 1712 | CloseHandle(handle); |
1698 | 1713 | } |
1699 | 1714 | |
1715 | ||
1716 | static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { | |
1717 | int r; | |
1718 | DWORD w_realpath_len; | |
1719 | WCHAR* w_realpath_ptr; | |
1720 | WCHAR* w_finalpath_ptr = NULL; | |
1721 | ||
1722 | w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS); | |
1723 | if (w_realpath_len == 0) { | |
1724 | return -1; | |
1725 | } | |
1726 | ||
1727 | w_realpath_ptr = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR)); | |
1728 | if (w_realpath_ptr == NULL) { | |
1729 | SetLastError(ERROR_OUTOFMEMORY); | |
1730 | return -1; | |
1731 | } | |
1732 | ||
1733 | if (pGetFinalPathNameByHandleW(handle, | |
1734 | w_realpath_ptr, | |
1735 | w_realpath_len, | |
1736 | VOLUME_NAME_DOS) == 0) { | |
1737 | uv__free(w_realpath_ptr); | |
1738 | SetLastError(ERROR_INVALID_HANDLE); | |
1739 | return -1; | |
1740 | } | |
1741 | ||
1742 | /* convert UNC path to long path */ | |
1743 | if (wcsncmp(w_realpath_ptr, | |
1744 | UNC_PATH_PREFIX, | |
1745 | UNC_PATH_PREFIX_LEN) == 0) { | |
1746 | w_finalpath_ptr = w_realpath_ptr + 6; | |
1747 | *w_finalpath_ptr = L'\\'; | |
1748 | } else if (wcsncmp(w_realpath_ptr, | |
1749 | LONG_PATH_PREFIX, | |
1750 | LONG_PATH_PREFIX_LEN) == 0) { | |
1751 | w_finalpath_ptr = w_realpath_ptr + 4; | |
1752 | } else { | |
1753 | uv__free(w_realpath_ptr); | |
1754 | SetLastError(ERROR_INVALID_HANDLE); | |
1755 | return -1; | |
1756 | } | |
1757 | ||
1758 | r = fs__wide_to_utf8(w_finalpath_ptr, w_realpath_len, realpath_ptr, NULL); | |
1759 | uv__free(w_realpath_ptr); | |
1760 | return r; | |
1761 | } | |
1762 | ||
1763 | static void fs__realpath(uv_fs_t* req) { | |
1764 | HANDLE handle; | |
1765 | ||
1766 | if (!pGetFinalPathNameByHandleW) { | |
1767 | SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); | |
1768 | return; | |
1769 | } | |
1770 | ||
1771 | handle = CreateFileW(req->file.pathw, | |
1772 | 0, | |
1773 | 0, | |
1774 | NULL, | |
1775 | OPEN_EXISTING, | |
1776 | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, | |
1777 | NULL); | |
1778 | if (handle == INVALID_HANDLE_VALUE) { | |
1779 | SET_REQ_WIN32_ERROR(req, GetLastError()); | |
1780 | return; | |
1781 | } | |
1782 | ||
1783 | if (fs__realpath_handle(handle, (char**) &req->ptr) == -1) { | |
1784 | CloseHandle(handle); | |
1785 | SET_REQ_WIN32_ERROR(req, GetLastError()); | |
1786 | return; | |
1787 | } | |
1788 | ||
1789 | CloseHandle(handle); | |
1790 | req->flags |= UV_FS_FREE_PTR; | |
1791 | SET_REQ_RESULT(req, 0); | |
1792 | } | |
1700 | 1793 | |
1701 | 1794 | |
1702 | 1795 | static void fs__chown(uv_fs_t* req) { |
1742 | 1835 | XX(LINK, link) |
1743 | 1836 | XX(SYMLINK, symlink) |
1744 | 1837 | XX(READLINK, readlink) |
1838 | XX(REALPATH, realpath) | |
1745 | 1839 | XX(CHOWN, chown) |
1746 | 1840 | XX(FCHOWN, fchown); |
1747 | 1841 | default: |
2066 | 2160 | } |
2067 | 2161 | |
2068 | 2162 | |
2163 | int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, | |
2164 | uv_fs_cb cb) { | |
2165 | int err; | |
2166 | ||
2167 | if (!req || !path) { | |
2168 | return UV_EINVAL; | |
2169 | } | |
2170 | ||
2171 | uv_fs_req_init(loop, req, UV_FS_REALPATH, cb); | |
2172 | ||
2173 | err = fs__capture_path(req, path, NULL, cb != NULL); | |
2174 | if (err) { | |
2175 | return uv_translate_sys_error(err); | |
2176 | } | |
2177 | ||
2178 | if (cb) { | |
2179 | QUEUE_FS_TP_JOB(loop, req); | |
2180 | return 0; | |
2181 | } else { | |
2182 | fs__realpath(req); | |
2183 | return req->result; | |
2184 | } | |
2185 | } | |
2186 | ||
2187 | ||
2069 | 2188 | int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, |
2070 | 2189 | uv_gid_t gid, uv_fs_cb cb) { |
2071 | 2190 | int err; |
108 | 108 | req = container_of(w, uv_getaddrinfo_t, work_req); |
109 | 109 | |
110 | 110 | /* release input parameter memory */ |
111 | if (req->alloc != NULL) { | |
112 | uv__free(req->alloc); | |
113 | req->alloc = NULL; | |
114 | } | |
111 | uv__free(req->alloc); | |
112 | req->alloc = NULL; | |
115 | 113 | |
116 | 114 | if (status == UV_ECANCELED) { |
117 | 115 | assert(req->retcode == 0); |
218 | 216 | char* alloc_ptr = (char*)ai; |
219 | 217 | |
220 | 218 | /* release copied result memory */ |
221 | if (alloc_ptr != NULL) { | |
222 | uv__free(alloc_ptr); | |
223 | } | |
219 | uv__free(alloc_ptr); | |
224 | 220 | } |
225 | 221 | |
226 | 222 | |
353 | 349 | } |
354 | 350 | |
355 | 351 | error: |
356 | if (req != NULL && req->alloc != NULL) { | |
352 | if (req != NULL) { | |
357 | 353 | uv__free(req->alloc); |
354 | req->alloc = NULL; | |
358 | 355 | } |
359 | 356 | return uv_translate_sys_error(err); |
360 | 357 | } |
326 | 326 | |
327 | 327 | uint64_t uv__hrtime(double scale); |
328 | 328 | int uv_parent_pid(); |
329 | int uv_current_pid(); | |
329 | 330 | __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); |
330 | 331 | |
331 | 332 |
84 | 84 | |
85 | 85 | |
86 | 86 | static void uv_unique_pipe_name(char* ptr, char* name, size_t size) { |
87 | _snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId()); | |
87 | snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId()); | |
88 | 88 | } |
89 | 89 | |
90 | 90 | |
1245 | 1245 | if (send_handle) { |
1246 | 1246 | tcp_send_handle = (uv_tcp_t*)send_handle; |
1247 | 1247 | |
1248 | if (handle->pipe.conn.ipc_pid == 0) { | |
1249 | handle->pipe.conn.ipc_pid = uv_current_pid(); | |
1250 | } | |
1251 | ||
1248 | 1252 | err = uv_tcp_duplicate_socket(tcp_send_handle, handle->pipe.conn.ipc_pid, |
1249 | 1253 | &ipc_frame.socket_info_ex.socket_info); |
1250 | 1254 | if (err) { |
1628 | 1632 | |
1629 | 1633 | if (ReadFile(handle->handle, |
1630 | 1634 | buf.base, |
1631 | buf.len, | |
1635 | min(buf.len, avail), | |
1632 | 1636 | &bytes, |
1633 | 1637 | NULL)) { |
1634 | 1638 | /* Successful read */ |
0 | /* Copyright the libuv project contributors. All rights reserved. | |
1 | * | |
2 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | * of this software and associated documentation files (the "Software"), to | |
4 | * deal in the Software without restriction, including without limitation the | |
5 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | |
6 | * sell copies of the Software, and to permit persons to whom the Software is | |
7 | * furnished to do so, subject to the following conditions: | |
8 | * | |
9 | * The above copyright notice and this permission notice shall be included in | |
10 | * all copies or substantial portions of the Software. | |
11 | * | |
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
17 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
18 | * IN THE SOFTWARE. | |
19 | */ | |
20 | ||
21 | #if defined(_MSC_VER) && _MSC_VER < 1900 | |
22 | ||
23 | #include <stdio.h> | |
24 | #include <stdarg.h> | |
25 | ||
26 | /* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer | |
27 | * on overflow... | |
28 | */ | |
29 | int snprintf(char* buf, size_t len, const char* fmt, ...) { | |
30 | int n; | |
31 | va_list ap; | |
32 | va_start(ap, fmt); | |
33 | ||
34 | n = _vscprintf(fmt, ap); | |
35 | vsnprintf_s(buf, len, _TRUNCATE, fmt, ap); | |
36 | ||
37 | va_end(ap); | |
38 | return n; | |
39 | } | |
40 | ||
41 | #endif |
207 | 207 | static int style_captured = 0; |
208 | 208 | |
209 | 209 | /* Only do this once. |
210 | /* Assumption: Caller has acquired uv_tty_output_lock. */ | |
210 | Assumption: Caller has acquired uv_tty_output_lock. */ | |
211 | 211 | if (style_captured) |
212 | 212 | return; |
213 | 213 |
58 | 58 | static char *process_title; |
59 | 59 | static CRITICAL_SECTION process_title_lock; |
60 | 60 | |
61 | /* Cached copy of the process id, written once. */ | |
62 | static DWORD current_pid = 0; | |
63 | ||
64 | ||
61 | 65 | /* Interval (in seconds) of the high-resolution clock. */ |
62 | 66 | static double hrtime_interval_ = 0; |
63 | 67 | |
355 | 359 | |
356 | 360 | CloseHandle(handle); |
357 | 361 | return parent_pid; |
362 | } | |
363 | ||
364 | ||
365 | int uv_current_pid() { | |
366 | if (current_pid == 0) { | |
367 | current_pid = GetCurrentProcessId(); | |
368 | } | |
369 | return current_pid; | |
358 | 370 | } |
359 | 371 | |
360 | 372 |
45 | 45 | sWakeAllConditionVariable pWakeAllConditionVariable; |
46 | 46 | sWakeConditionVariable pWakeConditionVariable; |
47 | 47 | sCancelSynchronousIo pCancelSynchronousIo; |
48 | sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; | |
48 | 49 | |
49 | 50 | |
50 | 51 | void uv_winapi_init() { |
138 | 139 | |
139 | 140 | pCancelSynchronousIo = (sCancelSynchronousIo) |
140 | 141 | GetProcAddress(kernel32_module, "CancelSynchronousIo"); |
142 | ||
143 | pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW) | |
144 | GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW"); | |
141 | 145 | } |
4677 | 4677 | typedef BOOL (WINAPI* sCancelSynchronousIo) |
4678 | 4678 | (HANDLE hThread); |
4679 | 4679 | |
4680 | typedef DWORD (WINAPI* sGetFinalPathNameByHandleW) | |
4681 | (HANDLE hFile, | |
4682 | LPWSTR lpszFilePath, | |
4683 | DWORD cchFilePath, | |
4684 | DWORD dwFlags); | |
4685 | ||
4680 | 4686 | /* Ntdll function pointers */ |
4681 | 4687 | extern sRtlNtStatusToDosError pRtlNtStatusToDosError; |
4682 | 4688 | extern sNtDeviceIoControlFile pNtDeviceIoControlFile; |
4698 | 4704 | extern sWakeAllConditionVariable pWakeAllConditionVariable; |
4699 | 4705 | extern sWakeConditionVariable pWakeConditionVariable; |
4700 | 4706 | extern sCancelSynchronousIo pCancelSynchronousIo; |
4707 | extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; | |
4701 | 4708 | |
4702 | 4709 | #endif /* UV_WIN_WINAPI_H_ */ |
18 | 18 | * IN THE SOFTWARE. |
19 | 19 | */ |
20 | 20 | |
21 | /* Don't complain about _snprintf being insecure. */ | |
22 | #define _CRT_SECURE_NO_WARNINGS | |
23 | ||
24 | 21 | /* Don't complain about write(), fileno() etc. being deprecated. */ |
25 | 22 | #pragma warning(disable : 4996) |
26 | 23 | |
29 | 26 | #include <windows.h> |
30 | 27 | #include <stdio.h> |
31 | 28 | |
32 | ||
33 | /* Windows has no snprintf, only _snprintf. */ | |
34 | #define snprintf _snprintf | |
35 | ||
29 | #if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900 | |
30 | extern int snprintf(char*, size_t, const char*, ...); | |
31 | #endif | |
36 | 32 | |
37 | 33 | typedef struct { |
38 | 34 | HANDLE process; |
209 | 209 | #ifndef _WIN32 |
210 | 210 | /* Clean up stale socket from previous run. */ |
211 | 211 | remove(TEST_PIPENAME); |
212 | remove(TEST_PIPENAME_2); | |
213 | remove(TEST_PIPENAME_3); | |
212 | 214 | #endif |
213 | 215 | |
214 | 216 | /* If it's a helper the user asks for, start it directly. */ |
49 | 49 | #ifdef _WIN32 |
50 | 50 | # define TEST_PIPENAME "\\\\?\\pipe\\uv-test" |
51 | 51 | # define TEST_PIPENAME_2 "\\\\?\\pipe\\uv-test2" |
52 | # define TEST_PIPENAME_3 "\\\\?\\pipe\\uv-test3" | |
52 | 53 | #else |
53 | 54 | # define TEST_PIPENAME "/tmp/uv-test-sock" |
54 | 55 | # define TEST_PIPENAME_2 "/tmp/uv-test-sock2" |
56 | # define TEST_PIPENAME_3 "/tmp/uv-test-sock3" | |
55 | 57 | #endif |
56 | 58 | |
57 | 59 | #ifdef _WIN32 |
173 | 175 | |
174 | 176 | #endif |
175 | 177 | |
176 | ||
177 | #if defined _WIN32 && ! defined __GNUC__ | |
178 | ||
179 | #include <stdarg.h> | |
180 | ||
181 | /* Define inline for MSVC<2015 */ | |
182 | # if defined(_MSC_VER) && _MSC_VER < 1900 | |
183 | # define inline __inline | |
184 | # endif | |
185 | ||
186 | # if defined(_MSC_VER) && _MSC_VER < 1900 | |
187 | /* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer | |
188 | * on overflow... | |
189 | */ | |
190 | inline int snprintf(char* buf, size_t len, const char* fmt, ...) { | |
191 | va_list ap; | |
192 | int n; | |
193 | ||
194 | va_start(ap, fmt); | |
195 | n = _vsprintf_p(buf, len, fmt, ap); | |
196 | va_end(ap); | |
197 | ||
198 | /* It's a sad fact of life that no one ever checks the return value of | |
199 | * snprintf(). Zero-terminating the buffer hopefully reduces the risk | |
200 | * of gaping security holes. | |
201 | */ | |
202 | if (n < 0) | |
203 | if (len > 0) | |
204 | buf[0] = '\0'; | |
205 | ||
206 | return n; | |
207 | } | |
208 | # endif | |
209 | ||
178 | #if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900 | |
179 | extern int snprintf(char*, size_t, const char*, ...); | |
210 | 180 | #endif |
211 | 181 | |
212 | 182 | #if defined(__clang__) || \ |
24 | 24 | #include "task.h" |
25 | 25 | |
26 | 26 | #include <errno.h> |
27 | #include <stdio.h> | |
28 | 27 | #include <sys/resource.h> |
29 | 28 | #include <unistd.h> |
30 | 29 | |
44 | 43 | uv_loop_t* loop; |
45 | 44 | int first_fd; |
46 | 45 | |
46 | /* Lower the file descriptor limit and use up all fds save one. */ | |
47 | limits.rlim_cur = limits.rlim_max = maxfd + 1; | |
48 | if (setrlimit(RLIMIT_NOFILE, &limits)) { | |
49 | ASSERT(errno == EPERM); /* Valgrind blocks the setrlimit() call. */ | |
50 | RETURN_SKIP("setrlimit(RLIMIT_NOFILE) failed, running under valgrind?"); | |
51 | } | |
52 | ||
47 | 53 | loop = uv_default_loop(); |
48 | 54 | ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); |
49 | 55 | ASSERT(0 == uv_tcp_init(loop, &server_handle)); |
50 | 56 | ASSERT(0 == uv_tcp_init(loop, &client_handle)); |
51 | 57 | ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0)); |
52 | 58 | ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 8, connection_cb)); |
53 | ||
54 | /* Lower the file descriptor limit and use up all fds save one. */ | |
55 | limits.rlim_cur = limits.rlim_max = maxfd + 1; | |
56 | if (setrlimit(RLIMIT_NOFILE, &limits)) { | |
57 | perror("setrlimit(RLIMIT_NOFILE)"); | |
58 | ASSERT(0); | |
59 | } | |
60 | 59 | |
61 | 60 | /* Remember the first one so we can clean up afterwards. */ |
62 | 61 | do |
114 | 114 | ASSERT(handle == &fs_event); |
115 | 115 | ASSERT(status == 0); |
116 | 116 | ASSERT(events == UV_RENAME); |
117 | #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) | |
118 | ASSERT(strcmp(filename, "file1") == 0); | |
119 | #else | |
117 | 120 | ASSERT(filename == NULL || strcmp(filename, "file1") == 0); |
121 | #endif | |
118 | 122 | ASSERT(0 == uv_fs_event_stop(handle)); |
119 | 123 | uv_close((uv_handle_t*)handle, close_cb); |
120 | 124 | } |
177 | 181 | ASSERT(handle == &fs_event); |
178 | 182 | ASSERT(status == 0); |
179 | 183 | ASSERT(events == UV_CHANGE || UV_RENAME); |
184 | #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) | |
185 | ASSERT(strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0); | |
186 | #else | |
180 | 187 | ASSERT(filename == NULL || |
181 | 188 | strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0); |
189 | #endif | |
182 | 190 | |
183 | 191 | if (fs_event_created + fs_event_removed == fs_event_file_count) { |
184 | 192 | /* Once we've processed all create events, delete all files */ |
249 | 257 | ASSERT(handle == &fs_event); |
250 | 258 | ASSERT(status == 0); |
251 | 259 | ASSERT(events == UV_CHANGE || UV_RENAME); |
260 | #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) | |
261 | ASSERT(strncmp(filename, | |
262 | file_prefix_in_subdir, | |
263 | sizeof(file_prefix_in_subdir) - 1) == 0); | |
264 | #else | |
252 | 265 | ASSERT(filename == NULL || |
253 | strncmp(filename, file_prefix_in_subdir, sizeof(file_prefix_in_subdir) - 1) == 0); | |
266 | strncmp(filename, | |
267 | file_prefix_in_subdir, | |
268 | sizeof(file_prefix_in_subdir) - 1) == 0); | |
269 | #endif | |
254 | 270 | |
255 | 271 | if (fs_event_created + fs_event_removed == fs_event_file_count) { |
256 | 272 | /* Once we've processed all create events, delete all files */ |
269 | 285 | ASSERT(handle == &fs_event); |
270 | 286 | ASSERT(status == 0); |
271 | 287 | ASSERT(events == UV_CHANGE); |
288 | #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) | |
289 | ASSERT(strcmp(filename, "file2") == 0); | |
290 | #else | |
272 | 291 | ASSERT(filename == NULL || strcmp(filename, "file2") == 0); |
292 | #endif | |
273 | 293 | ASSERT(0 == uv_fs_event_stop(handle)); |
274 | 294 | uv_close((uv_handle_t*)handle, close_cb); |
275 | 295 | } |
292 | 312 | ASSERT(handle == &fs_event); |
293 | 313 | ASSERT(status == 0); |
294 | 314 | ASSERT(events == UV_CHANGE); |
315 | #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) | |
316 | ASSERT(strcmp(filename, "watch_file") == 0); | |
317 | #else | |
295 | 318 | ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0); |
319 | #endif | |
296 | 320 | |
297 | 321 | /* Regression test for SunOS: touch should generate just one event. */ |
298 | 322 | { |
486 | 510 | r = uv_timer_init(loop, &timer); |
487 | 511 | ASSERT(r == 0); |
488 | 512 | |
489 | r = uv_timer_start(&timer, timer_cb_touch, 1, 0); | |
513 | r = uv_timer_start(&timer, timer_cb_touch, 10, 0); | |
490 | 514 | ASSERT(r == 0); |
491 | 515 | |
492 | 516 | ASSERT(timer_cb_touch_called == 0); |
82 | 82 | static int link_cb_count; |
83 | 83 | static int symlink_cb_count; |
84 | 84 | static int readlink_cb_count; |
85 | static int realpath_cb_count; | |
85 | 86 | static int utime_cb_count; |
86 | 87 | static int futime_cb_count; |
87 | 88 | |
163 | 164 | ASSERT(req->result == 0); |
164 | 165 | ASSERT(strcmp(req->ptr, "test_file_symlink2") == 0); |
165 | 166 | readlink_cb_count++; |
167 | uv_fs_req_cleanup(req); | |
168 | } | |
169 | ||
170 | ||
171 | static void realpath_cb(uv_fs_t* req) { | |
172 | char test_file_abs_buf[PATHMAX]; | |
173 | size_t test_file_abs_size = sizeof(test_file_abs_buf); | |
174 | ASSERT(req->fs_type == UV_FS_REALPATH); | |
175 | #ifdef _WIN32 | |
176 | /* | |
177 | * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() | |
178 | */ | |
179 | if (req->result == UV_ENOSYS) { | |
180 | realpath_cb_count++; | |
181 | uv_fs_req_cleanup(req); | |
182 | return; | |
183 | } | |
184 | #endif | |
185 | ASSERT(req->result == 0); | |
186 | ||
187 | uv_cwd(test_file_abs_buf, &test_file_abs_size); | |
188 | #ifdef _WIN32 | |
189 | strcat(test_file_abs_buf, "\\test_file"); | |
190 | ASSERT(stricmp(req->ptr, test_file_abs_buf) == 0); | |
191 | #else | |
192 | strcat(test_file_abs_buf, "/test_file"); | |
193 | ASSERT(strcmp(req->ptr, test_file_abs_buf) == 0); | |
194 | #endif | |
195 | realpath_cb_count++; | |
166 | 196 | uv_fs_req_cleanup(req); |
167 | 197 | } |
168 | 198 | |
1564 | 1594 | } |
1565 | 1595 | |
1566 | 1596 | |
1597 | TEST_IMPL(fs_realpath) { | |
1598 | uv_fs_t req; | |
1599 | ||
1600 | loop = uv_default_loop(); | |
1601 | ASSERT(0 == uv_fs_realpath(loop, &req, "no_such_file", dummy_cb)); | |
1602 | ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); | |
1603 | ASSERT(dummy_cb_count == 1); | |
1604 | ASSERT(req.ptr == NULL); | |
1605 | #ifdef _WIN32 | |
1606 | /* | |
1607 | * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() | |
1608 | */ | |
1609 | if (req.result == UV_ENOSYS) { | |
1610 | uv_fs_req_cleanup(&req); | |
1611 | RETURN_SKIP("realpath is not supported on Windows XP"); | |
1612 | } | |
1613 | #endif | |
1614 | ASSERT(req.result == UV_ENOENT); | |
1615 | uv_fs_req_cleanup(&req); | |
1616 | ||
1617 | ASSERT(UV_ENOENT == uv_fs_realpath(NULL, &req, "no_such_file", NULL)); | |
1618 | ASSERT(req.ptr == NULL); | |
1619 | ASSERT(req.result == UV_ENOENT); | |
1620 | uv_fs_req_cleanup(&req); | |
1621 | ||
1622 | MAKE_VALGRIND_HAPPY(); | |
1623 | return 0; | |
1624 | } | |
1625 | ||
1626 | ||
1567 | 1627 | TEST_IMPL(fs_symlink) { |
1568 | 1628 | int r; |
1569 | 1629 | uv_fs_t req; |
1570 | 1630 | uv_file file; |
1571 | 1631 | uv_file link; |
1632 | char test_file_abs_buf[PATHMAX]; | |
1633 | size_t test_file_abs_size; | |
1572 | 1634 | |
1573 | 1635 | /* Setup. */ |
1574 | 1636 | unlink("test_file"); |
1576 | 1638 | unlink("test_file_symlink2"); |
1577 | 1639 | unlink("test_file_symlink_symlink"); |
1578 | 1640 | unlink("test_file_symlink2_symlink"); |
1641 | test_file_abs_size = sizeof(test_file_abs_buf); | |
1642 | #ifdef _WIN32 | |
1643 | uv_cwd(test_file_abs_buf, &test_file_abs_size); | |
1644 | strcat(test_file_abs_buf, "\\test_file"); | |
1645 | #else | |
1646 | uv_cwd(test_file_abs_buf, &test_file_abs_size); | |
1647 | strcat(test_file_abs_buf, "/test_file"); | |
1648 | #endif | |
1579 | 1649 | |
1580 | 1650 | loop = uv_default_loop(); |
1581 | 1651 | |
1646 | 1716 | ASSERT(strcmp(req.ptr, "test_file_symlink") == 0); |
1647 | 1717 | uv_fs_req_cleanup(&req); |
1648 | 1718 | |
1719 | r = uv_fs_realpath(NULL, &req, "test_file_symlink_symlink", NULL); | |
1720 | #ifdef _WIN32 | |
1721 | /* | |
1722 | * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() | |
1723 | */ | |
1724 | if (r == UV_ENOSYS) { | |
1725 | uv_fs_req_cleanup(&req); | |
1726 | RETURN_SKIP("realpath is not supported on Windows XP"); | |
1727 | } | |
1728 | #endif | |
1729 | ASSERT(r == 0); | |
1730 | #ifdef _WIN32 | |
1731 | ASSERT(stricmp(req.ptr, test_file_abs_buf) == 0); | |
1732 | #else | |
1733 | ASSERT(strcmp(req.ptr, test_file_abs_buf) == 0); | |
1734 | #endif | |
1735 | uv_fs_req_cleanup(&req); | |
1736 | ||
1649 | 1737 | /* async link */ |
1650 | 1738 | r = uv_fs_symlink(loop, |
1651 | 1739 | &req, |
1686 | 1774 | uv_run(loop, UV_RUN_DEFAULT); |
1687 | 1775 | ASSERT(readlink_cb_count == 1); |
1688 | 1776 | |
1777 | r = uv_fs_realpath(loop, &req, "test_file", realpath_cb); | |
1778 | #ifdef _WIN32 | |
1779 | /* | |
1780 | * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() | |
1781 | */ | |
1782 | if (r == UV_ENOSYS) { | |
1783 | uv_fs_req_cleanup(&req); | |
1784 | RETURN_SKIP("realpath is not supported on Windows XP"); | |
1785 | } | |
1786 | #endif | |
1787 | ASSERT(r == 0); | |
1788 | uv_run(loop, UV_RUN_DEFAULT); | |
1789 | ASSERT(realpath_cb_count == 1); | |
1790 | ||
1689 | 1791 | /* |
1690 | 1792 | * Run the loop just to check we don't have make any extraneous uv_ref() |
1691 | 1793 | * calls. This should drop out immediately. |
1709 | 1811 | int r; |
1710 | 1812 | char* test_dir; |
1711 | 1813 | uv_dirent_t dent; |
1814 | static char test_dir_abs_buf[PATHMAX]; | |
1815 | size_t test_dir_abs_size; | |
1712 | 1816 | |
1713 | 1817 | /* set-up */ |
1714 | 1818 | unlink("test_dir/file1"); |
1715 | 1819 | unlink("test_dir/file2"); |
1716 | 1820 | rmdir("test_dir"); |
1717 | 1821 | rmdir("test_dir_symlink"); |
1822 | test_dir_abs_size = sizeof(test_dir_abs_buf); | |
1718 | 1823 | |
1719 | 1824 | loop = uv_default_loop(); |
1720 | 1825 | |
1722 | 1827 | uv_fs_req_cleanup(&req); |
1723 | 1828 | |
1724 | 1829 | #ifdef _WIN32 |
1725 | { | |
1726 | static char src_path_buf[PATHMAX]; | |
1727 | size_t size; | |
1728 | size = sizeof(src_path_buf); | |
1729 | strcpy(src_path_buf, "\\\\?\\"); | |
1730 | uv_cwd(src_path_buf + 4, &size); | |
1731 | strcat(src_path_buf, "\\test_dir\\"); | |
1732 | test_dir = src_path_buf; | |
1733 | } | |
1830 | strcpy(test_dir_abs_buf, "\\\\?\\"); | |
1831 | uv_cwd(test_dir_abs_buf + 4, &test_dir_abs_size); | |
1832 | test_dir_abs_size += 4; | |
1833 | strcat(test_dir_abs_buf, "\\test_dir\\"); | |
1834 | test_dir_abs_size += strlen("\\test_dir\\"); | |
1835 | test_dir = test_dir_abs_buf; | |
1734 | 1836 | #else |
1837 | uv_cwd(test_dir_abs_buf, &test_dir_abs_size); | |
1838 | strcat(test_dir_abs_buf, "/test_dir"); | |
1839 | test_dir_abs_size += strlen("/test_dir"); | |
1735 | 1840 | test_dir = "test_dir"; |
1736 | 1841 | #endif |
1737 | 1842 | |
1763 | 1868 | ASSERT(strcmp(req.ptr, test_dir + 4) == 0); |
1764 | 1869 | #else |
1765 | 1870 | ASSERT(strcmp(req.ptr, test_dir) == 0); |
1871 | #endif | |
1872 | uv_fs_req_cleanup(&req); | |
1873 | ||
1874 | r = uv_fs_realpath(NULL, &req, "test_dir_symlink", NULL); | |
1875 | #ifdef _WIN32 | |
1876 | /* | |
1877 | * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() | |
1878 | */ | |
1879 | if (r == UV_ENOSYS) { | |
1880 | uv_fs_req_cleanup(&req); | |
1881 | RETURN_SKIP("realpath is not supported on Windows XP"); | |
1882 | } | |
1883 | #endif | |
1884 | ASSERT(r == 0); | |
1885 | #ifdef _WIN32 | |
1886 | ASSERT(strlen(req.ptr) == test_dir_abs_size - 5); | |
1887 | ASSERT(strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 5) == 0); | |
1888 | #else | |
1889 | ASSERT(strcmp(req.ptr, test_dir_abs_buf) == 0); | |
1766 | 1890 | #endif |
1767 | 1891 | uv_fs_req_cleanup(&req); |
1768 | 1892 |
23 | 23 | |
24 | 24 | TEST_IMPL(get_loadavg) { |
25 | 25 | |
26 | double avg[3]; | |
26 | double avg[3] = {-1, -1, -1}; | |
27 | 27 | uv_loadavg(avg); |
28 | 28 | |
29 | ASSERT(avg != NULL); | |
30 | 29 | ASSERT(avg[0] >= 0); |
31 | 30 | ASSERT(avg[1] >= 0); |
32 | 31 | ASSERT(avg[2] >= 0); |
82 | 82 | TEST_IMPL(getaddrinfo_fail) { |
83 | 83 | uv_getaddrinfo_t req; |
84 | 84 | |
85 | /* Use a FQDN by ending in a period */ | |
85 | 86 | ASSERT(0 == uv_getaddrinfo(uv_default_loop(), |
86 | 87 | &req, |
87 | 88 | getaddrinfo_fail_cb, |
88 | "xyzzy.xyzzy.xyzzy", | |
89 | "xyzzy.xyzzy.xyzzy.", | |
89 | 90 | NULL, |
90 | 91 | NULL)); |
91 | 92 | ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); |
99 | 100 | TEST_IMPL(getaddrinfo_fail_sync) { |
100 | 101 | uv_getaddrinfo_t req; |
101 | 102 | |
103 | /* Use a FQDN by ending in a period */ | |
102 | 104 | ASSERT(0 > uv_getaddrinfo(uv_default_loop(), |
103 | 105 | &req, |
104 | 106 | NULL, |
105 | "xyzzy.xyzzy.xyzzy", | |
107 | "xyzzy.xyzzy.xyzzy.", | |
106 | 108 | NULL, |
107 | 109 | NULL)); |
108 | 110 | uv_freeaddrinfo(req.addrinfo); |
72 | 72 | NULL, |
73 | 73 | (const struct sockaddr*)&addr4, |
74 | 74 | 0)); |
75 | ASSERT(req.host != NULL); | |
76 | ASSERT(req.service != NULL); | |
75 | ASSERT(req.host[0] != '\0'); | |
76 | ASSERT(req.service[0] != '\0'); | |
77 | 77 | |
78 | 78 | MAKE_VALGRIND_HAPPY(); |
79 | 79 | return 0; |
29 | 29 | uv_process_t* process, |
30 | 30 | const char* helper); |
31 | 31 | |
32 | void ipc_send_recv_helper_threadproc(void* arg); | |
33 | ||
32 | 34 | union handles { |
33 | 35 | uv_handle_t handle; |
34 | 36 | uv_stream_t stream; |
37 | 39 | uv_tty_t tty; |
38 | 40 | }; |
39 | 41 | |
42 | struct test_ctx { | |
43 | uv_pipe_t channel; | |
44 | uv_connect_t connect_req; | |
45 | uv_write_t write_req; | |
46 | uv_write_t write_req2; | |
47 | uv_handle_type expected_type; | |
48 | union handles send; | |
49 | union handles send2; | |
50 | union handles recv; | |
51 | union handles recv2; | |
52 | }; | |
53 | ||
40 | 54 | struct echo_ctx { |
55 | uv_pipe_t listen; | |
41 | 56 | uv_pipe_t channel; |
42 | 57 | uv_write_t write_req; |
58 | uv_write_t write_req2; | |
43 | 59 | uv_handle_type expected_type; |
44 | union handles send; | |
45 | 60 | union handles recv; |
61 | union handles recv2; | |
46 | 62 | }; |
47 | 63 | |
48 | static struct echo_ctx ctx; | |
49 | static int num_recv_handles; | |
64 | static struct test_ctx ctx; | |
65 | static struct echo_ctx ctx2; | |
66 | ||
67 | /* Used in write2_cb to decide if we need to cleanup or not */ | |
68 | static int is_child_process; | |
69 | static int is_in_process; | |
70 | static int read_cb_called; | |
71 | static int recv_cb_called; | |
72 | static int write2_cb_called; | |
50 | 73 | |
51 | 74 | |
52 | 75 | static void alloc_cb(uv_handle_t* handle, |
65 | 88 | uv_handle_type pending; |
66 | 89 | uv_pipe_t* pipe; |
67 | 90 | int r; |
91 | union handles* recv; | |
92 | ||
93 | if (++recv_cb_called == 1) { | |
94 | recv = &ctx.recv; | |
95 | } else { | |
96 | recv = &ctx.recv2; | |
97 | } | |
68 | 98 | |
69 | 99 | pipe = (uv_pipe_t*) handle; |
70 | 100 | ASSERT(pipe == &ctx.channel); |
71 | ASSERT(nread >= 0); | |
72 | ASSERT(1 == uv_pipe_pending_count(pipe)); | |
73 | ||
74 | pending = uv_pipe_pending_type(pipe); | |
75 | ASSERT(pending == ctx.expected_type); | |
76 | ||
77 | if (pending == UV_NAMED_PIPE) | |
78 | r = uv_pipe_init(ctx.channel.loop, &ctx.recv.pipe, 0); | |
79 | else if (pending == UV_TCP) | |
80 | r = uv_tcp_init(ctx.channel.loop, &ctx.recv.tcp); | |
81 | else | |
82 | abort(); | |
83 | ASSERT(r == 0); | |
84 | ||
85 | r = uv_accept(handle, &ctx.recv.stream); | |
86 | ASSERT(r == 0); | |
87 | ||
88 | uv_close((uv_handle_t*)&ctx.channel, NULL); | |
89 | uv_close(&ctx.send.handle, NULL); | |
90 | uv_close(&ctx.recv.handle, NULL); | |
91 | num_recv_handles++; | |
92 | } | |
93 | ||
94 | ||
95 | static int run_test(void) { | |
96 | uv_process_t process; | |
101 | ||
102 | /* Depending on the OS, the final recv_cb can be called after the child | |
103 | * process has terminated which can result in nread being UV_EOF instead of | |
104 | * the number of bytes read. Since the other end of the pipe has closed this | |
105 | * UV_EOF is an acceptable value. */ | |
106 | if (nread == UV_EOF) { | |
107 | /* UV_EOF is only acceptable for the final recv_cb call */ | |
108 | ASSERT(recv_cb_called == 2); | |
109 | } else { | |
110 | ASSERT(nread >= 0); | |
111 | ASSERT(1 == uv_pipe_pending_count(pipe)); | |
112 | ||
113 | pending = uv_pipe_pending_type(pipe); | |
114 | ASSERT(pending == ctx.expected_type); | |
115 | ||
116 | if (pending == UV_NAMED_PIPE) | |
117 | r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0); | |
118 | else if (pending == UV_TCP) | |
119 | r = uv_tcp_init(ctx.channel.loop, &recv->tcp); | |
120 | else | |
121 | abort(); | |
122 | ASSERT(r == 0); | |
123 | ||
124 | r = uv_accept(handle, &recv->stream); | |
125 | ASSERT(r == 0); | |
126 | } | |
127 | ||
128 | /* Close after two writes received */ | |
129 | if (recv_cb_called == 2) { | |
130 | uv_close((uv_handle_t*)&ctx.channel, NULL); | |
131 | } | |
132 | } | |
133 | ||
134 | static void connect_cb(uv_connect_t* req, int status) { | |
135 | int r; | |
97 | 136 | uv_buf_t buf; |
98 | int r; | |
99 | ||
100 | spawn_helper(&ctx.channel, &process, "ipc_send_recv_helper"); | |
137 | ||
138 | ASSERT(req == &ctx.connect_req); | |
139 | ASSERT(status == 0); | |
101 | 140 | |
102 | 141 | buf = uv_buf_init(".", 1); |
103 | 142 | r = uv_write2(&ctx.write_req, |
107 | 146 | NULL); |
108 | 147 | ASSERT(r == 0); |
109 | 148 | |
149 | /* Perform two writes to the same pipe to make sure that on Windows we are | |
150 | * not running into issue 505: | |
151 | * https://github.com/libuv/libuv/issues/505 */ | |
152 | buf = uv_buf_init(".", 1); | |
153 | r = uv_write2(&ctx.write_req2, | |
154 | (uv_stream_t*)&ctx.channel, | |
155 | &buf, 1, | |
156 | &ctx.send2.stream, | |
157 | NULL); | |
158 | ASSERT(r == 0); | |
159 | ||
110 | 160 | r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, recv_cb); |
111 | 161 | ASSERT(r == 0); |
162 | } | |
163 | ||
164 | static int run_test(int inprocess) { | |
165 | uv_process_t process; | |
166 | uv_thread_t tid; | |
167 | int r; | |
168 | ||
169 | if (inprocess) { | |
170 | r = uv_thread_create(&tid, ipc_send_recv_helper_threadproc, (void *) 42); | |
171 | ASSERT(r == 0); | |
172 | ||
173 | uv_sleep(1000); | |
174 | ||
175 | r = uv_pipe_init(uv_default_loop(), &ctx.channel, 1); | |
176 | ASSERT(r == 0); | |
177 | ||
178 | uv_pipe_connect(&ctx.connect_req, &ctx.channel, TEST_PIPENAME_3, connect_cb); | |
179 | } else { | |
180 | spawn_helper(&ctx.channel, &process, "ipc_send_recv_helper"); | |
181 | ||
182 | connect_cb(&ctx.connect_req, 0); | |
183 | } | |
112 | 184 | |
113 | 185 | r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); |
114 | 186 | ASSERT(r == 0); |
115 | 187 | |
116 | ASSERT(num_recv_handles == 1); | |
188 | ASSERT(recv_cb_called == 2); | |
189 | ||
190 | if (inprocess) { | |
191 | r = uv_thread_join(&tid); | |
192 | ASSERT(r == 0); | |
193 | } | |
117 | 194 | |
118 | 195 | return 0; |
119 | 196 | } |
120 | 197 | |
121 | ||
122 | TEST_IMPL(ipc_send_recv_pipe) { | |
198 | static int run_ipc_send_recv_pipe(int inprocess) { | |
123 | 199 | int r; |
124 | 200 | |
125 | 201 | ctx.expected_type = UV_NAMED_PIPE; |
130 | 206 | r = uv_pipe_bind(&ctx.send.pipe, TEST_PIPENAME); |
131 | 207 | ASSERT(r == 0); |
132 | 208 | |
133 | r = run_test(); | |
209 | r = uv_pipe_init(uv_default_loop(), &ctx.send2.pipe, 1); | |
210 | ASSERT(r == 0); | |
211 | ||
212 | r = uv_pipe_bind(&ctx.send2.pipe, TEST_PIPENAME_2); | |
213 | ASSERT(r == 0); | |
214 | ||
215 | r = run_test(inprocess); | |
134 | 216 | ASSERT(r == 0); |
135 | 217 | |
136 | 218 | MAKE_VALGRIND_HAPPY(); |
137 | 219 | return 0; |
138 | 220 | } |
139 | 221 | |
140 | ||
141 | TEST_IMPL(ipc_send_recv_tcp) { | |
222 | TEST_IMPL(ipc_send_recv_pipe) { | |
223 | return run_ipc_send_recv_pipe(0); | |
224 | } | |
225 | ||
226 | TEST_IMPL(ipc_send_recv_pipe_inprocess) { | |
227 | return run_ipc_send_recv_pipe(1); | |
228 | } | |
229 | ||
230 | static int run_ipc_send_recv_tcp(int inprocess) { | |
142 | 231 | struct sockaddr_in addr; |
143 | 232 | int r; |
144 | 233 | |
149 | 238 | r = uv_tcp_init(uv_default_loop(), &ctx.send.tcp); |
150 | 239 | ASSERT(r == 0); |
151 | 240 | |
241 | r = uv_tcp_init(uv_default_loop(), &ctx.send2.tcp); | |
242 | ASSERT(r == 0); | |
243 | ||
152 | 244 | r = uv_tcp_bind(&ctx.send.tcp, (const struct sockaddr*) &addr, 0); |
153 | 245 | ASSERT(r == 0); |
154 | 246 | |
155 | r = run_test(); | |
247 | r = uv_tcp_bind(&ctx.send2.tcp, (const struct sockaddr*) &addr, 0); | |
248 | ASSERT(r == 0); | |
249 | ||
250 | r = run_test(inprocess); | |
156 | 251 | ASSERT(r == 0); |
157 | 252 | |
158 | 253 | MAKE_VALGRIND_HAPPY(); |
159 | 254 | return 0; |
160 | 255 | } |
161 | 256 | |
162 | ||
163 | /* Everything here runs in a child process. */ | |
257 | TEST_IMPL(ipc_send_recv_tcp) { | |
258 | return run_ipc_send_recv_tcp(0); | |
259 | } | |
260 | ||
261 | TEST_IMPL(ipc_send_recv_tcp_inprocess) { | |
262 | return run_ipc_send_recv_tcp(1); | |
263 | } | |
264 | ||
265 | ||
266 | /* Everything here runs in a child process or second thread. */ | |
164 | 267 | |
165 | 268 | static void write2_cb(uv_write_t* req, int status) { |
166 | 269 | ASSERT(status == 0); |
167 | uv_close(&ctx.recv.handle, NULL); | |
168 | uv_close((uv_handle_t*)&ctx.channel, NULL); | |
169 | } | |
170 | ||
270 | ||
271 | /* After two successful writes in the child process, allow the child | |
272 | * process to be closed. */ | |
273 | if (++write2_cb_called == 2 && (is_child_process || is_in_process)) { | |
274 | uv_close(&ctx2.recv.handle, NULL); | |
275 | uv_close(&ctx2.recv2.handle, NULL); | |
276 | uv_close((uv_handle_t*)&ctx2.channel, NULL); | |
277 | uv_close((uv_handle_t*)&ctx2.listen, NULL); | |
278 | } | |
279 | } | |
171 | 280 | |
172 | 281 | static void read_cb(uv_stream_t* handle, |
173 | 282 | ssize_t nread, |
176 | 285 | uv_pipe_t* pipe; |
177 | 286 | uv_handle_type pending; |
178 | 287 | int r; |
288 | union handles* recv; | |
289 | uv_write_t* write_req; | |
290 | ||
291 | if (nread == UV__EOF || nread == UV__ECONNABORTED) { | |
292 | return; | |
293 | } | |
294 | ||
295 | if (++read_cb_called == 2) { | |
296 | recv = &ctx2.recv; | |
297 | write_req = &ctx2.write_req; | |
298 | } else { | |
299 | recv = &ctx2.recv2; | |
300 | write_req = &ctx2.write_req2; | |
301 | } | |
179 | 302 | |
180 | 303 | pipe = (uv_pipe_t*) handle; |
181 | ASSERT(pipe == &ctx.channel); | |
304 | ASSERT(pipe == &ctx2.channel); | |
182 | 305 | ASSERT(nread >= 0); |
183 | 306 | ASSERT(1 == uv_pipe_pending_count(pipe)); |
184 | 307 | |
185 | 308 | pending = uv_pipe_pending_type(pipe); |
186 | 309 | ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP); |
187 | 310 | |
188 | wrbuf = uv_buf_init(".", 1); | |
189 | ||
190 | 311 | if (pending == UV_NAMED_PIPE) |
191 | r = uv_pipe_init(ctx.channel.loop, &ctx.recv.pipe, 0); | |
312 | r = uv_pipe_init(ctx2.channel.loop, &recv->pipe, 0); | |
192 | 313 | else if (pending == UV_TCP) |
193 | r = uv_tcp_init(ctx.channel.loop, &ctx.recv.tcp); | |
314 | r = uv_tcp_init(ctx2.channel.loop, &recv->tcp); | |
194 | 315 | else |
195 | 316 | abort(); |
196 | 317 | ASSERT(r == 0); |
197 | 318 | |
198 | r = uv_accept(handle, &ctx.recv.stream); | |
199 | ASSERT(r == 0); | |
200 | ||
201 | r = uv_write2(&ctx.write_req, | |
202 | (uv_stream_t*)&ctx.channel, | |
319 | r = uv_accept(handle, &recv->stream); | |
320 | ASSERT(r == 0); | |
321 | ||
322 | wrbuf = uv_buf_init(".", 1); | |
323 | r = uv_write2(write_req, | |
324 | (uv_stream_t*)&ctx2.channel, | |
203 | 325 | &wrbuf, |
204 | 326 | 1, |
205 | &ctx.recv.stream, | |
327 | &recv->stream, | |
206 | 328 | write2_cb); |
207 | 329 | ASSERT(r == 0); |
208 | 330 | } |
209 | 331 | |
332 | static void send_recv_start() { | |
333 | int r; | |
334 | ASSERT(1 == uv_is_readable((uv_stream_t*)&ctx2.channel)); | |
335 | ASSERT(1 == uv_is_writable((uv_stream_t*)&ctx2.channel)); | |
336 | ASSERT(0 == uv_is_closing((uv_handle_t*)&ctx2.channel)); | |
337 | ||
338 | r = uv_read_start((uv_stream_t*)&ctx2.channel, alloc_cb, read_cb); | |
339 | ASSERT(r == 0); | |
340 | } | |
341 | ||
342 | static void listen_cb(uv_stream_t* handle, int status) { | |
343 | int r; | |
344 | ASSERT(handle == (uv_stream_t*)&ctx2.listen); | |
345 | ASSERT(status == 0); | |
346 | ||
347 | r = uv_accept((uv_stream_t*)&ctx2.listen, (uv_stream_t*)&ctx2.channel); | |
348 | ASSERT(r == 0); | |
349 | ||
350 | send_recv_start(); | |
351 | } | |
352 | ||
353 | int run_ipc_send_recv_helper(uv_loop_t* loop, int inprocess) { | |
354 | int r; | |
355 | ||
356 | is_in_process = inprocess; | |
357 | ||
358 | memset(&ctx2, 0, sizeof(ctx2)); | |
359 | ||
360 | r = uv_pipe_init(loop, &ctx2.listen, 0); | |
361 | ASSERT(r == 0); | |
362 | ||
363 | r = uv_pipe_init(loop, &ctx2.channel, 1); | |
364 | ASSERT(r == 0); | |
365 | ||
366 | if (inprocess) { | |
367 | r = uv_pipe_bind(&ctx2.listen, TEST_PIPENAME_3); | |
368 | ASSERT(r == 0); | |
369 | ||
370 | r = uv_listen((uv_stream_t*)&ctx2.listen, SOMAXCONN, listen_cb); | |
371 | ASSERT(r == 0); | |
372 | } else { | |
373 | r = uv_pipe_open(&ctx2.channel, 0); | |
374 | ASSERT(r == 0); | |
375 | ||
376 | send_recv_start(); | |
377 | } | |
378 | ||
379 | r = uv_run(loop, UV_RUN_DEFAULT); | |
380 | ASSERT(r == 0); | |
381 | ||
382 | return 0; | |
383 | } | |
210 | 384 | |
211 | 385 | /* stdin is a duplex channel over which a handle is sent. |
212 | 386 | * We receive it and send it back where it came from. |
214 | 388 | int ipc_send_recv_helper(void) { |
215 | 389 | int r; |
216 | 390 | |
217 | memset(&ctx, 0, sizeof(ctx)); | |
218 | ||
219 | r = uv_pipe_init(uv_default_loop(), &ctx.channel, 1); | |
220 | ASSERT(r == 0); | |
221 | ||
222 | uv_pipe_open(&ctx.channel, 0); | |
223 | ASSERT(1 == uv_is_readable((uv_stream_t*)&ctx.channel)); | |
224 | ASSERT(1 == uv_is_writable((uv_stream_t*)&ctx.channel)); | |
225 | ASSERT(0 == uv_is_closing((uv_handle_t*)&ctx.channel)); | |
226 | ||
227 | r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, read_cb); | |
228 | ASSERT(r == 0); | |
229 | ||
230 | r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
391 | r = run_ipc_send_recv_helper(uv_default_loop(), 0); | |
231 | 392 | ASSERT(r == 0); |
232 | 393 | |
233 | 394 | MAKE_VALGRIND_HAPPY(); |
234 | 395 | return 0; |
235 | 396 | } |
397 | ||
398 | void ipc_send_recv_helper_threadproc(void* arg) { | |
399 | int r; | |
400 | uv_loop_t loop; | |
401 | ||
402 | r = uv_loop_init(&loop); | |
403 | ASSERT(r == 0); | |
404 | ||
405 | r = run_ipc_send_recv_helper(&loop, 1); | |
406 | ASSERT(r == 0); | |
407 | ||
408 | r = uv_loop_close(&loop); | |
409 | ASSERT(r == 0); | |
410 | } |
49 | 49 | TEST_DECLARE (ipc_listen_after_write) |
50 | 50 | #ifndef _WIN32 |
51 | 51 | TEST_DECLARE (ipc_send_recv_pipe) |
52 | TEST_DECLARE (ipc_send_recv_pipe_inprocess) | |
52 | 53 | #endif |
53 | 54 | TEST_DECLARE (ipc_send_recv_tcp) |
55 | TEST_DECLARE (ipc_send_recv_tcp_inprocess) | |
54 | 56 | TEST_DECLARE (ipc_tcp_connection) |
55 | 57 | TEST_DECLARE (tcp_ping_pong) |
56 | 58 | TEST_DECLARE (tcp_ping_pong_v6) |
251 | 253 | TEST_DECLARE (fs_chown) |
252 | 254 | TEST_DECLARE (fs_link) |
253 | 255 | TEST_DECLARE (fs_readlink) |
256 | TEST_DECLARE (fs_realpath) | |
254 | 257 | TEST_DECLARE (fs_symlink) |
255 | 258 | TEST_DECLARE (fs_symlink_dir) |
256 | 259 | TEST_DECLARE (fs_utime) |
333 | 336 | HELPER_DECLARE (udp4_echo_server) |
334 | 337 | HELPER_DECLARE (pipe_echo_server) |
335 | 338 | |
339 | TEST_DECLARE (queue_foreach_delete) | |
336 | 340 | |
337 | 341 | TASK_LIST_START |
338 | 342 | TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000) |
379 | 383 | TEST_ENTRY (ipc_listen_after_write) |
380 | 384 | #ifndef _WIN32 |
381 | 385 | TEST_ENTRY (ipc_send_recv_pipe) |
386 | TEST_ENTRY (ipc_send_recv_pipe_inprocess) | |
382 | 387 | #endif |
383 | 388 | TEST_ENTRY (ipc_send_recv_tcp) |
389 | TEST_ENTRY (ipc_send_recv_tcp_inprocess) | |
384 | 390 | TEST_ENTRY (ipc_tcp_connection) |
385 | 391 | |
386 | 392 | TEST_ENTRY (tcp_ping_pong) |
670 | 676 | TEST_ENTRY (fs_utime) |
671 | 677 | TEST_ENTRY (fs_futime) |
672 | 678 | TEST_ENTRY (fs_readlink) |
679 | TEST_ENTRY (fs_realpath) | |
673 | 680 | TEST_ENTRY (fs_symlink) |
674 | 681 | TEST_ENTRY (fs_symlink_dir) |
675 | 682 | TEST_ENTRY (fs_stat_missing_path) |
713 | 720 | TEST_ENTRY (dlerror) |
714 | 721 | TEST_ENTRY (ip4_addr) |
715 | 722 | TEST_ENTRY (ip6_addr_link_local) |
723 | ||
724 | TEST_ENTRY (queue_foreach_delete) | |
725 | ||
716 | 726 | #if 0 |
717 | 727 | /* These are for testing the test runner. */ |
718 | 728 | TEST_ENTRY (fail_always) |
24 | 24 | #include <stdio.h> |
25 | 25 | #include <stdlib.h> |
26 | 26 | |
27 | static uv_cond_t condvar; | |
28 | static uv_mutex_t mutex; | |
29 | static uv_rwlock_t rwlock; | |
30 | static int step; | |
27 | 31 | |
28 | 32 | /* The mutex and rwlock tests are really poor. |
29 | 33 | * They're very basic sanity checks and nothing more. |
62 | 66 | } |
63 | 67 | |
64 | 68 | |
65 | TEST_IMPL(thread_rwlock_trylock) { | |
66 | uv_rwlock_t rwlock; | |
67 | int r; | |
69 | /* Call when holding |mutex|. */ | |
70 | static void synchronize_nowait(void) { | |
71 | step += 1; | |
72 | uv_cond_signal(&condvar); | |
73 | } | |
68 | 74 | |
69 | r = uv_rwlock_init(&rwlock); | |
70 | ASSERT(r == 0); | |
71 | 75 | |
72 | /* No locks held. */ | |
76 | /* Call when holding |mutex|. */ | |
77 | static void synchronize(void) { | |
78 | int current; | |
73 | 79 | |
74 | r = uv_rwlock_trywrlock(&rwlock); | |
75 | ASSERT(r == 0); | |
80 | synchronize_nowait(); | |
81 | /* Wait for the other thread. Guard against spurious wakeups. */ | |
82 | for (current = step; current == step; uv_cond_wait(&condvar, &mutex)); | |
83 | ASSERT(step == current + 1); | |
84 | } | |
76 | 85 | |
77 | /* Write lock held. */ | |
78 | 86 | |
79 | r = uv_rwlock_tryrdlock(&rwlock); | |
80 | ASSERT(r == UV_EBUSY); | |
81 | r = uv_rwlock_trywrlock(&rwlock); | |
82 | ASSERT(r == UV_EBUSY); | |
87 | static void thread_rwlock_trylock_peer(void* unused) { | |
88 | (void) &unused; | |
83 | 89 | |
90 | uv_mutex_lock(&mutex); | |
91 | ||
92 | /* Write lock held by other thread. */ | |
93 | ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock)); | |
94 | ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); | |
95 | synchronize(); | |
96 | ||
97 | /* Read lock held by other thread. */ | |
98 | ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); | |
99 | uv_rwlock_rdunlock(&rwlock); | |
100 | ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); | |
101 | synchronize(); | |
102 | ||
103 | /* Acquire write lock. */ | |
104 | ASSERT(0 == uv_rwlock_trywrlock(&rwlock)); | |
105 | synchronize(); | |
106 | ||
107 | /* Release write lock and acquire read lock. */ | |
84 | 108 | uv_rwlock_wrunlock(&rwlock); |
85 | ||
86 | /* No locks held. */ | |
87 | ||
88 | r = uv_rwlock_tryrdlock(&rwlock); | |
89 | ASSERT(r == 0); | |
90 | ||
91 | /* One read lock held. */ | |
92 | ||
93 | r = uv_rwlock_tryrdlock(&rwlock); | |
94 | ASSERT(r == 0); | |
95 | ||
96 | /* Two read locks held. */ | |
97 | ||
98 | r = uv_rwlock_trywrlock(&rwlock); | |
99 | ASSERT(r == UV_EBUSY); | |
109 | ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); | |
110 | synchronize(); | |
100 | 111 | |
101 | 112 | uv_rwlock_rdunlock(&rwlock); |
113 | synchronize_nowait(); /* Signal main thread we're going away. */ | |
114 | uv_mutex_unlock(&mutex); | |
115 | } | |
102 | 116 | |
103 | /* One read lock held. */ | |
104 | 117 | |
118 | TEST_IMPL(thread_rwlock_trylock) { | |
119 | uv_thread_t thread; | |
120 | ||
121 | ASSERT(0 == uv_cond_init(&condvar)); | |
122 | ASSERT(0 == uv_mutex_init(&mutex)); | |
123 | ASSERT(0 == uv_rwlock_init(&rwlock)); | |
124 | ||
125 | uv_mutex_lock(&mutex); | |
126 | ASSERT(0 == uv_thread_create(&thread, thread_rwlock_trylock_peer, NULL)); | |
127 | ||
128 | /* Hold write lock. */ | |
129 | ASSERT(0 == uv_rwlock_trywrlock(&rwlock)); | |
130 | synchronize(); /* Releases the mutex to the other thread. */ | |
131 | ||
132 | /* Release write lock and acquire read lock. Pthreads doesn't support | |
133 | * the notion of upgrading or downgrading rwlocks, so neither do we. | |
134 | */ | |
135 | uv_rwlock_wrunlock(&rwlock); | |
136 | ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); | |
137 | synchronize(); | |
138 | ||
139 | /* Release read lock. */ | |
105 | 140 | uv_rwlock_rdunlock(&rwlock); |
141 | synchronize(); | |
106 | 142 | |
107 | /* No read locks held. */ | |
143 | /* Write lock held by other thread. */ | |
144 | ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock)); | |
145 | ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); | |
146 | synchronize(); | |
108 | 147 | |
109 | r = uv_rwlock_trywrlock(&rwlock); | |
110 | ASSERT(r == 0); | |
148 | /* Read lock held by other thread. */ | |
149 | ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); | |
150 | uv_rwlock_rdunlock(&rwlock); | |
151 | ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); | |
152 | synchronize(); | |
111 | 153 | |
112 | /* Write lock held. */ | |
113 | ||
114 | uv_rwlock_wrunlock(&rwlock); | |
115 | ||
116 | /* No locks held. */ | |
117 | ||
154 | ASSERT(0 == uv_thread_join(&thread)); | |
118 | 155 | uv_rwlock_destroy(&rwlock); |
156 | uv_mutex_unlock(&mutex); | |
157 | uv_mutex_destroy(&mutex); | |
158 | uv_cond_destroy(&condvar); | |
119 | 159 | |
120 | 160 | return 0; |
121 | 161 | } |
41 | 41 | |
42 | 42 | |
43 | 43 | TEST_IMPL(process_title) { |
44 | #if defined(__sun) | |
44 | #if defined(__sun) || defined(_AIX) | |
45 | 45 | RETURN_SKIP("uv_(get|set)_process_title is not implemented."); |
46 | 46 | #else |
47 | 47 | /* Check for format string vulnerabilities. */ |
0 | /* Copyright The libuv project and contributors. All rights reserved. | |
1 | * | |
2 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | * of this software and associated documentation files (the "Software"), to | |
4 | * deal in the Software without restriction, including without limitation the | |
5 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | |
6 | * sell copies of the Software, and to permit persons to whom the Software is | |
7 | * furnished to do so, subject to the following conditions: | |
8 | * | |
9 | * The above copyright notice and this permission notice shall be included in | |
10 | * all copies or substantial portions of the Software. | |
11 | * | |
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
17 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
18 | * IN THE SOFTWARE. | |
19 | */ | |
20 | ||
21 | #include "uv.h" | |
22 | #include "task.h" | |
23 | ||
24 | #include <string.h> | |
25 | ||
26 | ||
27 | /* | |
28 | * The idea behind the test is as follows. | |
29 | * Certain handle types are stored in a queue internally. | |
30 | * Extra care should be taken for removal of a handle from the queue while iterating over the queue. | |
31 | * (i.e., QUEUE_REMOVE() called within QUEUE_FOREACH()) | |
32 | * This usually happens when someone closes or stops a handle from within its callback. | |
33 | * So we need to check that we haven't screwed the queue on close/stop. | |
34 | * To do so we do the following (for each handle type): | |
35 | * 1. Create and start 3 handles (#0, #1, and #2). | |
36 | * | |
37 | * The queue after the start() calls: | |
38 | * ..=> [queue head] <=> [handle] <=> [handle #1] <=> [handle] <=.. | |
39 | * | |
40 | * 2. Trigger handles to fire (for uv_idle_t, uv_prepare_t, and uv_check_t there is nothing to do). | |
41 | * | |
42 | * 3. In the callback for the first-executed handle (#0 or #2 depending on handle type) | |
43 | * stop the handle and the next one (#1). | |
44 | * (for uv_idle_t, uv_prepare_t, and uv_check_t callbacks are executed in the reverse order as they are start()'ed, | |
45 | * so callback for handle #2 will be called first) | |
46 | * | |
47 | * The queue after the stop() calls: | |
48 | * correct foreach "next" | | |
49 | * \/ | |
50 | * ..=> [queue head] <==============================> [handle] <=.. | |
51 | * [ ] <- [handle] <=> [handle #1] -> [ ] | |
52 | * /\ | |
53 | * wrong foreach "next" | | |
54 | * | |
55 | * 4. The callback for handle #1 shouldn't be called because the handle #1 is stopped in the previous step. | |
56 | * However, if QUEUE_REMOVE() is not handled properly within QUEUE_FOREACH(), the callback _will_ be called. | |
57 | */ | |
58 | ||
59 | static const unsigned first_handle_number_idle = 2; | |
60 | static const unsigned first_handle_number_prepare = 2; | |
61 | static const unsigned first_handle_number_check = 2; | |
62 | #ifdef __linux__ | |
63 | static const unsigned first_handle_number_fs_event = 0; | |
64 | #endif | |
65 | ||
66 | ||
67 | #define DEFINE_GLOBALS_AND_CBS(name) \ | |
68 | static uv_##name##_t (name)[3]; \ | |
69 | static unsigned name##_cb_calls[3]; \ | |
70 | \ | |
71 | static void name##2_cb(uv_##name##_t* handle) { \ | |
72 | ASSERT(handle == &(name)[2]); \ | |
73 | if (first_handle_number_##name == 2) { \ | |
74 | uv_close((uv_handle_t*)&(name)[2], NULL); \ | |
75 | uv_close((uv_handle_t*)&(name)[1], NULL); \ | |
76 | } \ | |
77 | name##_cb_calls[2]++; \ | |
78 | } \ | |
79 | \ | |
80 | static void name##1_cb(uv_##name##_t* handle) { \ | |
81 | ASSERT(handle == &(name)[1]); \ | |
82 | ASSERT(0 && "Shouldn't be called" && (&name[0])); \ | |
83 | } \ | |
84 | \ | |
85 | static void name##0_cb(uv_##name##_t* handle) { \ | |
86 | ASSERT(handle == &(name)[0]); \ | |
87 | if (first_handle_number_##name == 0) { \ | |
88 | uv_close((uv_handle_t*)&(name)[0], NULL); \ | |
89 | uv_close((uv_handle_t*)&(name)[1], NULL); \ | |
90 | } \ | |
91 | name##_cb_calls[0]++; \ | |
92 | } \ | |
93 | \ | |
94 | static const uv_##name##_cb name##_cbs[] = { \ | |
95 | (uv_##name##_cb)name##0_cb, \ | |
96 | (uv_##name##_cb)name##1_cb, \ | |
97 | (uv_##name##_cb)name##2_cb, \ | |
98 | }; | |
99 | ||
100 | #define INIT_AND_START(name, loop) \ | |
101 | do { \ | |
102 | size_t i; \ | |
103 | for (i = 0; i < ARRAY_SIZE(name); i++) { \ | |
104 | int r; \ | |
105 | r = uv_##name##_init((loop), &(name)[i]); \ | |
106 | ASSERT(r == 0); \ | |
107 | \ | |
108 | r = uv_##name##_start(&(name)[i], name##_cbs[i]); \ | |
109 | ASSERT(r == 0); \ | |
110 | } \ | |
111 | } while (0) | |
112 | ||
113 | #define END_ASSERTS(name) \ | |
114 | do { \ | |
115 | ASSERT(name##_cb_calls[0] == 1); \ | |
116 | ASSERT(name##_cb_calls[1] == 0); \ | |
117 | ASSERT(name##_cb_calls[2] == 1); \ | |
118 | } while (0) | |
119 | ||
120 | DEFINE_GLOBALS_AND_CBS(idle) | |
121 | DEFINE_GLOBALS_AND_CBS(prepare) | |
122 | DEFINE_GLOBALS_AND_CBS(check) | |
123 | ||
124 | #ifdef __linux__ | |
125 | DEFINE_GLOBALS_AND_CBS(fs_event) | |
126 | ||
127 | static const char watched_dir[] = "."; | |
128 | static uv_timer_t timer; | |
129 | static unsigned helper_timer_cb_calls; | |
130 | ||
131 | ||
132 | static void init_and_start_fs_events(uv_loop_t* loop) { | |
133 | size_t i; | |
134 | for (i = 0; i < ARRAY_SIZE(fs_event); i++) { | |
135 | int r; | |
136 | r = uv_fs_event_init(loop, &fs_event[i]); | |
137 | ASSERT(r == 0); | |
138 | ||
139 | r = uv_fs_event_start(&fs_event[i], | |
140 | (uv_fs_event_cb)fs_event_cbs[i], | |
141 | watched_dir, | |
142 | 0); | |
143 | ASSERT(r == 0); | |
144 | } | |
145 | } | |
146 | ||
147 | static void helper_timer_cb(uv_timer_t* thandle) { | |
148 | int r; | |
149 | uv_fs_t fs_req; | |
150 | ||
151 | /* fire all fs_events */ | |
152 | r = uv_fs_utime(thandle->loop, &fs_req, watched_dir, 0, 0, NULL); | |
153 | ASSERT(r == 0); | |
154 | ASSERT(fs_req.result == 0); | |
155 | ASSERT(fs_req.fs_type == UV_FS_UTIME); | |
156 | ASSERT(strcmp(fs_req.path, watched_dir) == 0); | |
157 | uv_fs_req_cleanup(&fs_req); | |
158 | ||
159 | helper_timer_cb_calls++; | |
160 | } | |
161 | #endif | |
162 | ||
163 | ||
164 | TEST_IMPL(queue_foreach_delete) { | |
165 | uv_loop_t* loop; | |
166 | int r; | |
167 | ||
168 | loop = uv_default_loop(); | |
169 | ||
170 | INIT_AND_START(idle, loop); | |
171 | INIT_AND_START(prepare, loop); | |
172 | INIT_AND_START(check, loop); | |
173 | ||
174 | #ifdef __linux__ | |
175 | init_and_start_fs_events(loop); | |
176 | ||
177 | /* helper timer to trigger async and fs_event callbacks */ | |
178 | r = uv_timer_init(loop, &timer); | |
179 | ASSERT(r == 0); | |
180 | ||
181 | r = uv_timer_start(&timer, helper_timer_cb, 0, 0); | |
182 | ASSERT(r == 0); | |
183 | #endif | |
184 | ||
185 | r = uv_run(loop, UV_RUN_NOWAIT); | |
186 | ASSERT(r == 1); | |
187 | ||
188 | END_ASSERTS(idle); | |
189 | END_ASSERTS(prepare); | |
190 | END_ASSERTS(check); | |
191 | ||
192 | #ifdef __linux__ | |
193 | ASSERT(helper_timer_cb_calls == 1); | |
194 | #endif | |
195 | ||
196 | MAKE_VALGRIND_HAPPY(); | |
197 | ||
198 | return 0; | |
199 | } |
959 | 959 | options.stdio_count = 2; |
960 | 960 | |
961 | 961 | /* Create a pipe that'll cause a collision. */ |
962 | _snprintf(name, | |
963 | sizeof(name), | |
964 | "\\\\.\\pipe\\uv\\%p-%d", | |
965 | &out, | |
966 | GetCurrentProcessId()); | |
962 | snprintf(name, | |
963 | sizeof(name), | |
964 | "\\\\.\\pipe\\uv\\%p-%d", | |
965 | &out, | |
966 | GetCurrentProcessId()); | |
967 | 967 | pipe_handle = CreateNamedPipeA(name, |
968 | 968 | PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, |
969 | 969 | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, |
57 | 57 | break; |
58 | 58 | } |
59 | 59 | } while (1); |
60 | ||
61 | do { | |
62 | buf = uv_buf_init("", 0); | |
63 | r = uv_try_write((uv_stream_t*) &client, &buf, 1); | |
64 | } while (r != 0); | |
60 | 65 | uv_close((uv_handle_t*) &client, close_cb); |
61 | 66 | } |
62 | 67 |
42 | 42 | r = uv_fileno((uv_handle_t*)sock, &fd); |
43 | 43 | ASSERT(r == 0); |
44 | 44 | #ifdef _WIN32 |
45 | r = closesocket(fd); | |
45 | r = closesocket((uv_os_sock_t)fd); | |
46 | 46 | #else |
47 | 47 | r = close(fd); |
48 | 48 | #endif |
275 | 275 | |
276 | 276 | TEST_IMPL(threadpool_cancel_fs) { |
277 | 277 | struct cancel_info ci; |
278 | uv_fs_t reqs[25]; | |
278 | uv_fs_t reqs[26]; | |
279 | 279 | uv_loop_t* loop; |
280 | 280 | unsigned n; |
281 | 281 | uv_buf_t iov; |
304 | 304 | ASSERT(0 == uv_fs_read(loop, reqs + n++, 0, &iov, 1, 0, fs_cb)); |
305 | 305 | ASSERT(0 == uv_fs_scandir(loop, reqs + n++, "/", 0, fs_cb)); |
306 | 306 | ASSERT(0 == uv_fs_readlink(loop, reqs + n++, "/", fs_cb)); |
307 | ASSERT(0 == uv_fs_realpath(loop, reqs + n++, "/", fs_cb)); | |
307 | 308 | ASSERT(0 == uv_fs_rename(loop, reqs + n++, "/", "/", fs_cb)); |
308 | 309 | ASSERT(0 == uv_fs_mkdir(loop, reqs + n++, "/", 0, fs_cb)); |
309 | 310 | ASSERT(0 == uv_fs_sendfile(loop, reqs + n++, 0, 0, 0, 0, fs_cb)); |
152 | 152 | ASSERT(0 == close(fd)); |
153 | 153 | } |
154 | 154 | |
155 | /* Bug on AIX where '/dev/random' returns 1 from isatty() */ | |
156 | #ifndef _AIX | |
155 | 157 | fd = open("/dev/random", O_RDONLY); |
156 | 158 | if (fd != -1) { |
157 | 159 | ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1)); |
158 | 160 | ASSERT(0 == close(fd)); |
159 | 161 | } |
162 | #endif /* _AIX */ | |
160 | 163 | |
161 | 164 | fd = open("/dev/zero", O_RDONLY); |
162 | 165 | if (fd != -1) { |
25 | 25 | #include <stdlib.h> |
26 | 26 | #include <string.h> |
27 | 27 | |
28 | #ifdef __FreeBSD__ | |
29 | #include <sys/sysctl.h> | |
30 | #endif | |
31 | ||
28 | 32 | #define CHECK_HANDLE(handle) \ |
29 | 33 | ASSERT((uv_udp_t*)(handle) == &server \ |
30 | 34 | || (uv_udp_t*)(handle) == &client \ |
41 | 45 | static int send_cb_called; |
42 | 46 | static int recv_cb_called; |
43 | 47 | static int close_cb_called; |
48 | ||
49 | #ifdef __FreeBSD__ | |
50 | static int can_ipv6_ipv4_dual() { | |
51 | int v6only; | |
52 | size_t size = sizeof(int); | |
53 | ||
54 | if (sysctlbyname("net.inet6.ip6.v6only", &v6only, &size, NULL, 0)) | |
55 | return 0; | |
56 | ||
57 | return v6only != 1; | |
58 | } | |
59 | #endif | |
44 | 60 | |
45 | 61 | |
46 | 62 | static void alloc_cb(uv_handle_t* handle, |
149 | 165 | if (!can_ipv6()) |
150 | 166 | RETURN_SKIP("IPv6 not supported"); |
151 | 167 | |
168 | #ifdef __FreeBSD__ | |
169 | if (!can_ipv6_ipv4_dual()) | |
170 | RETURN_SKIP("IPv6-IPv4 dual stack not supported"); | |
171 | #endif | |
172 | ||
152 | 173 | do_test(ipv6_recv_ok, 0); |
153 | 174 | |
154 | 175 | ASSERT(recv_cb_called == 1); |
118 | 118 | ASSERT(r == 0); |
119 | 119 | |
120 | 120 | /* join the multicast channel */ |
121 | #if defined(__APPLE__) | |
121 | #if defined(__APPLE__) || defined(_AIX) | |
122 | 122 | r = uv_udp_set_membership(&client, "ff02::1", "::1%lo0", UV_JOIN_GROUP); |
123 | 123 | #else |
124 | 124 | r = uv_udp_set_membership(&client, "ff02::1", NULL, UV_JOIN_GROUP); |
102 | 102 | 'src/win/winapi.h', |
103 | 103 | 'src/win/winsock.c', |
104 | 104 | 'src/win/winsock.h', |
105 | ], | |
106 | 'conditions': [ | |
107 | ['MSVS_VERSION < "2015"', { | |
108 | 'sources': [ | |
109 | 'src/win/snprintf.c' | |
110 | ] | |
111 | }] | |
105 | 112 | ], |
106 | 113 | 'link_settings': { |
107 | 114 | 'libraries': [ |
339 | 346 | 'test/test-poll-close-doesnt-corrupt-stack.c', |
340 | 347 | 'test/test-poll-closesocket.c', |
341 | 348 | 'test/test-process-title.c', |
349 | 'test/test-queue-foreach-delete.c', | |
342 | 350 | 'test/test-ref.c', |
343 | 351 | 'test/test-run-nowait.c', |
344 | 352 | 'test/test-run-once.c', |