|
160
|
1 /* Copyright libuv project 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.h"
|
|
|
23 #include "internal.h"
|
|
|
24 #include <sys/ioctl.h>
|
|
|
25 #include <net/if.h>
|
|
|
26 #include <utmpx.h>
|
|
|
27 #include <unistd.h>
|
|
|
28 #include <sys/ps.h>
|
|
|
29 #include <builtins.h>
|
|
|
30 #include <termios.h>
|
|
|
31 #include <sys/msg.h>
|
|
|
32 #include <sys/resource.h>
|
|
|
33 #include "zos-base.h"
|
|
|
34 #include "zos-sys-info.h"
|
|
|
35 #if defined(__clang__)
|
|
|
36 #include "csrsic.h"
|
|
|
37 #else
|
|
|
38 #include "//'SYS1.SAMPLIB(CSRSIC)'"
|
|
|
39 #endif
|
|
|
40
|
|
|
41 #define CVT_PTR 0x10
|
|
|
42 #define PSA_PTR 0x00
|
|
|
43 #define CSD_OFFSET 0x294
|
|
|
44
|
|
|
45 /*
|
|
|
46 Long-term average CPU service used by this logical partition,
|
|
|
47 in millions of service units per hour. If this value is above
|
|
|
48 the partition's defined capacity, the partition will be capped.
|
|
|
49 It is calculated using the physical CPU adjustment factor
|
|
|
50 (RCTPCPUA) so it may not match other measures of service which
|
|
|
51 are based on the logical CPU adjustment factor. It is available
|
|
|
52 if the hardware supports LPAR cluster.
|
|
|
53 */
|
|
|
54 #define RCTLACS_OFFSET 0xC4
|
|
|
55
|
|
|
56 /* 32-bit count of alive CPUs. This includes both CPs and IFAs */
|
|
|
57 #define CSD_NUMBER_ONLINE_CPUS 0xD4
|
|
|
58
|
|
|
59 /* Address of system resources manager (SRM) control table */
|
|
|
60 #define CVTOPCTP_OFFSET 0x25C
|
|
|
61
|
|
|
62 /* Address of the RCT table */
|
|
|
63 #define RMCTRCT_OFFSET 0xE4
|
|
|
64
|
|
|
65 /* Address of the rsm control and enumeration area. */
|
|
|
66 #define CVTRCEP_OFFSET 0x490
|
|
|
67
|
|
|
68 /* Total number of frames currently on all available frame queues. */
|
|
|
69 #define RCEAFC_OFFSET 0x088
|
|
|
70
|
|
|
71 /* Pointer to the home (current) ASCB. */
|
|
|
72 #define PSAAOLD 0x224
|
|
|
73
|
|
|
74 /* Pointer to rsm address space block extension. */
|
|
|
75 #define ASCBRSME 0x16C
|
|
|
76
|
|
|
77 /*
|
|
|
78 NUMBER OF FRAMES CURRENTLY IN USE BY THIS ADDRESS SPACE.
|
|
|
79 It does not include 2G frames.
|
|
|
80 */
|
|
|
81 #define RAXFMCT 0x2C
|
|
|
82
|
|
|
83 /* Thread Entry constants */
|
|
|
84 #define PGTH_CURRENT 1
|
|
|
85 #define PGTH_LEN 26
|
|
|
86 #define PGTHAPATH 0x20
|
|
|
87 #pragma linkage(BPX4GTH, OS)
|
|
|
88 #pragma linkage(BPX1GTH, OS)
|
|
|
89
|
|
|
90 /* TOD Clock resolution in nanoseconds */
|
|
|
91 #define TOD_RES 4.096
|
|
|
92
|
|
|
93 typedef unsigned data_area_ptr_assign_type;
|
|
|
94
|
|
|
95 typedef union {
|
|
|
96 struct {
|
|
|
97 #if defined(_LP64)
|
|
|
98 data_area_ptr_assign_type lower;
|
|
|
99 #endif
|
|
|
100 data_area_ptr_assign_type assign;
|
|
|
101 };
|
|
|
102 char* deref;
|
|
|
103 } data_area_ptr;
|
|
|
104
|
|
|
105
|
|
|
106 void uv_loadavg(double avg[3]) {
|
|
|
107 /* TODO: implement the following */
|
|
|
108 avg[0] = 0;
|
|
|
109 avg[1] = 0;
|
|
|
110 avg[2] = 0;
|
|
|
111 }
|
|
|
112
|
|
|
113
|
|
|
114 int uv__platform_loop_init(uv_loop_t* loop) {
|
|
|
115 uv__os390_epoll* ep;
|
|
|
116
|
|
|
117 ep = epoll_create1(0);
|
|
|
118 loop->ep = ep;
|
|
|
119 if (ep == NULL)
|
|
|
120 return UV__ERR(errno);
|
|
|
121
|
|
|
122 return 0;
|
|
|
123 }
|
|
|
124
|
|
|
125
|
|
|
126 void uv__platform_loop_delete(uv_loop_t* loop) {
|
|
|
127 if (loop->ep != NULL) {
|
|
|
128 epoll_queue_close(loop->ep);
|
|
|
129 loop->ep = NULL;
|
|
|
130 }
|
|
|
131 }
|
|
|
132
|
|
|
133
|
|
|
134 uint64_t uv__hrtime(uv_clocktype_t type) {
|
|
|
135 unsigned long long timestamp;
|
|
|
136 __stckf(×tamp);
|
|
|
137 /* Convert to nanoseconds */
|
|
|
138 return timestamp / TOD_RES;
|
|
|
139 }
|
|
|
140
|
|
|
141
|
|
|
142 static int getexe(char* buf, size_t len) {
|
|
|
143 return uv__strscpy(buf, __getargv()[0], len);
|
|
|
144 }
|
|
|
145
|
|
|
146
|
|
|
147 /*
|
|
|
148 * We could use a static buffer for the path manipulations that we need outside
|
|
|
149 * of the function, but this function could be called by multiple consumers and
|
|
|
150 * we don't want to potentially create a race condition in the use of snprintf.
|
|
|
151 * There is no direct way of getting the exe path in zOS - either through /procfs
|
|
|
152 * or through some libc APIs. The below approach is to parse the argv[0]'s pattern
|
|
|
153 * and use it in conjunction with PATH environment variable to craft one.
|
|
|
154 */
|
|
|
155 int uv_exepath(char* buffer, size_t* size) {
|
|
|
156 int res;
|
|
|
157 char args[PATH_MAX];
|
|
|
158 int pid;
|
|
|
159
|
|
|
160 if (buffer == NULL || size == NULL || *size == 0)
|
|
|
161 return UV_EINVAL;
|
|
|
162
|
|
|
163 res = getexe(args, sizeof(args));
|
|
|
164 if (res < 0)
|
|
|
165 return UV_EINVAL;
|
|
|
166
|
|
|
167 return uv__search_path(args, buffer, size);
|
|
|
168 }
|
|
|
169
|
|
|
170
|
|
|
171 uint64_t uv_get_free_memory(void) {
|
|
|
172 uint64_t freeram;
|
|
|
173
|
|
|
174 data_area_ptr cvt = {0};
|
|
|
175 data_area_ptr rcep = {0};
|
|
|
176 cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
|
|
|
177 rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
|
|
|
178 freeram = (uint64_t)*((uint32_t*)(rcep.deref + RCEAFC_OFFSET)) * 4096;
|
|
|
179 return freeram;
|
|
|
180 }
|
|
|
181
|
|
|
182
|
|
|
183 uint64_t uv_get_total_memory(void) {
|
|
|
184 /* Use CVTRLSTG to get the size of actual real storage online at IPL in K. */
|
|
|
185 return (uint64_t)((int)((char *__ptr32 *__ptr32 *)0)[4][214]) * 1024;
|
|
|
186 }
|
|
|
187
|
|
|
188
|
|
|
189 uint64_t uv_get_constrained_memory(void) {
|
|
|
190 struct rlimit rl;
|
|
|
191
|
|
|
192 /* RLIMIT_MEMLIMIT return value is in megabytes rather than bytes. */
|
|
|
193 if (getrlimit(RLIMIT_MEMLIMIT, &rl) == 0)
|
|
|
194 return rl.rlim_cur * 1024 * 1024;
|
|
|
195
|
|
|
196 return 0; /* There is no memory limit set. */
|
|
|
197 }
|
|
|
198
|
|
|
199
|
|
|
200 uint64_t uv_get_available_memory(void) {
|
|
|
201 return uv_get_free_memory();
|
|
|
202 }
|
|
|
203
|
|
|
204
|
|
|
205 int uv_resident_set_memory(size_t* rss) {
|
|
|
206 char* ascb;
|
|
|
207 char* rax;
|
|
|
208 size_t nframes;
|
|
|
209
|
|
|
210 ascb = *(char* __ptr32 *)(PSA_PTR + PSAAOLD);
|
|
|
211 rax = *(char* __ptr32 *)(ascb + ASCBRSME);
|
|
|
212 nframes = *(unsigned int*)(rax + RAXFMCT);
|
|
|
213
|
|
|
214 *rss = nframes * sysconf(_SC_PAGESIZE);
|
|
|
215 return 0;
|
|
|
216 }
|
|
|
217
|
|
|
218
|
|
|
219 int uv_uptime(double* uptime) {
|
|
|
220 struct utmpx u ;
|
|
|
221 struct utmpx *v;
|
|
|
222 time64_t t;
|
|
|
223
|
|
|
224 u.ut_type = BOOT_TIME;
|
|
|
225 v = getutxid(&u);
|
|
|
226 if (v == NULL)
|
|
|
227 return -1;
|
|
|
228 *uptime = difftime64(time64(&t), v->ut_tv.tv_sec);
|
|
|
229 return 0;
|
|
|
230 }
|
|
|
231
|
|
|
232
|
|
|
233 int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
|
|
234 uv_cpu_info_t* cpu_info;
|
|
|
235 int idx;
|
|
|
236 siv1v2 info;
|
|
|
237 data_area_ptr cvt = {0};
|
|
|
238 data_area_ptr csd = {0};
|
|
|
239 data_area_ptr rmctrct = {0};
|
|
|
240 data_area_ptr cvtopctp = {0};
|
|
|
241 int cpu_usage_avg;
|
|
|
242
|
|
|
243 cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
|
|
|
244
|
|
|
245 csd.assign = *((data_area_ptr_assign_type *) (cvt.deref + CSD_OFFSET));
|
|
|
246 cvtopctp.assign = *((data_area_ptr_assign_type *) (cvt.deref + CVTOPCTP_OFFSET));
|
|
|
247 rmctrct.assign = *((data_area_ptr_assign_type *) (cvtopctp.deref + RMCTRCT_OFFSET));
|
|
|
248
|
|
|
249 *count = *((int*) (csd.deref + CSD_NUMBER_ONLINE_CPUS));
|
|
|
250 cpu_usage_avg = *((unsigned short int*) (rmctrct.deref + RCTLACS_OFFSET));
|
|
|
251
|
|
|
252 *cpu_infos = uv__malloc(*count * sizeof(uv_cpu_info_t));
|
|
|
253 if (!*cpu_infos)
|
|
|
254 return UV_ENOMEM;
|
|
|
255
|
|
|
256 cpu_info = *cpu_infos;
|
|
|
257 idx = 0;
|
|
|
258 while (idx < *count) {
|
|
|
259 cpu_info->speed = *(int*)(info.siv1v2si22v1.si22v1cpucapability);
|
|
|
260 cpu_info->model = uv__malloc(ZOSCPU_MODEL_LENGTH + 1);
|
|
|
261 if (cpu_info->model == NULL) {
|
|
|
262 uv_free_cpu_info(*cpu_infos, idx);
|
|
|
263 return UV_ENOMEM;
|
|
|
264 }
|
|
|
265 __get_cpu_model(cpu_info->model, ZOSCPU_MODEL_LENGTH + 1);
|
|
|
266 cpu_info->cpu_times.user = cpu_usage_avg;
|
|
|
267 /* TODO: implement the following */
|
|
|
268 cpu_info->cpu_times.sys = 0;
|
|
|
269 cpu_info->cpu_times.idle = 0;
|
|
|
270 cpu_info->cpu_times.irq = 0;
|
|
|
271 cpu_info->cpu_times.nice = 0;
|
|
|
272 ++cpu_info;
|
|
|
273 ++idx;
|
|
|
274 }
|
|
|
275
|
|
|
276 return 0;
|
|
|
277 }
|
|
|
278
|
|
|
279
|
|
|
280 static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
|
|
|
281 int* count) {
|
|
|
282 uv_interface_address_t* address;
|
|
|
283 int sockfd;
|
|
|
284 int maxsize;
|
|
|
285 __net_ifconf6header_t ifc;
|
|
|
286 __net_ifconf6entry_t* ifr;
|
|
|
287 __net_ifconf6entry_t* p;
|
|
|
288 unsigned int i;
|
|
|
289 int count_names;
|
|
|
290 unsigned char netmask[16] = {0};
|
|
|
291
|
|
|
292 *count = 0;
|
|
|
293 /* Assume maximum buffer size allowable */
|
|
|
294 maxsize = 16384;
|
|
|
295
|
|
|
296 if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)))
|
|
|
297 return UV__ERR(errno);
|
|
|
298
|
|
|
299 ifc.__nif6h_buffer = uv__calloc(1, maxsize);
|
|
|
300
|
|
|
301 if (ifc.__nif6h_buffer == NULL) {
|
|
|
302 uv__close(sockfd);
|
|
|
303 return UV_ENOMEM;
|
|
|
304 }
|
|
|
305
|
|
|
306 ifc.__nif6h_version = 1;
|
|
|
307 ifc.__nif6h_buflen = maxsize;
|
|
|
308
|
|
|
309 if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) {
|
|
|
310 /* This will error on a system that does not support IPv6. However, we want
|
|
|
311 * to treat this as there being 0 interfaces so we can continue to get IPv4
|
|
|
312 * interfaces in uv_interface_addresses(). So return 0 instead of the error.
|
|
|
313 */
|
|
|
314 uv__free(ifc.__nif6h_buffer);
|
|
|
315 uv__close(sockfd);
|
|
|
316 errno = 0;
|
|
|
317 return 0;
|
|
|
318 }
|
|
|
319
|
|
|
320 ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
|
|
|
321 while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
|
|
|
322 p = ifr;
|
|
|
323 ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
|
|
|
324
|
|
|
325 if (!(p->__nif6e_addr.sin6_family == AF_INET6))
|
|
|
326 continue;
|
|
|
327
|
|
|
328 if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
|
|
|
329 continue;
|
|
|
330
|
|
|
331 ++(*count);
|
|
|
332 }
|
|
|
333
|
|
|
334 if ((*count) == 0) {
|
|
|
335 uv__free(ifc.__nif6h_buffer);
|
|
|
336 uv__close(sockfd);
|
|
|
337 return 0;
|
|
|
338 }
|
|
|
339
|
|
|
340 /* Alloc the return interface structs */
|
|
|
341 *addresses = uv__calloc(1, *count * sizeof(uv_interface_address_t));
|
|
|
342 if (!(*addresses)) {
|
|
|
343 uv__free(ifc.__nif6h_buffer);
|
|
|
344 uv__close(sockfd);
|
|
|
345 return UV_ENOMEM;
|
|
|
346 }
|
|
|
347 address = *addresses;
|
|
|
348
|
|
|
349 count_names = 0;
|
|
|
350 ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
|
|
|
351 while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
|
|
|
352 p = ifr;
|
|
|
353 ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
|
|
|
354
|
|
|
355 if (!(p->__nif6e_addr.sin6_family == AF_INET6))
|
|
|
356 continue;
|
|
|
357
|
|
|
358 if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
|
|
|
359 continue;
|
|
|
360
|
|
|
361 /* All conditions above must match count loop */
|
|
|
362
|
|
|
363 i = 0;
|
|
|
364 /* Ignore EBCDIC space (0x40) padding in name */
|
|
|
365 while (i < ARRAY_SIZE(p->__nif6e_name) &&
|
|
|
366 p->__nif6e_name[i] != 0x40 &&
|
|
|
367 p->__nif6e_name[i] != 0)
|
|
|
368 ++i;
|
|
|
369 address->name = uv__malloc(i + 1);
|
|
|
370 if (address->name == NULL) {
|
|
|
371 uv_free_interface_addresses(*addresses, count_names);
|
|
|
372 uv__free(ifc.__nif6h_buffer);
|
|
|
373 uv__close(sockfd);
|
|
|
374 return UV_ENOMEM;
|
|
|
375 }
|
|
|
376 memcpy(address->name, p->__nif6e_name, i);
|
|
|
377 address->name[i] = '\0';
|
|
|
378 __e2a_s(address->name);
|
|
|
379 count_names++;
|
|
|
380
|
|
|
381 address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr);
|
|
|
382
|
|
|
383 for (i = 0; i < (p->__nif6e_prefixlen / 8); i++)
|
|
|
384 netmask[i] = 0xFF;
|
|
|
385
|
|
|
386 if (p->__nif6e_prefixlen % 8)
|
|
|
387 netmask[i] = 0xFF << (8 - (p->__nif6e_prefixlen % 8));
|
|
|
388
|
|
|
389 address->netmask.netmask6.sin6_len = p->__nif6e_prefixlen;
|
|
|
390 memcpy(&(address->netmask.netmask6.sin6_addr), netmask, 16);
|
|
|
391 address->netmask.netmask6.sin6_family = AF_INET6;
|
|
|
392
|
|
|
393 address->is_internal = p->__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
|
|
|
394 address++;
|
|
|
395 }
|
|
|
396
|
|
|
397 uv__free(ifc.__nif6h_buffer);
|
|
|
398 uv__close(sockfd);
|
|
|
399 return 0;
|
|
|
400 }
|
|
|
401
|
|
|
402
|
|
|
403 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
|
|
404 uv_interface_address_t* address;
|
|
|
405 int sockfd;
|
|
|
406 int maxsize;
|
|
|
407 struct ifconf ifc;
|
|
|
408 struct ifreq flg;
|
|
|
409 struct ifreq* ifr;
|
|
|
410 struct ifreq* p;
|
|
|
411 uv_interface_address_t* addresses_v6;
|
|
|
412 int count_v6;
|
|
|
413 unsigned int i;
|
|
|
414 int rc;
|
|
|
415 int count_names;
|
|
|
416
|
|
|
417 *count = 0;
|
|
|
418 *addresses = NULL;
|
|
|
419
|
|
|
420 /* get the ipv6 addresses first */
|
|
|
421 if ((rc = uv__interface_addresses_v6(&addresses_v6, &count_v6)) != 0)
|
|
|
422 return rc;
|
|
|
423
|
|
|
424 /* now get the ipv4 addresses */
|
|
|
425
|
|
|
426 /* Assume maximum buffer size allowable */
|
|
|
427 maxsize = 16384;
|
|
|
428
|
|
|
429 sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
|
|
|
430 if (0 > sockfd) {
|
|
|
431 if (count_v6)
|
|
|
432 uv_free_interface_addresses(addresses_v6, count_v6);
|
|
|
433 return UV__ERR(errno);
|
|
|
434 }
|
|
|
435
|
|
|
436 ifc.ifc_req = uv__calloc(1, maxsize);
|
|
|
437
|
|
|
438 if (ifc.ifc_req == NULL) {
|
|
|
439 if (count_v6)
|
|
|
440 uv_free_interface_addresses(addresses_v6, count_v6);
|
|
|
441 uv__close(sockfd);
|
|
|
442 return UV_ENOMEM;
|
|
|
443 }
|
|
|
444
|
|
|
445 ifc.ifc_len = maxsize;
|
|
|
446
|
|
|
447 if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
|
|
|
448 if (count_v6)
|
|
|
449 uv_free_interface_addresses(addresses_v6, count_v6);
|
|
|
450 uv__free(ifc.ifc_req);
|
|
|
451 uv__close(sockfd);
|
|
|
452 return UV__ERR(errno);
|
|
|
453 }
|
|
|
454
|
|
|
455 #define MAX(a,b) (((a)>(b))?(a):(b))
|
|
|
456 #define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
|
|
|
457
|
|
|
458 /* Count all up and running ipv4/ipv6 addresses */
|
|
|
459 ifr = ifc.ifc_req;
|
|
|
460 while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
|
|
|
461 p = ifr;
|
|
|
462 ifr = (struct ifreq*)
|
|
|
463 ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
|
|
|
464
|
|
|
465 if (!(p->ifr_addr.sa_family == AF_INET6 ||
|
|
|
466 p->ifr_addr.sa_family == AF_INET))
|
|
|
467 continue;
|
|
|
468
|
|
|
469 memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
|
|
|
470 if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
|
|
|
471 if (count_v6)
|
|
|
472 uv_free_interface_addresses(addresses_v6, count_v6);
|
|
|
473 uv__free(ifc.ifc_req);
|
|
|
474 uv__close(sockfd);
|
|
|
475 return UV__ERR(errno);
|
|
|
476 }
|
|
|
477
|
|
|
478 if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
|
|
|
479 continue;
|
|
|
480
|
|
|
481 (*count)++;
|
|
|
482 }
|
|
|
483
|
|
|
484 if (*count == 0 && count_v6 == 0) {
|
|
|
485 uv__free(ifc.ifc_req);
|
|
|
486 uv__close(sockfd);
|
|
|
487 return 0;
|
|
|
488 }
|
|
|
489
|
|
|
490 /* Alloc the return interface structs */
|
|
|
491 *addresses = uv__calloc(1, (*count + count_v6) *
|
|
|
492 sizeof(uv_interface_address_t));
|
|
|
493
|
|
|
494 if (!(*addresses)) {
|
|
|
495 if (count_v6)
|
|
|
496 uv_free_interface_addresses(addresses_v6, count_v6);
|
|
|
497 uv__free(ifc.ifc_req);
|
|
|
498 uv__close(sockfd);
|
|
|
499 return UV_ENOMEM;
|
|
|
500 }
|
|
|
501 address = *addresses;
|
|
|
502
|
|
|
503 /* copy over the ipv6 addresses if any are found */
|
|
|
504 if (count_v6) {
|
|
|
505 memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t));
|
|
|
506 address += count_v6;
|
|
|
507 *count += count_v6;
|
|
|
508 /* free ipv6 addresses, but keep address names */
|
|
|
509 uv__free(addresses_v6);
|
|
|
510 }
|
|
|
511
|
|
|
512 count_names = *count;
|
|
|
513 ifr = ifc.ifc_req;
|
|
|
514 while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
|
|
|
515 p = ifr;
|
|
|
516 ifr = (struct ifreq*)
|
|
|
517 ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
|
|
|
518
|
|
|
519 if (!(p->ifr_addr.sa_family == AF_INET6 ||
|
|
|
520 p->ifr_addr.sa_family == AF_INET))
|
|
|
521 continue;
|
|
|
522
|
|
|
523 memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
|
|
|
524 if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
|
|
|
525 uv_free_interface_addresses(*addresses, count_names);
|
|
|
526 uv__free(ifc.ifc_req);
|
|
|
527 uv__close(sockfd);
|
|
|
528 return UV_ENOSYS;
|
|
|
529 }
|
|
|
530
|
|
|
531 if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
|
|
|
532 continue;
|
|
|
533
|
|
|
534 /* All conditions above must match count loop */
|
|
|
535
|
|
|
536 i = 0;
|
|
|
537 /* Ignore EBCDIC space (0x40) padding in name */
|
|
|
538 while (i < ARRAY_SIZE(p->ifr_name) &&
|
|
|
539 p->ifr_name[i] != 0x40 &&
|
|
|
540 p->ifr_name[i] != 0)
|
|
|
541 ++i;
|
|
|
542 address->name = uv__malloc(i + 1);
|
|
|
543 if (address->name == NULL) {
|
|
|
544 uv_free_interface_addresses(*addresses, count_names);
|
|
|
545 uv__free(ifc.ifc_req);
|
|
|
546 uv__close(sockfd);
|
|
|
547 return UV_ENOMEM;
|
|
|
548 }
|
|
|
549 memcpy(address->name, p->ifr_name, i);
|
|
|
550 address->name[i] = '\0';
|
|
|
551 __e2a_s(address->name);
|
|
|
552 count_names++;
|
|
|
553
|
|
|
554 address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
|
|
|
555
|
|
|
556 if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) {
|
|
|
557 uv_free_interface_addresses(*addresses, count_names);
|
|
|
558 uv__free(ifc.ifc_req);
|
|
|
559 uv__close(sockfd);
|
|
|
560 return UV__ERR(errno);
|
|
|
561 }
|
|
|
562
|
|
|
563 address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr);
|
|
|
564 address->netmask.netmask4.sin_family = AF_INET;
|
|
|
565 address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
|
|
|
566 address++;
|
|
|
567 }
|
|
|
568
|
|
|
569 #undef ADDR_SIZE
|
|
|
570 #undef MAX
|
|
|
571
|
|
|
572 uv__free(ifc.ifc_req);
|
|
|
573 uv__close(sockfd);
|
|
|
574 return 0;
|
|
|
575 }
|
|
|
576
|
|
|
577
|
|
|
578 void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
|
|
579 int count) {
|
|
|
580 int i;
|
|
|
581 for (i = 0; i < count; ++i)
|
|
|
582 uv__free(addresses[i].name);
|
|
|
583 uv__free(addresses);
|
|
|
584 }
|
|
|
585
|
|
|
586
|
|
|
587 void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
|
|
588 struct epoll_event* events;
|
|
|
589 struct epoll_event dummy;
|
|
|
590 uintptr_t i;
|
|
|
591 uintptr_t nfds;
|
|
|
592
|
|
|
593 assert(loop->watchers != NULL);
|
|
|
594 assert(fd >= 0);
|
|
|
595
|
|
|
596 events = (struct epoll_event*) loop->watchers[loop->nwatchers];
|
|
|
597 nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
|
|
|
598 if (events != NULL)
|
|
|
599 /* Invalidate events with same file descriptor */
|
|
|
600 for (i = 0; i < nfds; i++)
|
|
|
601 if ((int) events[i].fd == fd)
|
|
|
602 events[i].fd = -1;
|
|
|
603
|
|
|
604 /* Remove the file descriptor from the epoll. */
|
|
|
605 if (loop->ep != NULL)
|
|
|
606 epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, &dummy);
|
|
|
607 }
|
|
|
608
|
|
|
609
|
|
|
610 int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
|
|
611 struct pollfd p[1];
|
|
|
612 int rv;
|
|
|
613
|
|
|
614 p[0].fd = fd;
|
|
|
615 p[0].events = POLLIN;
|
|
|
616
|
|
|
617 do
|
|
|
618 rv = poll(p, 1, 0);
|
|
|
619 while (rv == -1 && errno == EINTR);
|
|
|
620
|
|
|
621 if (rv == -1)
|
|
|
622 abort();
|
|
|
623
|
|
|
624 if (p[0].revents & POLLNVAL)
|
|
|
625 return -1;
|
|
|
626
|
|
|
627 return 0;
|
|
|
628 }
|
|
|
629
|
|
|
630
|
|
|
631 int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
|
|
|
632 uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
|
|
|
633 return 0;
|
|
|
634 }
|
|
|
635
|
|
|
636
|
|
|
637 static int os390_regfileint(uv_fs_event_t* handle, char* path) {
|
|
|
638 uv__os390_epoll* ep;
|
|
|
639 _RFIS reg_struct;
|
|
|
640 int rc;
|
|
|
641
|
|
|
642 ep = handle->loop->ep;
|
|
|
643 assert(ep->msg_queue != -1);
|
|
|
644
|
|
|
645 reg_struct.__rfis_cmd = _RFIS_REG;
|
|
|
646 reg_struct.__rfis_qid = ep->msg_queue;
|
|
|
647 reg_struct.__rfis_type = 1;
|
|
|
648 memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle));
|
|
|
649
|
|
|
650 rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct);
|
|
|
651 if (rc != 0)
|
|
|
652 return UV__ERR(errno);
|
|
|
653
|
|
|
654 memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok,
|
|
|
655 sizeof(handle->rfis_rftok));
|
|
|
656
|
|
|
657 return 0;
|
|
|
658 }
|
|
|
659
|
|
|
660
|
|
|
661 int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
|
|
|
662 const char* filename, unsigned int flags) {
|
|
|
663 char* path;
|
|
|
664 int rc;
|
|
|
665
|
|
|
666 if (uv__is_active(handle))
|
|
|
667 return UV_EINVAL;
|
|
|
668
|
|
|
669 path = uv__strdup(filename);
|
|
|
670 if (path == NULL)
|
|
|
671 return UV_ENOMEM;
|
|
|
672
|
|
|
673 rc = os390_regfileint(handle, path);
|
|
|
674 if (rc != 0) {
|
|
|
675 uv__free(path);
|
|
|
676 return rc;
|
|
|
677 }
|
|
|
678
|
|
|
679 uv__handle_start(handle);
|
|
|
680 handle->path = path;
|
|
|
681 handle->cb = cb;
|
|
|
682
|
|
|
683 return 0;
|
|
|
684 }
|
|
|
685
|
|
|
686
|
|
|
687 int uv__fs_event_stop(uv_fs_event_t* handle) {
|
|
|
688 uv__os390_epoll* ep;
|
|
|
689 _RFIS reg_struct;
|
|
|
690 int rc;
|
|
|
691
|
|
|
692 if (!uv__is_active(handle))
|
|
|
693 return 0;
|
|
|
694
|
|
|
695 ep = handle->loop->ep;
|
|
|
696 assert(ep->msg_queue != -1);
|
|
|
697
|
|
|
698 reg_struct.__rfis_cmd = _RFIS_UNREG;
|
|
|
699 reg_struct.__rfis_qid = ep->msg_queue;
|
|
|
700 reg_struct.__rfis_type = 1;
|
|
|
701 memcpy(reg_struct.__rfis_rftok, handle->rfis_rftok,
|
|
|
702 sizeof(handle->rfis_rftok));
|
|
|
703
|
|
|
704 /*
|
|
|
705 * This call will take "/" as the path argument in case we
|
|
|
706 * don't care to supply the correct path. The system will simply
|
|
|
707 * ignore it.
|
|
|
708 */
|
|
|
709 rc = __w_pioctl("/", _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct);
|
|
|
710 if (rc != 0 && errno != EALREADY && errno != ENOENT)
|
|
|
711 abort();
|
|
|
712
|
|
|
713 if (handle->path != NULL) {
|
|
|
714 uv__free(handle->path);
|
|
|
715 handle->path = NULL;
|
|
|
716 }
|
|
|
717
|
|
|
718 if (rc != 0 && errno == EALREADY)
|
|
|
719 return -1;
|
|
|
720
|
|
|
721 uv__handle_stop(handle);
|
|
|
722
|
|
|
723 return 0;
|
|
|
724 }
|
|
|
725
|
|
|
726
|
|
|
727 int uv_fs_event_stop(uv_fs_event_t* handle) {
|
|
|
728 uv__fs_event_stop(handle);
|
|
|
729 return 0;
|
|
|
730 }
|
|
|
731
|
|
|
732
|
|
|
733 void uv__fs_event_close(uv_fs_event_t* handle) {
|
|
|
734 /*
|
|
|
735 * If we were unable to unregister file interest here, then it is most likely
|
|
|
736 * that there is a pending queued change notification. When this happens, we
|
|
|
737 * don't want to complete the close as it will free the underlying memory for
|
|
|
738 * the handle, causing a use-after-free problem when the event is processed.
|
|
|
739 * We defer the final cleanup until after the event is consumed in
|
|
|
740 * os390_message_queue_handler().
|
|
|
741 */
|
|
|
742 if (uv__fs_event_stop(handle) == 0)
|
|
|
743 uv__make_close_pending((uv_handle_t*) handle);
|
|
|
744 }
|
|
|
745
|
|
|
746
|
|
|
747 static int os390_message_queue_handler(uv__os390_epoll* ep) {
|
|
|
748 uv_fs_event_t* handle;
|
|
|
749 int msglen;
|
|
|
750 int events;
|
|
|
751 _RFIM msg;
|
|
|
752
|
|
|
753 if (ep->msg_queue == -1)
|
|
|
754 return 0;
|
|
|
755
|
|
|
756 msglen = msgrcv(ep->msg_queue, &msg, sizeof(msg), 0, IPC_NOWAIT);
|
|
|
757
|
|
|
758 if (msglen == -1 && errno == ENOMSG)
|
|
|
759 return 0;
|
|
|
760
|
|
|
761 if (msglen == -1)
|
|
|
762 abort();
|
|
|
763
|
|
|
764 events = 0;
|
|
|
765 if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE)
|
|
|
766 events = UV_CHANGE;
|
|
|
767 else if (msg.__rfim_event == _RFIM_RENAME || msg.__rfim_event == _RFIM_UNLINK)
|
|
|
768 events = UV_RENAME;
|
|
|
769 else if (msg.__rfim_event == 156)
|
|
|
770 /* TODO(gabylb): zos - this event should not happen, need to investigate.
|
|
|
771 *
|
|
|
772 * This event seems to occur when the watched file is [re]moved, or an
|
|
|
773 * editor (like vim) renames then creates the file on save (for vim, that's
|
|
|
774 * when backupcopy=no|auto).
|
|
|
775 */
|
|
|
776 events = UV_RENAME;
|
|
|
777 else
|
|
|
778 /* Some event that we are not interested in. */
|
|
|
779 return 0;
|
|
|
780
|
|
|
781 /* `__rfim_utok` is treated as text when it should be treated as binary while
|
|
|
782 * running in ASCII mode, resulting in an unwanted autoconversion.
|
|
|
783 */
|
|
|
784 __a2e_l(msg.__rfim_utok, sizeof(msg.__rfim_utok));
|
|
|
785 handle = *(uv_fs_event_t**)(msg.__rfim_utok);
|
|
|
786 assert(handle != NULL);
|
|
|
787
|
|
|
788 assert((handle->flags & UV_HANDLE_CLOSED) == 0);
|
|
|
789 if (uv__is_closing(handle)) {
|
|
|
790 uv__handle_stop(handle);
|
|
|
791 uv__make_close_pending((uv_handle_t*) handle);
|
|
|
792 return 0;
|
|
|
793 } else if (handle->path == NULL) {
|
|
|
794 /* _RFIS_UNREG returned EALREADY. */
|
|
|
795 uv__handle_stop(handle);
|
|
|
796 return 0;
|
|
|
797 }
|
|
|
798
|
|
|
799 /* The file is implicitly unregistered when the change notification is
|
|
|
800 * sent, only one notification is sent per registration. So we need to
|
|
|
801 * re-register interest in a file after each change notification we
|
|
|
802 * receive.
|
|
|
803 */
|
|
|
804 assert(handle->path != NULL);
|
|
|
805 os390_regfileint(handle, handle->path);
|
|
|
806 handle->cb(handle, uv__basename_r(handle->path), events, 0);
|
|
|
807 return 1;
|
|
|
808 }
|
|
|
809
|
|
|
810
|
|
|
811 void uv__io_poll(uv_loop_t* loop, int timeout) {
|
|
|
812 static const int max_safe_timeout = 1789569;
|
|
|
813 uv__loop_internal_fields_t* lfields;
|
|
|
814 struct epoll_event events[1024];
|
|
|
815 struct epoll_event* pe;
|
|
|
816 struct epoll_event e;
|
|
|
817 uv__os390_epoll* ep;
|
|
|
818 int have_signals;
|
|
|
819 int real_timeout;
|
|
|
820 struct uv__queue* q;
|
|
|
821 uv__io_t* w;
|
|
|
822 uint64_t base;
|
|
|
823 int count;
|
|
|
824 int nfds;
|
|
|
825 int fd;
|
|
|
826 int op;
|
|
|
827 int i;
|
|
|
828 int user_timeout;
|
|
|
829 int reset_timeout;
|
|
|
830
|
|
|
831 if (loop->nfds == 0) {
|
|
|
832 assert(uv__queue_empty(&loop->watcher_queue));
|
|
|
833 return;
|
|
|
834 }
|
|
|
835
|
|
|
836 lfields = uv__get_internal_fields(loop);
|
|
|
837
|
|
|
838 while (!uv__queue_empty(&loop->watcher_queue)) {
|
|
|
839 uv_stream_t* stream;
|
|
|
840
|
|
|
841 q = uv__queue_head(&loop->watcher_queue);
|
|
|
842 uv__queue_remove(q);
|
|
|
843 uv__queue_init(q);
|
|
|
844 w = uv__queue_data(q, uv__io_t, watcher_queue);
|
|
|
845
|
|
|
846 assert(w->pevents != 0);
|
|
|
847 assert(w->fd >= 0);
|
|
|
848
|
|
|
849 stream= container_of(w, uv_stream_t, io_watcher);
|
|
|
850
|
|
|
851 assert(w->fd < (int) loop->nwatchers);
|
|
|
852
|
|
|
853 e.events = w->pevents;
|
|
|
854 e.fd = w->fd;
|
|
|
855
|
|
|
856 if (w->events == 0)
|
|
|
857 op = EPOLL_CTL_ADD;
|
|
|
858 else
|
|
|
859 op = EPOLL_CTL_MOD;
|
|
|
860
|
|
|
861 /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
|
|
|
862 * events, skip the syscall and squelch the events after epoll_wait().
|
|
|
863 */
|
|
|
864 if (epoll_ctl(loop->ep, op, w->fd, &e)) {
|
|
|
865 if (errno != EEXIST)
|
|
|
866 abort();
|
|
|
867
|
|
|
868 assert(op == EPOLL_CTL_ADD);
|
|
|
869
|
|
|
870 /* We've reactivated a file descriptor that's been watched before. */
|
|
|
871 if (epoll_ctl(loop->ep, EPOLL_CTL_MOD, w->fd, &e))
|
|
|
872 abort();
|
|
|
873 }
|
|
|
874
|
|
|
875 w->events = w->pevents;
|
|
|
876 }
|
|
|
877
|
|
|
878 assert(timeout >= -1);
|
|
|
879 base = loop->time;
|
|
|
880 count = 48; /* Benchmarks suggest this gives the best throughput. */
|
|
|
881 real_timeout = timeout;
|
|
|
882 int nevents = 0;
|
|
|
883 have_signals = 0;
|
|
|
884
|
|
|
885 if (lfields->flags & UV_METRICS_IDLE_TIME) {
|
|
|
886 reset_timeout = 1;
|
|
|
887 user_timeout = timeout;
|
|
|
888 timeout = 0;
|
|
|
889 } else {
|
|
|
890 reset_timeout = 0;
|
|
|
891 }
|
|
|
892
|
|
|
893 nfds = 0;
|
|
|
894 for (;;) {
|
|
|
895 /* Only need to set the provider_entry_time if timeout != 0. The function
|
|
|
896 * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
|
|
|
897 */
|
|
|
898 if (timeout != 0)
|
|
|
899 uv__metrics_set_provider_entry_time(loop);
|
|
|
900
|
|
|
901 if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
|
|
|
902 timeout = max_safe_timeout;
|
|
|
903
|
|
|
904 /* Store the current timeout in a location that's globally accessible so
|
|
|
905 * other locations like uv__work_done() can determine whether the queue
|
|
|
906 * of events in the callback were waiting when poll was called.
|
|
|
907 */
|
|
|
908 lfields->current_timeout = timeout;
|
|
|
909
|
|
|
910 nfds = epoll_wait(loop->ep, events,
|
|
|
911 ARRAY_SIZE(events), timeout);
|
|
|
912
|
|
|
913 /* Update loop->time unconditionally. It's tempting to skip the update when
|
|
|
914 * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
|
|
|
915 * operating system didn't reschedule our process while in the syscall.
|
|
|
916 */
|
|
|
917 base = loop->time;
|
|
|
918 SAVE_ERRNO(uv__update_time(loop));
|
|
|
919 if (nfds == 0) {
|
|
|
920 assert(timeout != -1);
|
|
|
921
|
|
|
922 if (reset_timeout != 0) {
|
|
|
923 timeout = user_timeout;
|
|
|
924 reset_timeout = 0;
|
|
|
925 }
|
|
|
926
|
|
|
927 if (timeout == -1)
|
|
|
928 continue;
|
|
|
929
|
|
|
930 if (timeout == 0)
|
|
|
931 return;
|
|
|
932
|
|
|
933 /* We may have been inside the system call for longer than |timeout|
|
|
|
934 * milliseconds so we need to update the timestamp to avoid drift.
|
|
|
935 */
|
|
|
936 goto update_timeout;
|
|
|
937 }
|
|
|
938
|
|
|
939 if (nfds == -1) {
|
|
|
940
|
|
|
941 if (errno != EINTR)
|
|
|
942 abort();
|
|
|
943
|
|
|
944 if (reset_timeout != 0) {
|
|
|
945 timeout = user_timeout;
|
|
|
946 reset_timeout = 0;
|
|
|
947 }
|
|
|
948
|
|
|
949 if (timeout == -1)
|
|
|
950 continue;
|
|
|
951
|
|
|
952 if (timeout == 0)
|
|
|
953 return;
|
|
|
954
|
|
|
955 /* Interrupted by a signal. Update timeout and poll again. */
|
|
|
956 goto update_timeout;
|
|
|
957 }
|
|
|
958
|
|
|
959
|
|
|
960 assert(loop->watchers != NULL);
|
|
|
961 loop->watchers[loop->nwatchers] = (void*) events;
|
|
|
962 loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
|
|
|
963 for (i = 0; i < nfds; i++) {
|
|
|
964 pe = events + i;
|
|
|
965 fd = pe->fd;
|
|
|
966
|
|
|
967 /* Skip invalidated events, see uv__platform_invalidate_fd */
|
|
|
968 if (fd == -1)
|
|
|
969 continue;
|
|
|
970
|
|
|
971 ep = loop->ep;
|
|
|
972 if (pe->is_msg) {
|
|
|
973 os390_message_queue_handler(ep);
|
|
|
974 nevents++;
|
|
|
975 continue;
|
|
|
976 }
|
|
|
977
|
|
|
978 assert(fd >= 0);
|
|
|
979 assert((unsigned) fd < loop->nwatchers);
|
|
|
980
|
|
|
981 w = loop->watchers[fd];
|
|
|
982
|
|
|
983 if (w == NULL) {
|
|
|
984 /* File descriptor that we've stopped watching, disarm it.
|
|
|
985 *
|
|
|
986 * Ignore all errors because we may be racing with another thread
|
|
|
987 * when the file descriptor is closed.
|
|
|
988 */
|
|
|
989 epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, pe);
|
|
|
990 continue;
|
|
|
991 }
|
|
|
992
|
|
|
993 /* Give users only events they're interested in. Prevents spurious
|
|
|
994 * callbacks when previous callback invocation in this loop has stopped
|
|
|
995 * the current watcher. Also, filters out events that users has not
|
|
|
996 * requested us to watch.
|
|
|
997 */
|
|
|
998 pe->events &= w->pevents | POLLERR | POLLHUP;
|
|
|
999
|
|
|
1000 if (pe->events == POLLERR || pe->events == POLLHUP)
|
|
|
1001 pe->events |= w->pevents & (POLLIN | POLLOUT);
|
|
|
1002
|
|
|
1003 if (pe->events != 0) {
|
|
|
1004 /* Run signal watchers last. This also affects child process watchers
|
|
|
1005 * because those are implemented in terms of signal watchers.
|
|
|
1006 */
|
|
|
1007 if (w == &loop->signal_io_watcher) {
|
|
|
1008 have_signals = 1;
|
|
|
1009 } else {
|
|
|
1010 uv__metrics_update_idle_time(loop);
|
|
|
1011 w->cb(loop, w, pe->events);
|
|
|
1012 }
|
|
|
1013 nevents++;
|
|
|
1014 }
|
|
|
1015 }
|
|
|
1016
|
|
|
1017 uv__metrics_inc_events(loop, nevents);
|
|
|
1018 if (reset_timeout != 0) {
|
|
|
1019 timeout = user_timeout;
|
|
|
1020 reset_timeout = 0;
|
|
|
1021 uv__metrics_inc_events_waiting(loop, nevents);
|
|
|
1022 }
|
|
|
1023
|
|
|
1024 if (have_signals != 0) {
|
|
|
1025 uv__metrics_update_idle_time(loop);
|
|
|
1026 loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
|
|
|
1027 }
|
|
|
1028
|
|
|
1029 loop->watchers[loop->nwatchers] = NULL;
|
|
|
1030 loop->watchers[loop->nwatchers + 1] = NULL;
|
|
|
1031
|
|
|
1032 if (have_signals != 0)
|
|
|
1033 return; /* Event loop should cycle now so don't poll again. */
|
|
|
1034
|
|
|
1035 if (nevents != 0) {
|
|
|
1036 if (nfds == ARRAY_SIZE(events) && --count != 0) {
|
|
|
1037 /* Poll for more events but don't block this time. */
|
|
|
1038 timeout = 0;
|
|
|
1039 continue;
|
|
|
1040 }
|
|
|
1041 return;
|
|
|
1042 }
|
|
|
1043
|
|
|
1044 if (timeout == 0)
|
|
|
1045 return;
|
|
|
1046
|
|
|
1047 if (timeout == -1)
|
|
|
1048 continue;
|
|
|
1049
|
|
|
1050 update_timeout:
|
|
|
1051 assert(timeout > 0);
|
|
|
1052
|
|
|
1053 real_timeout -= (loop->time - base);
|
|
|
1054 if (real_timeout <= 0)
|
|
|
1055 return;
|
|
|
1056
|
|
|
1057 timeout = real_timeout;
|
|
|
1058 }
|
|
|
1059 }
|
|
|
1060
|
|
|
1061
|
|
|
1062 int uv__io_fork(uv_loop_t* loop) {
|
|
|
1063 /*
|
|
|
1064 Nullify the msg queue but don't close it because
|
|
|
1065 it is still being used by the parent.
|
|
|
1066 */
|
|
|
1067 loop->ep = NULL;
|
|
|
1068
|
|
|
1069 return uv__platform_loop_init(loop);
|
|
|
1070 }
|