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