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