passenger 5.0.8 → 5.0.9

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (168) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/.editorconfig +20 -0
  5. data/CHANGELOG +21 -0
  6. data/bin/passenger-install-apache2-module +3 -1
  7. data/build/agents.rb +7 -5
  8. data/build/basics.rb +3 -3
  9. data/build/common_library.rb +52 -30
  10. data/build/cxx_tests.rb +20 -13
  11. data/build/misc.rb +5 -5
  12. data/doc/Design and Architecture.html +1 -1
  13. data/doc/Design and Architecture.txt +1 -1
  14. data/doc/Packaging.html +4 -4
  15. data/doc/Packaging.txt.md +4 -4
  16. data/doc/Users guide Apache.html +22 -9
  17. data/doc/Users guide Apache.idmap.txt +4 -2
  18. data/doc/Users guide Apache.txt +2 -0
  19. data/doc/Users guide Nginx.html +22 -9
  20. data/doc/Users guide Nginx.idmap.txt +4 -2
  21. data/doc/Users guide Nginx.txt +2 -0
  22. data/doc/Users guide Standalone.html +14 -9
  23. data/doc/Users guide Standalone.idmap.txt +4 -2
  24. data/doc/users_guide_snippets/installation.txt +10 -6
  25. data/ext/apache2/Hooks.cpp +13 -2
  26. data/ext/common/ApplicationPool2/Pool/Inspection.h +8 -3
  27. data/ext/common/BackgroundEventLoop.cpp +249 -67
  28. data/ext/common/BackgroundEventLoop.h +5 -5
  29. data/ext/common/Constants.h +1 -1
  30. data/ext/common/InstanceDirectory.h +8 -6
  31. data/ext/common/ServerKit/Context.h +8 -2
  32. data/ext/common/ServerKit/FileBufferedChannel.h +262 -226
  33. data/ext/common/ServerKit/HeaderTable.h +28 -3
  34. data/ext/common/ServerKit/HttpHeaderParser.h +37 -13
  35. data/ext/common/ServerKit/HttpServer.h +17 -1
  36. data/ext/common/ServerKit/Implementation.cpp +2 -0
  37. data/ext/common/ServerKit/Server.h +25 -28
  38. data/ext/common/Utils/IOUtils.cpp +11 -0
  39. data/ext/common/Utils/ProcessMetricsCollector.h +4 -0
  40. data/ext/common/Utils/StrIntUtils.cpp +11 -7
  41. data/ext/common/Utils/StrIntUtils.h +1 -1
  42. data/ext/common/Utils/StrIntUtilsNoStrictAliasing.cpp +21 -16
  43. data/ext/common/agents/Base.cpp +6 -0
  44. data/ext/common/agents/Base.h +2 -0
  45. data/ext/common/agents/HelperAgent/AdminServer.h +25 -25
  46. data/ext/common/agents/HelperAgent/Main.cpp +37 -12
  47. data/ext/common/agents/HelperAgent/RequestHandler.h +18 -20
  48. data/ext/common/agents/HelperAgent/RequestHandler/AppResponse.h +4 -0
  49. data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +10 -6
  50. data/ext/common/agents/HelperAgent/RequestHandler/Hooks.cpp +2 -0
  51. data/ext/common/agents/HelperAgent/RequestHandler/InitRequest.cpp +1 -1
  52. data/ext/common/agents/HelperAgent/RequestHandler/SendRequest.cpp +1 -1
  53. data/ext/common/agents/HelperAgent/RequestHandler/Utils.cpp +9 -2
  54. data/ext/common/agents/HelperAgent/ResponseCache.h +11 -11
  55. data/ext/common/agents/LoggingAgent/AdminServer.h +8 -8
  56. data/ext/common/agents/LoggingAgent/Main.cpp +6 -5
  57. data/ext/common/agents/Watchdog/AdminServer.h +13 -13
  58. data/ext/common/agents/Watchdog/Main.cpp +8 -3
  59. data/ext/libuv/.gitignore +72 -0
  60. data/ext/libuv/AUTHORS +199 -0
  61. data/ext/libuv/ChangeLog +2023 -0
  62. data/ext/libuv/LICENSE +46 -0
  63. data/ext/libuv/Makefile.am +336 -0
  64. data/ext/libuv/README.md +197 -0
  65. data/ext/libuv/checksparse.sh +233 -0
  66. data/ext/libuv/common.gypi +210 -0
  67. data/ext/libuv/configure.ac +67 -0
  68. data/ext/libuv/gyp_uv.py +96 -0
  69. data/ext/libuv/include/android-ifaddrs.h +54 -0
  70. data/ext/libuv/include/pthread-fixes.h +72 -0
  71. data/ext/libuv/include/tree.h +768 -0
  72. data/ext/libuv/include/uv-aix.h +32 -0
  73. data/ext/libuv/include/uv-bsd.h +34 -0
  74. data/ext/libuv/include/uv-darwin.h +61 -0
  75. data/ext/libuv/include/uv-errno.h +418 -0
  76. data/ext/libuv/include/uv-linux.h +34 -0
  77. data/ext/libuv/include/uv-sunos.h +44 -0
  78. data/ext/libuv/include/uv-threadpool.h +37 -0
  79. data/ext/libuv/include/uv-unix.h +383 -0
  80. data/ext/libuv/include/uv-version.h +39 -0
  81. data/ext/libuv/include/uv.h +1455 -0
  82. data/ext/libuv/libuv.pc.in +11 -0
  83. data/ext/libuv/m4/.gitignore +4 -0
  84. data/ext/libuv/m4/as_case.m4 +21 -0
  85. data/ext/libuv/m4/libuv-check-flags.m4 +319 -0
  86. data/ext/libuv/src/fs-poll.c +255 -0
  87. data/ext/libuv/src/heap-inl.h +245 -0
  88. data/ext/libuv/src/inet.c +313 -0
  89. data/ext/libuv/src/queue.h +92 -0
  90. data/ext/libuv/src/threadpool.c +303 -0
  91. data/ext/libuv/src/unix/aix.c +1240 -0
  92. data/ext/libuv/src/unix/android-ifaddrs.c +703 -0
  93. data/ext/libuv/src/unix/async.c +284 -0
  94. data/ext/libuv/src/unix/atomic-ops.h +60 -0
  95. data/ext/libuv/src/unix/core.c +985 -0
  96. data/ext/libuv/src/unix/darwin-proctitle.c +206 -0
  97. data/ext/libuv/src/unix/darwin.c +331 -0
  98. data/ext/libuv/src/unix/dl.c +83 -0
  99. data/ext/libuv/src/unix/freebsd.c +435 -0
  100. data/ext/libuv/src/unix/fs.c +1189 -0
  101. data/ext/libuv/src/unix/fsevents.c +899 -0
  102. data/ext/libuv/src/unix/getaddrinfo.c +202 -0
  103. data/ext/libuv/src/unix/getnameinfo.c +120 -0
  104. data/ext/libuv/src/unix/internal.h +314 -0
  105. data/ext/libuv/src/unix/kqueue.c +418 -0
  106. data/ext/libuv/src/unix/linux-core.c +876 -0
  107. data/ext/libuv/src/unix/linux-inotify.c +257 -0
  108. data/ext/libuv/src/unix/linux-syscalls.c +471 -0
  109. data/ext/libuv/src/unix/linux-syscalls.h +158 -0
  110. data/ext/libuv/src/unix/loop-watcher.c +63 -0
  111. data/ext/libuv/src/unix/loop.c +135 -0
  112. data/ext/libuv/src/unix/netbsd.c +368 -0
  113. data/ext/libuv/src/unix/openbsd.c +384 -0
  114. data/ext/libuv/src/unix/pipe.c +288 -0
  115. data/ext/libuv/src/unix/poll.c +113 -0
  116. data/ext/libuv/src/unix/process.c +551 -0
  117. data/ext/libuv/src/unix/proctitle.c +102 -0
  118. data/ext/libuv/src/unix/pthread-fixes.c +103 -0
  119. data/ext/libuv/src/unix/signal.c +465 -0
  120. data/ext/libuv/src/unix/spinlock.h +53 -0
  121. data/ext/libuv/src/unix/stream.c +1598 -0
  122. data/ext/libuv/src/unix/sunos.c +763 -0
  123. data/ext/libuv/src/unix/tcp.c +327 -0
  124. data/ext/libuv/src/unix/thread.c +519 -0
  125. data/ext/libuv/src/unix/timer.c +172 -0
  126. data/ext/libuv/src/unix/tty.c +265 -0
  127. data/ext/libuv/src/unix/udp.c +833 -0
  128. data/ext/libuv/src/uv-common.c +544 -0
  129. data/ext/libuv/src/uv-common.h +214 -0
  130. data/ext/libuv/src/version.c +49 -0
  131. data/ext/libuv/uv.gyp +487 -0
  132. data/ext/nginx/ContentHandler.c +21 -10
  133. data/ext/nginx/ngx_http_passenger_module.c +7 -0
  134. data/ext/oxt/implementation.cpp +9 -2
  135. data/ext/oxt/initialize.hpp +5 -1
  136. data/lib/phusion_passenger.rb +3 -3
  137. data/lib/phusion_passenger/admin_tools/instance.rb +10 -6
  138. data/lib/phusion_passenger/admin_tools/instance_registry.rb +6 -2
  139. data/lib/phusion_passenger/packaging.rb +3 -4
  140. data/lib/phusion_passenger/platform_info.rb +13 -1
  141. data/lib/phusion_passenger/platform_info/apache.rb +15 -4
  142. data/lib/phusion_passenger/platform_info/apache_detector.rb +5 -1
  143. data/lib/phusion_passenger/rack/thread_handler_extension.rb +184 -99
  144. data/lib/phusion_passenger/request_handler/thread_handler.rb +13 -6
  145. data/lib/phusion_passenger/standalone/start_command.rb +2 -2
  146. data/resources/templates/apache2/apache_install_broken.txt.erb +2 -1
  147. metadata +99 -22
  148. metadata.gz.asc +7 -7
  149. data/ext/libeio/Changes +0 -76
  150. data/ext/libeio/LICENSE +0 -36
  151. data/ext/libeio/Makefile.am +0 -15
  152. data/ext/libeio/Makefile.in +0 -694
  153. data/ext/libeio/aclocal.m4 +0 -9418
  154. data/ext/libeio/autogen.sh +0 -3
  155. data/ext/libeio/config.guess +0 -1540
  156. data/ext/libeio/config.h.in +0 -136
  157. data/ext/libeio/config.sub +0 -1779
  158. data/ext/libeio/configure +0 -14822
  159. data/ext/libeio/configure.ac +0 -22
  160. data/ext/libeio/demo.c +0 -194
  161. data/ext/libeio/ecb.h +0 -714
  162. data/ext/libeio/eio.c +0 -2818
  163. data/ext/libeio/eio.h +0 -414
  164. data/ext/libeio/install-sh +0 -520
  165. data/ext/libeio/libeio.m4 +0 -195
  166. data/ext/libeio/ltmain.sh +0 -9636
  167. data/ext/libeio/missing +0 -376
  168. data/ext/libeio/xthread.h +0 -166
@@ -0,0 +1,92 @@
1
+ /* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
2
+ *
3
+ * Permission to use, copy, modify, and/or distribute this software for any
4
+ * purpose with or without fee is hereby granted, provided that the above
5
+ * copyright notice and this permission notice appear in all copies.
6
+ *
7
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
+ */
15
+
16
+ #ifndef QUEUE_H_
17
+ #define QUEUE_H_
18
+
19
+ typedef void *QUEUE[2];
20
+
21
+ /* Private macros. */
22
+ #define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
23
+ #define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
24
+ #define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
25
+ #define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
26
+
27
+ /* Public macros. */
28
+ #define QUEUE_DATA(ptr, type, field) \
29
+ ((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field)))
30
+
31
+ #define QUEUE_FOREACH(q, h) \
32
+ for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
33
+
34
+ #define QUEUE_EMPTY(q) \
35
+ ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
36
+
37
+ #define QUEUE_HEAD(q) \
38
+ (QUEUE_NEXT(q))
39
+
40
+ #define QUEUE_INIT(q) \
41
+ do { \
42
+ QUEUE_NEXT(q) = (q); \
43
+ QUEUE_PREV(q) = (q); \
44
+ } \
45
+ while (0)
46
+
47
+ #define QUEUE_ADD(h, n) \
48
+ do { \
49
+ QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \
50
+ QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \
51
+ QUEUE_PREV(h) = QUEUE_PREV(n); \
52
+ QUEUE_PREV_NEXT(h) = (h); \
53
+ } \
54
+ while (0)
55
+
56
+ #define QUEUE_SPLIT(h, q, n) \
57
+ do { \
58
+ QUEUE_PREV(n) = QUEUE_PREV(h); \
59
+ QUEUE_PREV_NEXT(n) = (n); \
60
+ QUEUE_NEXT(n) = (q); \
61
+ QUEUE_PREV(h) = QUEUE_PREV(q); \
62
+ QUEUE_PREV_NEXT(h) = (h); \
63
+ QUEUE_PREV(q) = (n); \
64
+ } \
65
+ while (0)
66
+
67
+ #define QUEUE_INSERT_HEAD(h, q) \
68
+ do { \
69
+ QUEUE_NEXT(q) = QUEUE_NEXT(h); \
70
+ QUEUE_PREV(q) = (h); \
71
+ QUEUE_NEXT_PREV(q) = (q); \
72
+ QUEUE_NEXT(h) = (q); \
73
+ } \
74
+ while (0)
75
+
76
+ #define QUEUE_INSERT_TAIL(h, q) \
77
+ do { \
78
+ QUEUE_NEXT(q) = (h); \
79
+ QUEUE_PREV(q) = QUEUE_PREV(h); \
80
+ QUEUE_PREV_NEXT(q) = (q); \
81
+ QUEUE_PREV(h) = (q); \
82
+ } \
83
+ while (0)
84
+
85
+ #define QUEUE_REMOVE(q) \
86
+ do { \
87
+ QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \
88
+ QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \
89
+ } \
90
+ while (0)
91
+
92
+ #endif /* QUEUE_H_ */
@@ -0,0 +1,303 @@
1
+ /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2
+ *
3
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ * of this software and associated documentation files (the "Software"), to
5
+ * deal in the Software without restriction, including without limitation the
6
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ * sell copies of the Software, and to permit persons to whom the Software is
8
+ * furnished to do so, subject to the following conditions:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included in
11
+ * all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19
+ * IN THE SOFTWARE.
20
+ */
21
+
22
+ #include "uv-common.h"
23
+
24
+ #if !defined(_WIN32)
25
+ # include "unix/internal.h"
26
+ #else
27
+ # include "win/req-inl.h"
28
+ /* TODO(saghul): unify internal req functions */
29
+ static void uv__req_init(uv_loop_t* loop,
30
+ uv_req_t* req,
31
+ uv_req_type type) {
32
+ uv_req_init(loop, req);
33
+ req->type = type;
34
+ uv__req_register(loop, req);
35
+ }
36
+ # define uv__req_init(loop, req, type) \
37
+ uv__req_init((loop), (uv_req_t*)(req), (type))
38
+ #endif
39
+
40
+ #include <stdlib.h>
41
+
42
+ #define MAX_THREADPOOL_SIZE 128
43
+
44
+ static uv_once_t once = UV_ONCE_INIT;
45
+ static uv_cond_t cond;
46
+ static uv_mutex_t mutex;
47
+ static unsigned int nthreads;
48
+ static uv_thread_t* threads;
49
+ static uv_thread_t default_threads[4];
50
+ static QUEUE exit_message;
51
+ static QUEUE wq;
52
+ static volatile int initialized;
53
+
54
+
55
+ static void uv__cancelled(struct uv__work* w) {
56
+ abort();
57
+ }
58
+
59
+
60
+ /* To avoid deadlock with uv_cancel() it's crucial that the worker
61
+ * never holds the global mutex and the loop-local mutex at the same time.
62
+ */
63
+ static void worker(void* arg) {
64
+ struct uv__work* w;
65
+ QUEUE* q;
66
+
67
+ (void) arg;
68
+
69
+ for (;;) {
70
+ uv_mutex_lock(&mutex);
71
+
72
+ while (QUEUE_EMPTY(&wq))
73
+ uv_cond_wait(&cond, &mutex);
74
+
75
+ q = QUEUE_HEAD(&wq);
76
+
77
+ if (q == &exit_message)
78
+ uv_cond_signal(&cond);
79
+ else {
80
+ QUEUE_REMOVE(q);
81
+ QUEUE_INIT(q); /* Signal uv_cancel() that the work req is
82
+ executing. */
83
+ }
84
+
85
+ uv_mutex_unlock(&mutex);
86
+
87
+ if (q == &exit_message)
88
+ break;
89
+
90
+ w = QUEUE_DATA(q, struct uv__work, wq);
91
+ w->work(w);
92
+
93
+ uv_mutex_lock(&w->loop->wq_mutex);
94
+ w->work = NULL; /* Signal uv_cancel() that the work req is done
95
+ executing. */
96
+ QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
97
+ uv_async_send(&w->loop->wq_async);
98
+ uv_mutex_unlock(&w->loop->wq_mutex);
99
+ }
100
+ }
101
+
102
+
103
+ static void post(QUEUE* q) {
104
+ uv_mutex_lock(&mutex);
105
+ QUEUE_INSERT_TAIL(&wq, q);
106
+ uv_cond_signal(&cond);
107
+ uv_mutex_unlock(&mutex);
108
+ }
109
+
110
+
111
+ #ifndef _WIN32
112
+ UV_DESTRUCTOR(static void cleanup(void)) {
113
+ unsigned int i;
114
+
115
+ if (initialized == 0)
116
+ return;
117
+
118
+ post(&exit_message);
119
+
120
+ for (i = 0; i < nthreads; i++)
121
+ if (uv_thread_join(threads + i))
122
+ abort();
123
+
124
+ if (threads != default_threads)
125
+ free(threads);
126
+
127
+ uv_mutex_destroy(&mutex);
128
+ uv_cond_destroy(&cond);
129
+
130
+ threads = NULL;
131
+ nthreads = 0;
132
+ initialized = 0;
133
+ }
134
+ #endif
135
+
136
+
137
+ static void init_once(void) {
138
+ unsigned int i;
139
+ const char* val;
140
+
141
+ nthreads = ARRAY_SIZE(default_threads);
142
+ val = getenv("UV_THREADPOOL_SIZE");
143
+ if (val != NULL)
144
+ nthreads = atoi(val);
145
+ if (nthreads == 0)
146
+ nthreads = 1;
147
+ if (nthreads > MAX_THREADPOOL_SIZE)
148
+ nthreads = MAX_THREADPOOL_SIZE;
149
+
150
+ threads = default_threads;
151
+ if (nthreads > ARRAY_SIZE(default_threads)) {
152
+ threads = malloc(nthreads * sizeof(threads[0]));
153
+ if (threads == NULL) {
154
+ nthreads = ARRAY_SIZE(default_threads);
155
+ threads = default_threads;
156
+ }
157
+ }
158
+
159
+ if (uv_cond_init(&cond))
160
+ abort();
161
+
162
+ if (uv_mutex_init(&mutex))
163
+ abort();
164
+
165
+ QUEUE_INIT(&wq);
166
+
167
+ for (i = 0; i < nthreads; i++)
168
+ if (uv_thread_create(threads + i, worker, NULL))
169
+ abort();
170
+
171
+ initialized = 1;
172
+ }
173
+
174
+
175
+ void uv__work_submit(uv_loop_t* loop,
176
+ struct uv__work* w,
177
+ void (*work)(struct uv__work* w),
178
+ void (*done)(struct uv__work* w, int status)) {
179
+ uv_once(&once, init_once);
180
+ w->loop = loop;
181
+ w->work = work;
182
+ w->done = done;
183
+ post(&w->wq);
184
+ }
185
+
186
+
187
+ static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
188
+ int cancelled;
189
+
190
+ uv_mutex_lock(&mutex);
191
+ uv_mutex_lock(&w->loop->wq_mutex);
192
+
193
+ cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL;
194
+ if (cancelled)
195
+ QUEUE_REMOVE(&w->wq);
196
+
197
+ uv_mutex_unlock(&w->loop->wq_mutex);
198
+ uv_mutex_unlock(&mutex);
199
+
200
+ if (!cancelled)
201
+ return UV_EBUSY;
202
+
203
+ w->work = uv__cancelled;
204
+ uv_mutex_lock(&loop->wq_mutex);
205
+ QUEUE_INSERT_TAIL(&loop->wq, &w->wq);
206
+ uv_async_send(&loop->wq_async);
207
+ uv_mutex_unlock(&loop->wq_mutex);
208
+
209
+ return 0;
210
+ }
211
+
212
+
213
+ void uv__work_done(uv_async_t* handle) {
214
+ struct uv__work* w;
215
+ uv_loop_t* loop;
216
+ QUEUE* q;
217
+ QUEUE wq;
218
+ int err;
219
+
220
+ loop = container_of(handle, uv_loop_t, wq_async);
221
+ QUEUE_INIT(&wq);
222
+
223
+ uv_mutex_lock(&loop->wq_mutex);
224
+ if (!QUEUE_EMPTY(&loop->wq)) {
225
+ q = QUEUE_HEAD(&loop->wq);
226
+ QUEUE_SPLIT(&loop->wq, q, &wq);
227
+ }
228
+ uv_mutex_unlock(&loop->wq_mutex);
229
+
230
+ while (!QUEUE_EMPTY(&wq)) {
231
+ q = QUEUE_HEAD(&wq);
232
+ QUEUE_REMOVE(q);
233
+
234
+ w = container_of(q, struct uv__work, wq);
235
+ err = (w->work == uv__cancelled) ? UV_ECANCELED : 0;
236
+ w->done(w, err);
237
+ }
238
+ }
239
+
240
+
241
+ static void uv__queue_work(struct uv__work* w) {
242
+ uv_work_t* req = container_of(w, uv_work_t, work_req);
243
+
244
+ req->work_cb(req);
245
+ }
246
+
247
+
248
+ static void uv__queue_done(struct uv__work* w, int err) {
249
+ uv_work_t* req;
250
+
251
+ req = container_of(w, uv_work_t, work_req);
252
+ uv__req_unregister(req->loop, req);
253
+
254
+ if (req->after_work_cb == NULL)
255
+ return;
256
+
257
+ req->after_work_cb(req, err);
258
+ }
259
+
260
+
261
+ int uv_queue_work(uv_loop_t* loop,
262
+ uv_work_t* req,
263
+ uv_work_cb work_cb,
264
+ uv_after_work_cb after_work_cb) {
265
+ if (work_cb == NULL)
266
+ return UV_EINVAL;
267
+
268
+ uv__req_init(loop, req, UV_WORK);
269
+ req->loop = loop;
270
+ req->work_cb = work_cb;
271
+ req->after_work_cb = after_work_cb;
272
+ uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done);
273
+ return 0;
274
+ }
275
+
276
+
277
+ int uv_cancel(uv_req_t* req) {
278
+ struct uv__work* wreq;
279
+ uv_loop_t* loop;
280
+
281
+ switch (req->type) {
282
+ case UV_FS:
283
+ loop = ((uv_fs_t*) req)->loop;
284
+ wreq = &((uv_fs_t*) req)->work_req;
285
+ break;
286
+ case UV_GETADDRINFO:
287
+ loop = ((uv_getaddrinfo_t*) req)->loop;
288
+ wreq = &((uv_getaddrinfo_t*) req)->work_req;
289
+ break;
290
+ case UV_GETNAMEINFO:
291
+ loop = ((uv_getnameinfo_t*) req)->loop;
292
+ wreq = &((uv_getnameinfo_t*) req)->work_req;
293
+ break;
294
+ case UV_WORK:
295
+ loop = ((uv_work_t*) req)->loop;
296
+ wreq = &((uv_work_t*) req)->work_req;
297
+ break;
298
+ default:
299
+ return UV_EINVAL;
300
+ }
301
+
302
+ return uv__work_cancel(loop, req, wreq);
303
+ }
@@ -0,0 +1,1240 @@
1
+ /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
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 "internal.h"
23
+
24
+ #include <stdio.h>
25
+ #include <stdint.h>
26
+ #include <stdlib.h>
27
+ #include <string.h>
28
+ #include <assert.h>
29
+ #include <errno.h>
30
+
31
+ #include <sys/types.h>
32
+ #include <sys/socket.h>
33
+ #include <sys/ioctl.h>
34
+ #include <net/if.h>
35
+ #include <netinet/in.h>
36
+ #include <arpa/inet.h>
37
+
38
+ #include <sys/time.h>
39
+ #include <unistd.h>
40
+ #include <fcntl.h>
41
+ #include <utmp.h>
42
+ #include <libgen.h>
43
+
44
+ #include <sys/protosw.h>
45
+ #include <libperfstat.h>
46
+ #include <sys/proc.h>
47
+ #include <sys/procfs.h>
48
+
49
+ #include <sys/poll.h>
50
+
51
+ #include <sys/pollset.h>
52
+ #include <ctype.h>
53
+ #include <sys/ahafs_evProds.h>
54
+
55
+ #include <sys/mntctl.h>
56
+ #include <sys/vmount.h>
57
+ #include <limits.h>
58
+ #include <strings.h>
59
+ #include <sys/vnode.h>
60
+
61
+ #define RDWR_BUF_SIZE 4096
62
+ #define EQ(a,b) (strcmp(a,b) == 0)
63
+
64
+ int uv__platform_loop_init(uv_loop_t* loop) {
65
+ loop->fs_fd = -1;
66
+
67
+ /* Passing maxfd of -1 should mean the limit is determined
68
+ * by the user's ulimit or the global limit as per the doc */
69
+ loop->backend_fd = pollset_create(-1);
70
+
71
+ if (loop->backend_fd == -1)
72
+ return -1;
73
+
74
+ return 0;
75
+ }
76
+
77
+
78
+ void uv__platform_loop_delete(uv_loop_t* loop) {
79
+ if (loop->fs_fd != -1) {
80
+ uv__close(loop->fs_fd);
81
+ loop->fs_fd = -1;
82
+ }
83
+
84
+ if (loop->backend_fd != -1) {
85
+ pollset_destroy(loop->backend_fd);
86
+ loop->backend_fd = -1;
87
+ }
88
+ }
89
+
90
+
91
+ void uv__io_poll(uv_loop_t* loop, int timeout) {
92
+ struct pollfd events[1024];
93
+ struct pollfd pqry;
94
+ struct pollfd* pe;
95
+ struct poll_ctl pc;
96
+ QUEUE* q;
97
+ uv__io_t* w;
98
+ uint64_t base;
99
+ uint64_t diff;
100
+ int nevents;
101
+ int count;
102
+ int nfds;
103
+ int i;
104
+ int rc;
105
+ int add_failed;
106
+
107
+ if (loop->nfds == 0) {
108
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
109
+ return;
110
+ }
111
+
112
+ while (!QUEUE_EMPTY(&loop->watcher_queue)) {
113
+ q = QUEUE_HEAD(&loop->watcher_queue);
114
+ QUEUE_REMOVE(q);
115
+ QUEUE_INIT(q);
116
+
117
+ w = QUEUE_DATA(q, uv__io_t, watcher_queue);
118
+ assert(w->pevents != 0);
119
+ assert(w->fd >= 0);
120
+ assert(w->fd < (int) loop->nwatchers);
121
+
122
+ pc.events = w->pevents;
123
+ pc.fd = w->fd;
124
+
125
+ add_failed = 0;
126
+ if (w->events == 0) {
127
+ pc.cmd = PS_ADD;
128
+ if (pollset_ctl(loop->backend_fd, &pc, 1)) {
129
+ if (errno != EINVAL) {
130
+ assert(0 && "Failed to add file descriptor (pc.fd) to pollset");
131
+ abort();
132
+ }
133
+ /* Check if the fd is already in the pollset */
134
+ pqry.fd = pc.fd;
135
+ rc = pollset_query(loop->backend_fd, &pqry);
136
+ switch (rc) {
137
+ case -1:
138
+ assert(0 && "Failed to query pollset for file descriptor");
139
+ abort();
140
+ case 0:
141
+ assert(0 && "Pollset does not contain file descriptor");
142
+ abort();
143
+ }
144
+ /* If we got here then the pollset already contained the file descriptor even though
145
+ * we didn't think it should. This probably shouldn't happen, but we can continue. */
146
+ add_failed = 1;
147
+ }
148
+ }
149
+ if (w->events != 0 || add_failed) {
150
+ /* Modify, potentially removing events -- need to delete then add.
151
+ * Could maybe mod if we knew for sure no events are removed, but
152
+ * content of w->events is handled above as not reliable (falls back)
153
+ * so may require a pollset_query() which would have to be pretty cheap
154
+ * compared to a PS_DELETE to be worth optimizing. Alternatively, could
155
+ * lazily remove events, squelching them in the mean time. */
156
+ pc.cmd = PS_DELETE;
157
+ if (pollset_ctl(loop->backend_fd, &pc, 1)) {
158
+ assert(0 && "Failed to delete file descriptor (pc.fd) from pollset");
159
+ abort();
160
+ }
161
+ pc.cmd = PS_ADD;
162
+ if (pollset_ctl(loop->backend_fd, &pc, 1)) {
163
+ assert(0 && "Failed to add file descriptor (pc.fd) to pollset");
164
+ abort();
165
+ }
166
+ }
167
+
168
+ w->events = w->pevents;
169
+ }
170
+
171
+ assert(timeout >= -1);
172
+ base = loop->time;
173
+ count = 48; /* Benchmarks suggest this gives the best throughput. */
174
+
175
+ for (;;) {
176
+ nfds = pollset_poll(loop->backend_fd,
177
+ events,
178
+ ARRAY_SIZE(events),
179
+ timeout);
180
+
181
+ /* Update loop->time unconditionally. It's tempting to skip the update when
182
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
183
+ * operating system didn't reschedule our process while in the syscall.
184
+ */
185
+ SAVE_ERRNO(uv__update_time(loop));
186
+
187
+ if (nfds == 0) {
188
+ assert(timeout != -1);
189
+ return;
190
+ }
191
+
192
+ if (nfds == -1) {
193
+ if (errno != EINTR) {
194
+ abort();
195
+ }
196
+
197
+ if (timeout == -1)
198
+ continue;
199
+
200
+ if (timeout == 0)
201
+ return;
202
+
203
+ /* Interrupted by a signal. Update timeout and poll again. */
204
+ goto update_timeout;
205
+ }
206
+
207
+ nevents = 0;
208
+
209
+ assert(loop->watchers != NULL);
210
+ loop->watchers[loop->nwatchers] = (void*) events;
211
+ loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
212
+
213
+ for (i = 0; i < nfds; i++) {
214
+ pe = events + i;
215
+ pc.cmd = PS_DELETE;
216
+ pc.fd = pe->fd;
217
+
218
+ /* Skip invalidated events, see uv__platform_invalidate_fd */
219
+ if (pc.fd == -1)
220
+ continue;
221
+
222
+ assert(pc.fd >= 0);
223
+ assert((unsigned) pc.fd < loop->nwatchers);
224
+
225
+ w = loop->watchers[pc.fd];
226
+
227
+ if (w == NULL) {
228
+ /* File descriptor that we've stopped watching, disarm it.
229
+ *
230
+ * Ignore all errors because we may be racing with another thread
231
+ * when the file descriptor is closed.
232
+ */
233
+ pollset_ctl(loop->backend_fd, &pc, 1);
234
+ continue;
235
+ }
236
+
237
+ w->cb(loop, w, pe->revents);
238
+ nevents++;
239
+ }
240
+
241
+ loop->watchers[loop->nwatchers] = NULL;
242
+ loop->watchers[loop->nwatchers + 1] = NULL;
243
+
244
+ if (nevents != 0) {
245
+ if (nfds == ARRAY_SIZE(events) && --count != 0) {
246
+ /* Poll for more events but don't block this time. */
247
+ timeout = 0;
248
+ continue;
249
+ }
250
+ return;
251
+ }
252
+
253
+ if (timeout == 0)
254
+ return;
255
+
256
+ if (timeout == -1)
257
+ continue;
258
+
259
+ update_timeout:
260
+ assert(timeout > 0);
261
+
262
+ diff = loop->time - base;
263
+ if (diff >= (uint64_t) timeout)
264
+ return;
265
+
266
+ timeout -= diff;
267
+ }
268
+ }
269
+
270
+
271
+ uint64_t uv__hrtime(uv_clocktype_t type) {
272
+ uint64_t G = 1000000000;
273
+ timebasestruct_t t;
274
+ read_wall_time(&t, TIMEBASE_SZ);
275
+ time_base_to_time(&t, TIMEBASE_SZ);
276
+ return (uint64_t) t.tb_high * G + t.tb_low;
277
+ }
278
+
279
+
280
+ /*
281
+ * We could use a static buffer for the path manipulations that we need outside
282
+ * of the function, but this function could be called by multiple consumers and
283
+ * we don't want to potentially create a race condition in the use of snprintf.
284
+ * There is no direct way of getting the exe path in AIX - either through /procfs
285
+ * or through some libc APIs. The below approach is to parse the argv[0]'s pattern
286
+ * and use it in conjunction with PATH environment variable to craft one.
287
+ */
288
+ int uv_exepath(char* buffer, size_t* size) {
289
+ ssize_t res;
290
+ char cwd[PATH_MAX], cwdl[PATH_MAX];
291
+ char symlink[PATH_MAX], temp_buffer[PATH_MAX];
292
+ char pp[64];
293
+ struct psinfo ps;
294
+ int fd;
295
+ char **argv;
296
+
297
+ if (buffer == NULL || size == NULL || *size == 0)
298
+ return -EINVAL;
299
+
300
+ snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid());
301
+
302
+ fd = open(pp, O_RDONLY);
303
+ if (fd < 0)
304
+ return fd;
305
+
306
+ res = read(fd, &ps, sizeof(ps));
307
+ uv__close(fd);
308
+ if (res < 0)
309
+ return res;
310
+
311
+ if (ps.pr_argv == 0)
312
+ return -EINVAL;
313
+
314
+ argv = (char **) *((char ***) (intptr_t) ps.pr_argv);
315
+
316
+ if ((argv == NULL) || (argv[0] == NULL))
317
+ return -EINVAL;
318
+
319
+ /*
320
+ * Three possibilities for argv[0]:
321
+ * i) an absolute path such as: /home/user/myprojects/nodejs/node
322
+ * ii) a relative path such as: ./node or ./myprojects/nodejs/node
323
+ * iii) a bare filename such as "node", after exporting PATH variable
324
+ * to its location.
325
+ */
326
+
327
+ /* case #1, absolute path. */
328
+ if (argv[0][0] == '/') {
329
+ snprintf(symlink, PATH_MAX-1, "%s", argv[0]);
330
+
331
+ /* This could or could not be a symlink. */
332
+ res = readlink(symlink, temp_buffer, PATH_MAX-1);
333
+
334
+ /* if readlink fails, it is a normal file just copy symlink to the
335
+ * output buffer.
336
+ */
337
+ if (res < 0) {
338
+ assert(*size > strlen(symlink));
339
+ strcpy(buffer, symlink);
340
+
341
+ /* If it is a link, the resolved filename is again a relative path,
342
+ * make it absolute.
343
+ */
344
+ } else {
345
+ assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
346
+ snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
347
+ }
348
+ *size = strlen(buffer);
349
+ return 0;
350
+
351
+ /* case #2, relative path with usage of '.' */
352
+ } else if (argv[0][0] == '.') {
353
+ char *relative = strchr(argv[0], '/');
354
+ if (relative == NULL)
355
+ return -EINVAL;
356
+
357
+ /* Get the current working directory to resolve the relative path. */
358
+ snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
359
+
360
+ /* This is always a symlink, resolve it. */
361
+ res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
362
+ if (res < 0)
363
+ return -errno;
364
+
365
+ snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, relative + 1);
366
+
367
+ res = readlink(symlink, temp_buffer, PATH_MAX-1);
368
+ if (res < 0) {
369
+ assert(*size > strlen(symlink));
370
+ strcpy(buffer, symlink);
371
+ } else {
372
+ assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
373
+ snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
374
+ }
375
+ *size = strlen(buffer);
376
+ return 0;
377
+
378
+ /* case #3, relative path without usage of '.', such as invocations in Node test suite. */
379
+ } else if (strchr(argv[0], '/') != NULL) {
380
+ /* Get the current working directory to resolve the relative path. */
381
+ snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
382
+
383
+ /* This is always a symlink, resolve it. */
384
+ res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
385
+ if (res < 0)
386
+ return -errno;
387
+
388
+ snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, argv[0]);
389
+
390
+ res = readlink(symlink, temp_buffer, PATH_MAX-1);
391
+ if (res < 0) {
392
+ assert(*size > strlen(symlink));
393
+ strcpy(buffer, symlink);
394
+ } else {
395
+ assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
396
+ snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
397
+ }
398
+ *size = strlen(buffer);
399
+ return 0;
400
+ /* Usage of absolute filename with location exported in PATH */
401
+ } else {
402
+ char clonedpath[8192]; /* assume 8k buffer will fit PATH */
403
+ char *token = NULL;
404
+ struct stat statstruct;
405
+
406
+ /* Get the paths. */
407
+ char *path = getenv("PATH");
408
+ if(sizeof(clonedpath) <= strlen(path))
409
+ return -EINVAL;
410
+
411
+ /* Get a local copy. */
412
+ strcpy(clonedpath, path);
413
+
414
+ /* Tokenize. */
415
+ token = strtok(clonedpath, ":");
416
+
417
+ /* Get current working directory. (may be required in the loop). */
418
+ snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
419
+ res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
420
+ if (res < 0)
421
+ return -errno;
422
+ /* Run through the tokens, append our executable file name with each,
423
+ * and see which one succeeds. Exit on first match. */
424
+ while(token != NULL) {
425
+ if (token[0] == '.') {
426
+ /* Path contains a token relative to current directory. */
427
+ char *relative = strchr(token, '/');
428
+ if (relative != NULL)
429
+ /* A path which is not current directory. */
430
+ snprintf(symlink, PATH_MAX-1, "%s%s/%s", cwdl, relative+1, ps.pr_fname);
431
+ else
432
+ snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, ps.pr_fname);
433
+ if (stat(symlink, &statstruct) != -1) {
434
+ /* File exists. Resolve if it is a link. */
435
+ res = readlink(symlink, temp_buffer, PATH_MAX-1);
436
+ if (res < 0) {
437
+ assert(*size > strlen(symlink));
438
+ strcpy(buffer, symlink);
439
+ } else {
440
+ assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
441
+ snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
442
+ }
443
+ *size = strlen(buffer);
444
+ return 0;
445
+ }
446
+
447
+ /* Absolute path names. */
448
+ } else {
449
+ snprintf(symlink, PATH_MAX-1, "%s/%s", token, ps.pr_fname);
450
+ if (stat(symlink, &statstruct) != -1) {
451
+ res = readlink(symlink, temp_buffer, PATH_MAX-1);
452
+ if (res < 0) {
453
+ assert(*size > strlen(symlink));
454
+ strcpy(buffer, symlink);
455
+ } else {
456
+ assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer)));
457
+ snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer);
458
+ }
459
+ *size = strlen(buffer);
460
+ return 0;
461
+ }
462
+ }
463
+ token = strtok(NULL, ":");
464
+ }
465
+ /* Out of tokens (path entries), and no match found */
466
+ return -EINVAL;
467
+ }
468
+ }
469
+
470
+
471
+ uint64_t uv_get_free_memory(void) {
472
+ perfstat_memory_total_t mem_total;
473
+ int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
474
+ if (result == -1) {
475
+ return 0;
476
+ }
477
+ return mem_total.real_free * 4096;
478
+ }
479
+
480
+
481
+ uint64_t uv_get_total_memory(void) {
482
+ perfstat_memory_total_t mem_total;
483
+ int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
484
+ if (result == -1) {
485
+ return 0;
486
+ }
487
+ return mem_total.real_total * 4096;
488
+ }
489
+
490
+
491
+ void uv_loadavg(double avg[3]) {
492
+ perfstat_cpu_total_t ps_total;
493
+ int result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
494
+ if (result == -1) {
495
+ avg[0] = 0.; avg[1] = 0.; avg[2] = 0.;
496
+ return;
497
+ }
498
+ avg[0] = ps_total.loadavg[0] / (double)(1 << SBITS);
499
+ avg[1] = ps_total.loadavg[1] / (double)(1 << SBITS);
500
+ avg[2] = ps_total.loadavg[2] / (double)(1 << SBITS);
501
+ }
502
+
503
+
504
+ static char *uv__rawname(char *cp) {
505
+ static char rawbuf[FILENAME_MAX+1];
506
+ char *dp = rindex(cp, '/');
507
+
508
+ if (dp == 0)
509
+ return 0;
510
+
511
+ *dp = 0;
512
+ strcpy(rawbuf, cp);
513
+ *dp = '/';
514
+ strcat(rawbuf, "/r");
515
+ strcat(rawbuf, dp+1);
516
+ return rawbuf;
517
+ }
518
+
519
+
520
+ /*
521
+ * Determine whether given pathname is a directory
522
+ * Returns 0 if the path is a directory, -1 if not
523
+ *
524
+ * Note: Opportunity here for more detailed error information but
525
+ * that requires changing callers of this function as well
526
+ */
527
+ static int uv__path_is_a_directory(char* filename) {
528
+ struct stat statbuf;
529
+
530
+ if (stat(filename, &statbuf) < 0)
531
+ return -1; /* failed: not a directory, assume it is a file */
532
+
533
+ if (statbuf.st_type == VDIR)
534
+ return 0;
535
+
536
+ return -1;
537
+ }
538
+
539
+
540
+ /*
541
+ * Check whether AHAFS is mounted.
542
+ * Returns 0 if AHAFS is mounted, or an error code < 0 on failure
543
+ */
544
+ static int uv__is_ahafs_mounted(void){
545
+ int rv, i = 2;
546
+ struct vmount *p;
547
+ int size_multiplier = 10;
548
+ size_t siz = sizeof(struct vmount)*size_multiplier;
549
+ struct vmount *vmt;
550
+ const char *dev = "/aha";
551
+ char *obj, *stub;
552
+
553
+ p = malloc(siz);
554
+ if (p == NULL)
555
+ return -errno;
556
+
557
+ /* Retrieve all mounted filesystems */
558
+ rv = mntctl(MCTL_QUERY, siz, (char*)p);
559
+ if (rv < 0)
560
+ return -errno;
561
+ if (rv == 0) {
562
+ /* buffer was not large enough, reallocate to correct size */
563
+ siz = *(int*)p;
564
+ free(p);
565
+ p = malloc(siz);
566
+ if (p == NULL)
567
+ return -errno;
568
+ rv = mntctl(MCTL_QUERY, siz, (char*)p);
569
+ if (rv < 0)
570
+ return -errno;
571
+ }
572
+
573
+ /* Look for dev in filesystems mount info */
574
+ for(vmt = p, i = 0; i < rv; i++) {
575
+ obj = vmt2dataptr(vmt, VMT_OBJECT); /* device */
576
+ stub = vmt2dataptr(vmt, VMT_STUB); /* mount point */
577
+
578
+ if (EQ(obj, dev) || EQ(uv__rawname(obj), dev) || EQ(stub, dev)) {
579
+ free(p); /* Found a match */
580
+ return 0;
581
+ }
582
+ vmt = (struct vmount *) ((char *) vmt + vmt->vmt_length);
583
+ }
584
+
585
+ /* /aha is required for monitoring filesystem changes */
586
+ return -1;
587
+ }
588
+
589
+ /*
590
+ * Recursive call to mkdir() to create intermediate folders, if any
591
+ * Returns code from mkdir call
592
+ */
593
+ static int uv__makedir_p(const char *dir) {
594
+ char tmp[256];
595
+ char *p = NULL;
596
+ size_t len;
597
+ int err;
598
+
599
+ snprintf(tmp, sizeof(tmp),"%s",dir);
600
+ len = strlen(tmp);
601
+ if (tmp[len - 1] == '/')
602
+ tmp[len - 1] = 0;
603
+ for (p = tmp + 1; *p; p++) {
604
+ if (*p == '/') {
605
+ *p = 0;
606
+ err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
607
+ if(err != 0)
608
+ return err;
609
+ *p = '/';
610
+ }
611
+ }
612
+ return mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
613
+ }
614
+
615
+ /*
616
+ * Creates necessary subdirectories in the AIX Event Infrastructure
617
+ * file system for monitoring the object specified.
618
+ * Returns code from mkdir call
619
+ */
620
+ static int uv__make_subdirs_p(const char *filename) {
621
+ char cmd[2048];
622
+ char *p;
623
+ int rc = 0;
624
+
625
+ /* Strip off the monitor file name */
626
+ p = strrchr(filename, '/');
627
+
628
+ if (p == NULL)
629
+ return 0;
630
+
631
+ if (uv__path_is_a_directory((char*)filename) == 0) {
632
+ sprintf(cmd, "/aha/fs/modDir.monFactory");
633
+ } else {
634
+ sprintf(cmd, "/aha/fs/modFile.monFactory");
635
+ }
636
+
637
+ strncat(cmd, filename, (p - filename));
638
+ rc = uv__makedir_p(cmd);
639
+
640
+ if (rc == -1 && errno != EEXIST){
641
+ return -errno;
642
+ }
643
+
644
+ return rc;
645
+ }
646
+
647
+
648
+ /*
649
+ * Checks if /aha is mounted, then proceeds to set up the monitoring
650
+ * objects for the specified file.
651
+ * Returns 0 on success, or an error code < 0 on failure
652
+ */
653
+ static int uv__setup_ahafs(const char* filename, int *fd) {
654
+ int rc = 0;
655
+ char mon_file_write_string[RDWR_BUF_SIZE];
656
+ char mon_file[PATH_MAX];
657
+ int file_is_directory = 0; /* -1 == NO, 0 == YES */
658
+
659
+ /* Create monitor file name for object */
660
+ file_is_directory = uv__path_is_a_directory((char*)filename);
661
+
662
+ if (file_is_directory == 0)
663
+ sprintf(mon_file, "/aha/fs/modDir.monFactory");
664
+ else
665
+ sprintf(mon_file, "/aha/fs/modFile.monFactory");
666
+
667
+ if ((strlen(mon_file) + strlen(filename) + 5) > PATH_MAX)
668
+ return -ENAMETOOLONG;
669
+
670
+ /* Make the necessary subdirectories for the monitor file */
671
+ rc = uv__make_subdirs_p(filename);
672
+ if (rc == -1 && errno != EEXIST)
673
+ return rc;
674
+
675
+ strcat(mon_file, filename);
676
+ strcat(mon_file, ".mon");
677
+
678
+ *fd = 0; errno = 0;
679
+
680
+ /* Open the monitor file, creating it if necessary */
681
+ *fd = open(mon_file, O_CREAT|O_RDWR);
682
+ if (*fd < 0)
683
+ return -errno;
684
+
685
+ /* Write out the monitoring specifications.
686
+ * In this case, we are monitoring for a state change event type
687
+ * CHANGED=YES
688
+ * We will be waiting in select call, rather than a read:
689
+ * WAIT_TYPE=WAIT_IN_SELECT
690
+ * We only want minimal information for files:
691
+ * INFO_LVL=1
692
+ * For directories, we want more information to track what file
693
+ * caused the change
694
+ * INFO_LVL=2
695
+ */
696
+
697
+ if (file_is_directory == 0)
698
+ sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=2");
699
+ else
700
+ sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1");
701
+
702
+ rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1);
703
+ if (rc < 0)
704
+ return -errno;
705
+
706
+ return 0;
707
+ }
708
+
709
+ /*
710
+ * Skips a specified number of lines in the buffer passed in.
711
+ * Walks the buffer pointed to by p and attempts to skip n lines.
712
+ * Returns the total number of lines skipped
713
+ */
714
+ static int uv__skip_lines(char **p, int n) {
715
+ int lines = 0;
716
+
717
+ while(n > 0) {
718
+ *p = strchr(*p, '\n');
719
+ if (!p)
720
+ return lines;
721
+
722
+ (*p)++;
723
+ n--;
724
+ lines++;
725
+ }
726
+ return lines;
727
+ }
728
+
729
+
730
+ /*
731
+ * Parse the event occurrence data to figure out what event just occurred
732
+ * and take proper action.
733
+ *
734
+ * The buf is a pointer to the buffer containing the event occurrence data
735
+ * Returns 0 on success, -1 if unrecoverable error in parsing
736
+ *
737
+ */
738
+ static int uv__parse_data(char *buf, int *events, uv_fs_event_t* handle) {
739
+ int evp_rc, i;
740
+ char *p;
741
+ char filename[PATH_MAX]; /* To be used when handling directories */
742
+
743
+ p = buf;
744
+ *events = 0;
745
+
746
+ /* Clean the filename buffer*/
747
+ for(i = 0; i < PATH_MAX; i++) {
748
+ filename[i] = 0;
749
+ }
750
+ i = 0;
751
+
752
+ /* Check for BUF_WRAP */
753
+ if (strncmp(buf, "BUF_WRAP", strlen("BUF_WRAP")) == 0) {
754
+ assert(0 && "Buffer wrap detected, Some event occurrences lost!");
755
+ return 0;
756
+ }
757
+
758
+ /* Since we are using the default buffer size (4K), and have specified
759
+ * INFO_LVL=1, we won't see any EVENT_OVERFLOW conditions. Applications
760
+ * should check for this keyword if they are using an INFO_LVL of 2 or
761
+ * higher, and have a buffer size of <= 4K
762
+ */
763
+
764
+ /* Skip to RC_FROM_EVPROD */
765
+ if (uv__skip_lines(&p, 9) != 9)
766
+ return -1;
767
+
768
+ if (sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1) {
769
+ if (uv__path_is_a_directory(handle->path) == 0) { /* Directory */
770
+ if (evp_rc == AHAFS_MODDIR_UNMOUNT || evp_rc == AHAFS_MODDIR_REMOVE_SELF) {
771
+ /* The directory is no longer available for monitoring */
772
+ *events = UV_RENAME;
773
+ handle->dir_filename = NULL;
774
+ } else {
775
+ /* A file was added/removed inside the directory */
776
+ *events = UV_CHANGE;
777
+
778
+ /* Get the EVPROD_INFO */
779
+ if (uv__skip_lines(&p, 1) != 1)
780
+ return -1;
781
+
782
+ /* Scan out the name of the file that triggered the event*/
783
+ if (sscanf(p, "BEGIN_EVPROD_INFO\n%sEND_EVPROD_INFO", filename) == 1) {
784
+ handle->dir_filename = strdup((const char*)&filename);
785
+ } else
786
+ return -1;
787
+ }
788
+ } else { /* Regular File */
789
+ if (evp_rc == AHAFS_MODFILE_RENAME)
790
+ *events = UV_RENAME;
791
+ else
792
+ *events = UV_CHANGE;
793
+ }
794
+ }
795
+ else
796
+ return -1;
797
+
798
+ return 0;
799
+ }
800
+
801
+
802
+ /* This is the internal callback */
803
+ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int fflags) {
804
+ char result_data[RDWR_BUF_SIZE];
805
+ int bytes, rc = 0;
806
+ uv_fs_event_t* handle;
807
+ int events = 0;
808
+ int i = 0;
809
+ char fname[PATH_MAX];
810
+ char *p;
811
+
812
+ handle = container_of(event_watch, uv_fs_event_t, event_watcher);
813
+
814
+ /* Clean all the buffers*/
815
+ for(i = 0; i < PATH_MAX; i++) {
816
+ fname[i] = 0;
817
+ }
818
+ i = 0;
819
+
820
+ /* At this point, we assume that polling has been done on the
821
+ * file descriptor, so we can just read the AHAFS event occurrence
822
+ * data and parse its results without having to block anything
823
+ */
824
+ bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0);
825
+
826
+ assert((bytes <= 0) && "uv__ahafs_event - Error reading monitor file");
827
+
828
+ /* Parse the data */
829
+ if(bytes > 0)
830
+ rc = uv__parse_data(result_data, &events, handle);
831
+
832
+ /* For directory changes, the name of the files that triggered the change
833
+ * are never absolute pathnames
834
+ */
835
+ if (uv__path_is_a_directory(handle->path) == 0) {
836
+ p = handle->dir_filename;
837
+ while(*p != NULL){
838
+ fname[i]= *p;
839
+ i++;
840
+ p++;
841
+ }
842
+ } else {
843
+ /* For file changes, figure out whether filename is absolute or not */
844
+ if (handle->path[0] == '/') {
845
+ p = strrchr(handle->path, '/');
846
+ p++;
847
+
848
+ while(*p != NULL) {
849
+ fname[i]= *p;
850
+ i++;
851
+ p++;
852
+ }
853
+ }
854
+ }
855
+
856
+ /* Unrecoverable error */
857
+ if (rc == -1)
858
+ return;
859
+ else /* Call the actual JavaScript callback function */
860
+ handle->cb(handle, (const char*)&fname, events, 0);
861
+ }
862
+
863
+
864
+ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
865
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
866
+ return 0;
867
+ }
868
+
869
+
870
+ int uv_fs_event_start(uv_fs_event_t* handle,
871
+ uv_fs_event_cb cb,
872
+ const char* filename,
873
+ unsigned int flags) {
874
+ int fd, rc, i = 0, res = 0;
875
+ char cwd[PATH_MAX];
876
+ char absolute_path[PATH_MAX];
877
+ char fname[PATH_MAX];
878
+ char *p;
879
+
880
+ /* Clean all the buffers*/
881
+ for(i = 0; i < PATH_MAX; i++) {
882
+ cwd[i] = 0;
883
+ absolute_path[i] = 0;
884
+ fname[i] = 0;
885
+ }
886
+ i = 0;
887
+
888
+ /* Figure out whether filename is absolute or not */
889
+ if (filename[0] == '/') {
890
+ /* We have absolute pathname, create the relative pathname*/
891
+ sprintf(absolute_path, filename);
892
+ p = strrchr(filename, '/');
893
+ p++;
894
+ } else {
895
+ if (filename[0] == '.' && filename[1] == '/') {
896
+ /* We have a relative pathname, compose the absolute pathname */
897
+ sprintf(fname, filename);
898
+ snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
899
+ res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1);
900
+ if (res < 0)
901
+ return res;
902
+ p = strrchr(absolute_path, '/');
903
+ p++;
904
+ p++;
905
+ } else {
906
+ /* We have a relative pathname, compose the absolute pathname */
907
+ sprintf(fname, filename);
908
+ snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
909
+ res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1);
910
+ if (res < 0)
911
+ return res;
912
+ p = strrchr(absolute_path, '/');
913
+ p++;
914
+ }
915
+ /* Copy to filename buffer */
916
+ while(filename[i] != NULL) {
917
+ *p = filename[i];
918
+ i++;
919
+ p++;
920
+ }
921
+ }
922
+
923
+ if (uv__is_ahafs_mounted() < 0) /* /aha checks failed */
924
+ return UV_ENOSYS;
925
+
926
+ /* Setup ahafs */
927
+ rc = uv__setup_ahafs((const char *)absolute_path, &fd);
928
+ if (rc != 0)
929
+ return rc;
930
+
931
+ /* Setup/Initialize all the libuv routines */
932
+ uv__handle_start(handle);
933
+ uv__io_init(&handle->event_watcher, uv__ahafs_event, fd);
934
+ handle->path = strdup((const char*)&absolute_path);
935
+ handle->cb = cb;
936
+
937
+ uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN);
938
+
939
+ return 0;
940
+ }
941
+
942
+
943
+ int uv_fs_event_stop(uv_fs_event_t* handle) {
944
+
945
+ if (!uv__is_active(handle))
946
+ return 0;
947
+
948
+ uv__io_close(handle->loop, &handle->event_watcher);
949
+ uv__handle_stop(handle);
950
+
951
+ if (uv__path_is_a_directory(handle->path) == 0) {
952
+ free(handle->dir_filename);
953
+ handle->dir_filename = NULL;
954
+ }
955
+
956
+ free(handle->path);
957
+ handle->path = NULL;
958
+ uv__close(handle->event_watcher.fd);
959
+ handle->event_watcher.fd = -1;
960
+
961
+ return 0;
962
+ }
963
+
964
+
965
+ void uv__fs_event_close(uv_fs_event_t* handle) {
966
+ uv_fs_event_stop(handle);
967
+ }
968
+
969
+
970
+ char** uv_setup_args(int argc, char** argv) {
971
+ return argv;
972
+ }
973
+
974
+
975
+ int uv_set_process_title(const char* title) {
976
+ return 0;
977
+ }
978
+
979
+
980
+ int uv_get_process_title(char* buffer, size_t size) {
981
+ if (size > 0) {
982
+ buffer[0] = '\0';
983
+ }
984
+ return 0;
985
+ }
986
+
987
+
988
+ int uv_resident_set_memory(size_t* rss) {
989
+ char pp[64];
990
+ psinfo_t psinfo;
991
+ int err;
992
+ int fd;
993
+
994
+ snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid());
995
+
996
+ fd = open(pp, O_RDONLY);
997
+ if (fd == -1)
998
+ return -errno;
999
+
1000
+ /* FIXME(bnoordhuis) Handle EINTR. */
1001
+ err = -EINVAL;
1002
+ if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
1003
+ *rss = (size_t)psinfo.pr_rssize * 1024;
1004
+ err = 0;
1005
+ }
1006
+ uv__close(fd);
1007
+
1008
+ return err;
1009
+ }
1010
+
1011
+
1012
+ int uv_uptime(double* uptime) {
1013
+ struct utmp *utmp_buf;
1014
+ size_t entries = 0;
1015
+ time_t boot_time;
1016
+
1017
+ utmpname(UTMP_FILE);
1018
+
1019
+ setutent();
1020
+
1021
+ while ((utmp_buf = getutent()) != NULL) {
1022
+ if (utmp_buf->ut_user[0] && utmp_buf->ut_type == USER_PROCESS)
1023
+ ++entries;
1024
+ if (utmp_buf->ut_type == BOOT_TIME)
1025
+ boot_time = utmp_buf->ut_time;
1026
+ }
1027
+
1028
+ endutent();
1029
+
1030
+ if (boot_time == 0)
1031
+ return -ENOSYS;
1032
+
1033
+ *uptime = time(NULL) - boot_time;
1034
+ return 0;
1035
+ }
1036
+
1037
+
1038
+ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
1039
+ uv_cpu_info_t* cpu_info;
1040
+ perfstat_cpu_total_t ps_total;
1041
+ perfstat_cpu_t* ps_cpus;
1042
+ perfstat_id_t cpu_id;
1043
+ int result, ncpus, idx = 0;
1044
+
1045
+ result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
1046
+ if (result == -1) {
1047
+ return -ENOSYS;
1048
+ }
1049
+
1050
+ ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
1051
+ if (result == -1) {
1052
+ return -ENOSYS;
1053
+ }
1054
+
1055
+ ps_cpus = (perfstat_cpu_t*) malloc(ncpus * sizeof(perfstat_cpu_t));
1056
+ if (!ps_cpus) {
1057
+ return -ENOMEM;
1058
+ }
1059
+
1060
+ strcpy(cpu_id.name, FIRST_CPU);
1061
+ result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus);
1062
+ if (result == -1) {
1063
+ free(ps_cpus);
1064
+ return -ENOSYS;
1065
+ }
1066
+
1067
+ *cpu_infos = (uv_cpu_info_t*) malloc(ncpus * sizeof(uv_cpu_info_t));
1068
+ if (!*cpu_infos) {
1069
+ free(ps_cpus);
1070
+ return -ENOMEM;
1071
+ }
1072
+
1073
+ *count = ncpus;
1074
+
1075
+ cpu_info = *cpu_infos;
1076
+ while (idx < ncpus) {
1077
+ cpu_info->speed = (int)(ps_total.processorHZ / 1000000);
1078
+ cpu_info->model = strdup(ps_total.description);
1079
+ cpu_info->cpu_times.user = ps_cpus[idx].user;
1080
+ cpu_info->cpu_times.sys = ps_cpus[idx].sys;
1081
+ cpu_info->cpu_times.idle = ps_cpus[idx].idle;
1082
+ cpu_info->cpu_times.irq = ps_cpus[idx].wait;
1083
+ cpu_info->cpu_times.nice = 0;
1084
+ cpu_info++;
1085
+ idx++;
1086
+ }
1087
+
1088
+ free(ps_cpus);
1089
+ return 0;
1090
+ }
1091
+
1092
+
1093
+ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
1094
+ int i;
1095
+
1096
+ for (i = 0; i < count; ++i) {
1097
+ free(cpu_infos[i].model);
1098
+ }
1099
+
1100
+ free(cpu_infos);
1101
+ }
1102
+
1103
+
1104
+ int uv_interface_addresses(uv_interface_address_t** addresses,
1105
+ int* count) {
1106
+ uv_interface_address_t* address;
1107
+ int sockfd, size = 1;
1108
+ struct ifconf ifc;
1109
+ struct ifreq *ifr, *p, flg;
1110
+
1111
+ *count = 0;
1112
+
1113
+ if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
1114
+ return -errno;
1115
+ }
1116
+
1117
+ if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
1118
+ SAVE_ERRNO(uv__close(sockfd));
1119
+ return -errno;
1120
+ }
1121
+
1122
+ ifc.ifc_req = (struct ifreq*)malloc(size);
1123
+ ifc.ifc_len = size;
1124
+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
1125
+ SAVE_ERRNO(uv__close(sockfd));
1126
+ return -errno;
1127
+ }
1128
+
1129
+ #define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
1130
+
1131
+ /* Count all up and running ipv4/ipv6 addresses */
1132
+ ifr = ifc.ifc_req;
1133
+ while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
1134
+ p = ifr;
1135
+ ifr = (struct ifreq*)
1136
+ ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
1137
+
1138
+ if (!(p->ifr_addr.sa_family == AF_INET6 ||
1139
+ p->ifr_addr.sa_family == AF_INET))
1140
+ continue;
1141
+
1142
+ memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
1143
+ if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
1144
+ SAVE_ERRNO(uv__close(sockfd));
1145
+ return -errno;
1146
+ }
1147
+
1148
+ if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
1149
+ continue;
1150
+
1151
+ (*count)++;
1152
+ }
1153
+
1154
+ /* Alloc the return interface structs */
1155
+ *addresses = (uv_interface_address_t*)
1156
+ malloc(*count * sizeof(uv_interface_address_t));
1157
+ if (!(*addresses)) {
1158
+ uv__close(sockfd);
1159
+ return -ENOMEM;
1160
+ }
1161
+ address = *addresses;
1162
+
1163
+ ifr = ifc.ifc_req;
1164
+ while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
1165
+ p = ifr;
1166
+ ifr = (struct ifreq*)
1167
+ ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
1168
+
1169
+ if (!(p->ifr_addr.sa_family == AF_INET6 ||
1170
+ p->ifr_addr.sa_family == AF_INET))
1171
+ continue;
1172
+
1173
+ memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
1174
+ if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
1175
+ uv__close(sockfd);
1176
+ return -ENOSYS;
1177
+ }
1178
+
1179
+ if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
1180
+ continue;
1181
+
1182
+ /* All conditions above must match count loop */
1183
+
1184
+ address->name = strdup(p->ifr_name);
1185
+
1186
+ if (p->ifr_addr.sa_family == AF_INET6) {
1187
+ address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
1188
+ } else {
1189
+ address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
1190
+ }
1191
+
1192
+ /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
1193
+
1194
+ address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
1195
+
1196
+ address++;
1197
+ }
1198
+
1199
+ #undef ADDR_SIZE
1200
+
1201
+ uv__close(sockfd);
1202
+ return 0;
1203
+ }
1204
+
1205
+
1206
+ void uv_free_interface_addresses(uv_interface_address_t* addresses,
1207
+ int count) {
1208
+ int i;
1209
+
1210
+ for (i = 0; i < count; ++i) {
1211
+ free(addresses[i].name);
1212
+ }
1213
+
1214
+ free(addresses);
1215
+ }
1216
+
1217
+ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
1218
+ struct pollfd* events;
1219
+ uintptr_t i;
1220
+ uintptr_t nfds;
1221
+ struct poll_ctl pc;
1222
+
1223
+ assert(loop->watchers != NULL);
1224
+
1225
+ events = (struct pollfd*) loop->watchers[loop->nwatchers];
1226
+ nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
1227
+
1228
+ if (events != NULL)
1229
+ /* Invalidate events with same file descriptor */
1230
+ for (i = 0; i < nfds; i++)
1231
+ if ((int) events[i].fd == fd)
1232
+ events[i].fd = -1;
1233
+
1234
+ /* Remove the file descriptor from the poll set */
1235
+ pc.events = 0;
1236
+ pc.cmd = PS_DELETE;
1237
+ pc.fd = fd;
1238
+ if(loop->backend_fd >= 0)
1239
+ pollset_ctl(loop->backend_fd, &pc, 1);
1240
+ }