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