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(×tamp);
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), ®_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), ®_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