Blame src/unix/os390.c

Packit b5b901
/* Copyright libuv project contributors. All rights reserved.
Packit b5b901
 *
Packit b5b901
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit b5b901
 * of this software and associated documentation files (the "Software"), to
Packit b5b901
 * deal in the Software without restriction, including without limitation the
Packit b5b901
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit b5b901
 * sell copies of the Software, and to permit persons to whom the Software is
Packit b5b901
 * furnished to do so, subject to the following conditions:
Packit b5b901
 *
Packit b5b901
 * The above copyright notice and this permission notice shall be included in
Packit b5b901
 * all copies or substantial portions of the Software.
Packit b5b901
 *
Packit b5b901
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit b5b901
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit b5b901
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit b5b901
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit b5b901
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit b5b901
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit b5b901
 * IN THE SOFTWARE.
Packit b5b901
 */
Packit b5b901
Packit b5b901
#include "internal.h"
Packit b5b901
#include <sys/ioctl.h>
Packit b5b901
#include <net/if.h>
Packit b5b901
#include <utmpx.h>
Packit b5b901
#include <unistd.h>
Packit b5b901
#include <sys/ps.h>
Packit b5b901
#include <builtins.h>
Packit b5b901
#include <termios.h>
Packit b5b901
#include <sys/msg.h>
Packit b5b901
#if defined(__clang__)
Packit b5b901
#include "csrsic.h"
Packit b5b901
#else
Packit b5b901
#include "//'SYS1.SAMPLIB(CSRSIC)'"
Packit b5b901
#endif
Packit b5b901
Packit b5b901
#define CVT_PTR           0x10
Packit b5b901
#define PSA_PTR           0x00
Packit b5b901
#define CSD_OFFSET        0x294
Packit b5b901
Packit b5b901
/*
Packit b5b901
    Long-term average CPU service used by this logical partition,
Packit b5b901
    in millions of service units per hour. If this value is above
Packit b5b901
    the partition's defined capacity, the partition will be capped.
Packit b5b901
    It is calculated using the physical CPU adjustment factor
Packit b5b901
    (RCTPCPUA) so it may not match other measures of service which
Packit b5b901
    are based on the logical CPU adjustment factor. It is available
Packit b5b901
    if the hardware supports LPAR cluster.
Packit b5b901
*/
Packit b5b901
#define RCTLACS_OFFSET    0xC4
Packit b5b901
Packit b5b901
/* 32-bit count of alive CPUs. This includes both CPs and IFAs */
Packit b5b901
#define CSD_NUMBER_ONLINE_CPUS        0xD4
Packit b5b901
Packit b5b901
/* Address of system resources manager (SRM) control table */
Packit b5b901
#define CVTOPCTP_OFFSET   0x25C
Packit b5b901
Packit b5b901
/* Address of the RCT table */
Packit b5b901
#define RMCTRCT_OFFSET    0xE4
Packit b5b901
Packit b5b901
/* Address of the rsm control and enumeration area. */
Packit b5b901
#define CVTRCEP_OFFSET    0x490
Packit b5b901
Packit b5b901
/*
Packit b5b901
    Number of frames currently available to system.
Packit b5b901
    Excluded are frames backing perm storage, frames offline, and bad frames.
Packit b5b901
*/
Packit b5b901
#define RCEPOOL_OFFSET    0x004
Packit b5b901
Packit b5b901
/* Total number of frames currently on all available frame queues. */
Packit b5b901
#define RCEAFC_OFFSET     0x088
Packit b5b901
Packit b5b901
/* CPC model length from the CSRSI Service. */
Packit b5b901
#define CPCMODEL_LENGTH   16
Packit b5b901
Packit b5b901
/* Pointer to the home (current) ASCB. */
Packit b5b901
#define PSAAOLD           0x224
Packit b5b901
Packit b5b901
/* Pointer to rsm address space block extension. */
Packit b5b901
#define ASCBRSME          0x16C
Packit b5b901
Packit b5b901
/*
Packit b5b901
    NUMBER OF FRAMES CURRENTLY IN USE BY THIS ADDRESS SPACE.
Packit b5b901
    It does not include 2G frames.
Packit b5b901
*/
Packit b5b901
#define RAXFMCT           0x2C
Packit b5b901
Packit b5b901
/* Thread Entry constants */
Packit b5b901
#define PGTH_CURRENT  1
Packit b5b901
#define PGTH_LEN      26
Packit b5b901
#define PGTHAPATH     0x20
Packit b5b901
#pragma linkage(BPX4GTH, OS)
Packit b5b901
#pragma linkage(BPX1GTH, OS)
Packit b5b901
Packit b5b901
/* TOD Clock resolution in nanoseconds */
Packit b5b901
#define TOD_RES 4.096
Packit b5b901
Packit b5b901
typedef unsigned data_area_ptr_assign_type;
Packit b5b901
Packit b5b901
typedef union {
Packit b5b901
  struct {
Packit b5b901
#if defined(_LP64)
Packit b5b901
    data_area_ptr_assign_type lower;
Packit b5b901
#endif
Packit b5b901
    data_area_ptr_assign_type assign;
Packit b5b901
  };
Packit b5b901
  char* deref;
Packit b5b901
} data_area_ptr;
Packit b5b901
Packit b5b901
Packit b5b901
void uv_loadavg(double avg[3]) {
Packit b5b901
  /* TODO: implement the following */
Packit b5b901
  avg[0] = 0;
Packit b5b901
  avg[1] = 0;
Packit b5b901
  avg[2] = 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv__platform_loop_init(uv_loop_t* loop) {
Packit b5b901
  uv__os390_epoll* ep;
Packit b5b901
Packit b5b901
  ep = epoll_create1(0);
Packit b5b901
  loop->ep = ep;
Packit b5b901
  if (ep == NULL)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv__platform_loop_delete(uv_loop_t* loop) {
Packit b5b901
  if (loop->ep != NULL) {
Packit b5b901
    epoll_queue_close(loop->ep);
Packit b5b901
    loop->ep = NULL;
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
uint64_t uv__hrtime(uv_clocktype_t type) {
Packit b5b901
  unsigned long long timestamp;
Packit b5b901
  __stckf(&timestamp);
Packit b5b901
  /* Convert to nanoseconds */
Packit b5b901
  return timestamp / TOD_RES;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
/*
Packit b5b901
    Get the exe path using the thread entry information
Packit b5b901
    in the address space.
Packit b5b901
*/
Packit b5b901
static int getexe(const int pid, char* buf, size_t len) {
Packit b5b901
  struct {
Packit b5b901
    int pid;
Packit b5b901
    int thid[2];
Packit b5b901
    char accesspid;
Packit b5b901
    char accessthid;
Packit b5b901
    char asid[2];
Packit b5b901
    char loginname[8];
Packit b5b901
    char flag;
Packit b5b901
    char len;
Packit b5b901
  } Input_data;
Packit b5b901
Packit b5b901
  union {
Packit b5b901
    struct {
Packit b5b901
      char gthb[4];
Packit b5b901
      int pid;
Packit b5b901
      int thid[2];
Packit b5b901
      char accesspid;
Packit b5b901
      char accessthid[3];
Packit b5b901
      int lenused;
Packit b5b901
      int offsetProcess;
Packit b5b901
      int offsetConTTY;
Packit b5b901
      int offsetPath;
Packit b5b901
      int offsetCommand;
Packit b5b901
      int offsetFileData;
Packit b5b901
      int offsetThread;
Packit b5b901
    } Output_data;
Packit b5b901
    char buf[2048];
Packit b5b901
  } Output_buf;
Packit b5b901
Packit b5b901
  struct Output_path_type {
Packit b5b901
    char gthe[4];
Packit b5b901
    short int len;
Packit b5b901
    char path[1024];
Packit b5b901
  };
Packit b5b901
Packit b5b901
  int Input_length;
Packit b5b901
  int Output_length;
Packit b5b901
  void* Input_address;
Packit b5b901
  void* Output_address;
Packit b5b901
  struct Output_path_type* Output_path;
Packit b5b901
  int rv;
Packit b5b901
  int rc;
Packit b5b901
  int rsn;
Packit b5b901
Packit b5b901
  Input_length = PGTH_LEN;
Packit b5b901
  Output_length = sizeof(Output_buf);
Packit b5b901
  Output_address = &Output_buf;
Packit b5b901
  Input_address = &Input_data;
Packit b5b901
  memset(&Input_data, 0, sizeof Input_data);
Packit b5b901
  Input_data.flag |= PGTHAPATH;
Packit b5b901
  Input_data.pid = pid;
Packit b5b901
  Input_data.accesspid = PGTH_CURRENT;
Packit b5b901
Packit b5b901
#ifdef _LP64
Packit b5b901
  BPX4GTH(&Input_length,
Packit b5b901
          &Input_address,
Packit b5b901
          &Output_length,
Packit b5b901
          &Output_address,
Packit b5b901
          &rv,
Packit b5b901
          &rc,
Packit b5b901
          &rsn;;
Packit b5b901
#else
Packit b5b901
  BPX1GTH(&Input_length,
Packit b5b901
          &Input_address,
Packit b5b901
          &Output_length,
Packit b5b901
          &Output_address,
Packit b5b901
          &rv,
Packit b5b901
          &rc,
Packit b5b901
          &rsn;;
Packit b5b901
#endif
Packit b5b901
Packit b5b901
  if (rv == -1) {
Packit b5b901
    errno = rc;
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Check highest byte to ensure data availability */
Packit b5b901
  assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A');
Packit b5b901
Packit b5b901
  /* Get the offset from the lowest 3 bytes */
Packit Service e08953
  Output_path = (struct Output_path_type*) ((char*) (&Output_buf) +
Packit Service e08953
      (Output_buf.Output_data.offsetPath & 0x00FFFFFF));
Packit b5b901
Packit b5b901
  if (Output_path->len >= len) {
Packit b5b901
    errno = ENOBUFS;
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
Packit Service e08953
  uv__strscpy(buf, Output_path->path, len);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
/*
Packit b5b901
 * We could use a static buffer for the path manipulations that we need outside
Packit b5b901
 * of the function, but this function could be called by multiple consumers and
Packit b5b901
 * we don't want to potentially create a race condition in the use of snprintf.
Packit b5b901
 * There is no direct way of getting the exe path in zOS - either through /procfs
Packit b5b901
 * or through some libc APIs. The below approach is to parse the argv[0]'s pattern
Packit b5b901
 * and use it in conjunction with PATH environment variable to craft one.
Packit b5b901
 */
Packit b5b901
int uv_exepath(char* buffer, size_t* size) {
Packit b5b901
  int res;
Packit b5b901
  char args[PATH_MAX];
Packit b5b901
  char abspath[PATH_MAX];
Packit b5b901
  size_t abspath_size;
Packit b5b901
  int pid;
Packit b5b901
Packit b5b901
  if (buffer == NULL || size == NULL || *size == 0)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  pid = getpid();
Packit b5b901
  res = getexe(pid, args, sizeof(args));
Packit b5b901
  if (res < 0)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  /*
Packit b5b901
   * Possibilities for args:
Packit b5b901
   * i) an absolute path such as: /home/user/myprojects/nodejs/node
Packit b5b901
   * ii) a relative path such as: ./node or ../myprojects/nodejs/node
Packit b5b901
   * iii) a bare filename such as "node", after exporting PATH variable
Packit b5b901
   *     to its location.
Packit b5b901
   */
Packit b5b901
Packit b5b901
  /* Case i) and ii) absolute or relative paths */
Packit b5b901
  if (strchr(args, '/') != NULL) {
Packit b5b901
    if (realpath(args, abspath) != abspath)
Packit b5b901
      return UV__ERR(errno);
Packit b5b901
Packit b5b901
    abspath_size = strlen(abspath);
Packit b5b901
Packit b5b901
    *size -= 1;
Packit b5b901
    if (*size > abspath_size)
Packit b5b901
      *size = abspath_size;
Packit b5b901
Packit b5b901
    memcpy(buffer, abspath, *size);
Packit b5b901
    buffer[*size] = '\0';
Packit b5b901
Packit b5b901
    return 0;
Packit b5b901
  } else {
Packit b5b901
    /* Case iii). Search PATH environment variable */
Packit b5b901
    char trypath[PATH_MAX];
Packit b5b901
    char* clonedpath = NULL;
Packit b5b901
    char* token = NULL;
Packit b5b901
    char* path = getenv("PATH");
Packit b5b901
Packit b5b901
    if (path == NULL)
Packit b5b901
      return UV_EINVAL;
Packit b5b901
Packit b5b901
    clonedpath = uv__strdup(path);
Packit b5b901
    if (clonedpath == NULL)
Packit b5b901
      return UV_ENOMEM;
Packit b5b901
Packit b5b901
    token = strtok(clonedpath, ":");
Packit b5b901
    while (token != NULL) {
Packit b5b901
      snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args);
Packit b5b901
      if (realpath(trypath, abspath) == abspath) {
Packit b5b901
        /* Check the match is executable */
Packit b5b901
        if (access(abspath, X_OK) == 0) {
Packit b5b901
          abspath_size = strlen(abspath);
Packit b5b901
Packit b5b901
          *size -= 1;
Packit b5b901
          if (*size > abspath_size)
Packit b5b901
            *size = abspath_size;
Packit b5b901
Packit b5b901
          memcpy(buffer, abspath, *size);
Packit b5b901
          buffer[*size] = '\0';
Packit b5b901
Packit b5b901
          uv__free(clonedpath);
Packit b5b901
          return 0;
Packit b5b901
        }
Packit b5b901
      }
Packit b5b901
      token = strtok(NULL, ":");
Packit b5b901
    }
Packit b5b901
    uv__free(clonedpath);
Packit b5b901
Packit b5b901
    /* Out of tokens (path entries), and no match found */
Packit b5b901
    return UV_EINVAL;
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
uint64_t uv_get_free_memory(void) {
Packit b5b901
  uint64_t freeram;
Packit b5b901
Packit b5b901
  data_area_ptr cvt = {0};
Packit b5b901
  data_area_ptr rcep = {0};
Packit b5b901
  cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
Packit b5b901
  rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
Packit b5b901
  freeram = *((uint64_t*)(rcep.deref + RCEAFC_OFFSET)) * 4;
Packit b5b901
  return freeram;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
uint64_t uv_get_total_memory(void) {
Packit b5b901
  uint64_t totalram;
Packit b5b901
Packit b5b901
  data_area_ptr cvt = {0};
Packit b5b901
  data_area_ptr rcep = {0};
Packit b5b901
  cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
Packit b5b901
  rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
Packit b5b901
  totalram = *((uint64_t*)(rcep.deref + RCEPOOL_OFFSET)) * 4;
Packit b5b901
  return totalram;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit Service e08953
uint64_t uv_get_constrained_memory(void) {
Packit Service e08953
  return 0;  /* Memory constraints are unknown. */
Packit Service e08953
}
Packit Service e08953
Packit Service e08953
Packit b5b901
int uv_resident_set_memory(size_t* rss) {
Packit b5b901
  char* ascb;
Packit b5b901
  char* rax;
Packit b5b901
  size_t nframes;
Packit b5b901
Packit Service e08953
  ascb  = *(char* __ptr32 *)(PSA_PTR + PSAAOLD);
Packit b5b901
  rax = *(char* __ptr32 *)(ascb + ASCBRSME);
Packit b5b901
  nframes = *(unsigned int*)(rax + RAXFMCT);
Packit b5b901
Packit b5b901
  *rss = nframes * sysconf(_SC_PAGESIZE);
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_uptime(double* uptime) {
Packit b5b901
  struct utmpx u ;
Packit b5b901
  struct utmpx *v;
Packit b5b901
  time64_t t;
Packit b5b901
Packit b5b901
  u.ut_type = BOOT_TIME;
Packit b5b901
  v = getutxid(&u);
Packit b5b901
  if (v == NULL)
Packit b5b901
    return -1;
Packit b5b901
  *uptime = difftime64(time64(&t), v->ut_tv.tv_sec);
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
Packit b5b901
  uv_cpu_info_t* cpu_info;
Packit b5b901
  int idx;
Packit b5b901
  siv1v2 info;
Packit b5b901
  data_area_ptr cvt = {0};
Packit b5b901
  data_area_ptr csd = {0};
Packit b5b901
  data_area_ptr rmctrct = {0};
Packit b5b901
  data_area_ptr cvtopctp = {0};
Packit b5b901
  int cpu_usage_avg;
Packit b5b901
Packit b5b901
  cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
Packit b5b901
Packit b5b901
  csd.assign = *((data_area_ptr_assign_type *) (cvt.deref + CSD_OFFSET));
Packit b5b901
  cvtopctp.assign = *((data_area_ptr_assign_type *) (cvt.deref + CVTOPCTP_OFFSET));
Packit b5b901
  rmctrct.assign = *((data_area_ptr_assign_type *) (cvtopctp.deref + RMCTRCT_OFFSET));
Packit b5b901
Packit b5b901
  *count = *((int*) (csd.deref + CSD_NUMBER_ONLINE_CPUS));
Packit b5b901
  cpu_usage_avg = *((unsigned short int*) (rmctrct.deref + RCTLACS_OFFSET));
Packit b5b901
Packit b5b901
  *cpu_infos = uv__malloc(*count * sizeof(uv_cpu_info_t));
Packit b5b901
  if (!*cpu_infos)
Packit b5b901
    return UV_ENOMEM;
Packit b5b901
Packit b5b901
  cpu_info = *cpu_infos;
Packit b5b901
  idx = 0;
Packit b5b901
  while (idx < *count) {
Packit b5b901
    cpu_info->speed = *(int*)(info.siv1v2si22v1.si22v1cpucapability);
Packit b5b901
    cpu_info->model = uv__malloc(CPCMODEL_LENGTH + 1);
Packit b5b901
    memset(cpu_info->model, '\0', CPCMODEL_LENGTH + 1);
Packit b5b901
    memcpy(cpu_info->model, info.siv1v2si11v1.si11v1cpcmodel, CPCMODEL_LENGTH);
Packit b5b901
    cpu_info->cpu_times.user = cpu_usage_avg;
Packit b5b901
    /* TODO: implement the following */
Packit b5b901
    cpu_info->cpu_times.sys = 0;
Packit b5b901
    cpu_info->cpu_times.idle = 0;
Packit b5b901
    cpu_info->cpu_times.irq = 0;
Packit b5b901
    cpu_info->cpu_times.nice = 0;
Packit b5b901
    ++cpu_info;
Packit b5b901
    ++idx;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
Packit b5b901
                                      int* count) {
Packit b5b901
  uv_interface_address_t* address;
Packit b5b901
  int sockfd;
Packit b5b901
  int maxsize;
Packit b5b901
  __net_ifconf6header_t ifc;
Packit b5b901
  __net_ifconf6entry_t* ifr;
Packit b5b901
  __net_ifconf6entry_t* p;
Packit b5b901
  __net_ifconf6entry_t flg;
Packit b5b901
Packit b5b901
  *count = 0;
Packit b5b901
  /* Assume maximum buffer size allowable */
Packit b5b901
  maxsize = 16384;
Packit b5b901
Packit b5b901
  if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)))
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  ifc.__nif6h_version = 1;
Packit b5b901
  ifc.__nif6h_buflen = maxsize;
Packit b5b901
  ifc.__nif6h_buffer = uv__calloc(1, maxsize);;
Packit b5b901
Packit b5b901
  if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) {
Packit b5b901
    uv__close(sockfd);
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
  }
Packit b5b901
Packit b5b901
Packit b5b901
  *count = 0;
Packit b5b901
  ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
Packit b5b901
  while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
Packit b5b901
    p = ifr;
Packit b5b901
    ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
Packit b5b901
Packit b5b901
    if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
Packit b5b901
          p->__nif6e_addr.sin6_family == AF_INET))
Packit b5b901
      continue;
Packit b5b901
Packit b5b901
    if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
Packit b5b901
      continue;
Packit b5b901
Packit b5b901
    ++(*count);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* Alloc the return interface structs */
Packit b5b901
  *addresses = uv__malloc(*count * sizeof(uv_interface_address_t));
Packit b5b901
  if (!(*addresses)) {
Packit b5b901
    uv__close(sockfd);
Packit b5b901
    return UV_ENOMEM;
Packit b5b901
  }
Packit b5b901
  address = *addresses;
Packit b5b901
Packit b5b901
  ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
Packit b5b901
  while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
Packit b5b901
    p = ifr;
Packit b5b901
    ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
Packit b5b901
Packit b5b901
    if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
Packit b5b901
          p->__nif6e_addr.sin6_family == AF_INET))
Packit b5b901
      continue;
Packit b5b901
Packit b5b901
    if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
Packit b5b901
      continue;
Packit b5b901
Packit b5b901
    /* All conditions above must match count loop */
Packit b5b901
Packit b5b901
    address->name = uv__strdup(p->__nif6e_name);
Packit b5b901
Packit b5b901
    if (p->__nif6e_addr.sin6_family == AF_INET6)
Packit b5b901
      address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr);
Packit b5b901
    else
Packit b5b901
      address->address.address4 = *((struct sockaddr_in*) &p->__nif6e_addr);
Packit b5b901
Packit b5b901
    /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
Packit b5b901
Packit b5b901
    address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
Packit Service e08953
    memset(address->phys_addr, 0, sizeof(address->phys_addr));
Packit b5b901
    address++;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  uv__close(sockfd);
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
Packit b5b901
  uv_interface_address_t* address;
Packit b5b901
  int sockfd;
Packit b5b901
  int maxsize;
Packit b5b901
  struct ifconf ifc;
Packit b5b901
  struct ifreq flg;
Packit b5b901
  struct ifreq* ifr;
Packit b5b901
  struct ifreq* p;
Packit b5b901
  int count_v6;
Packit b5b901
Packit Service e08953
  *count = 0;
Packit Service e08953
  *addresses = NULL;
Packit Service e08953
Packit b5b901
  /* get the ipv6 addresses first */
Packit b5b901
  uv_interface_address_t* addresses_v6;
Packit b5b901
  uv__interface_addresses_v6(&addresses_v6, &count_v6);
Packit b5b901
Packit b5b901
  /* now get the ipv4 addresses */
Packit b5b901
Packit b5b901
  /* Assume maximum buffer size allowable */
Packit b5b901
  maxsize = 16384;
Packit b5b901
Packit b5b901
  sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
Packit b5b901
  if (0 > sockfd)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  ifc.ifc_req = uv__calloc(1, maxsize);
Packit b5b901
  ifc.ifc_len = maxsize;
Packit b5b901
  if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
Packit b5b901
    uv__close(sockfd);
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
  }
Packit b5b901
Packit b5b901
#define MAX(a,b) (((a)>(b))?(a):(b))
Packit b5b901
#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
Packit b5b901
Packit b5b901
  /* Count all up and running ipv4/ipv6 addresses */
Packit b5b901
  ifr = ifc.ifc_req;
Packit b5b901
  while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
Packit b5b901
    p = ifr;
Packit b5b901
    ifr = (struct ifreq*)
Packit b5b901
      ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
Packit b5b901
Packit b5b901
    if (!(p->ifr_addr.sa_family == AF_INET6 ||
Packit b5b901
          p->ifr_addr.sa_family == AF_INET))
Packit b5b901
      continue;
Packit b5b901
Packit b5b901
    memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
Packit b5b901
    if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
Packit b5b901
      uv__close(sockfd);
Packit b5b901
      return UV__ERR(errno);
Packit b5b901
    }
Packit b5b901
Packit b5b901
    if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
Packit b5b901
      continue;
Packit b5b901
Packit b5b901
    (*count)++;
Packit b5b901
  }
Packit b5b901
Packit Service e08953
  if (*count == 0) {
Packit Service e08953
    uv__close(sockfd);
Packit Service e08953
    return 0;
Packit Service e08953
  }
Packit Service e08953
Packit b5b901
  /* Alloc the return interface structs */
Packit b5b901
  *addresses = uv__malloc((*count + count_v6) *
Packit b5b901
                          sizeof(uv_interface_address_t));
Packit b5b901
Packit b5b901
  if (!(*addresses)) {
Packit b5b901
    uv__close(sockfd);
Packit b5b901
    return UV_ENOMEM;
Packit b5b901
  }
Packit b5b901
  address = *addresses;
Packit b5b901
Packit b5b901
  /* copy over the ipv6 addresses */
Packit b5b901
  memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t));
Packit b5b901
  address += count_v6;
Packit b5b901
  *count += count_v6;
Packit b5b901
  uv__free(addresses_v6);
Packit b5b901
Packit b5b901
  ifr = ifc.ifc_req;
Packit b5b901
  while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
Packit b5b901
    p = ifr;
Packit b5b901
    ifr = (struct ifreq*)
Packit b5b901
      ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
Packit b5b901
Packit b5b901
    if (!(p->ifr_addr.sa_family == AF_INET6 ||
Packit b5b901
          p->ifr_addr.sa_family == AF_INET))
Packit b5b901
      continue;
Packit b5b901
Packit b5b901
    memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
Packit b5b901
    if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
Packit b5b901
      uv__close(sockfd);
Packit b5b901
      return UV_ENOSYS;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
Packit b5b901
      continue;
Packit b5b901
Packit b5b901
    /* All conditions above must match count loop */
Packit b5b901
Packit b5b901
    address->name = uv__strdup(p->ifr_name);
Packit b5b901
Packit b5b901
    if (p->ifr_addr.sa_family == AF_INET6) {
Packit b5b901
      address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
Packit b5b901
    } else {
Packit b5b901
      address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
Packit b5b901
    }
Packit b5b901
Packit b5b901
    address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
Packit Service e08953
    memset(address->phys_addr, 0, sizeof(address->phys_addr));
Packit b5b901
    address++;
Packit b5b901
  }
Packit b5b901
Packit b5b901
#undef ADDR_SIZE
Packit b5b901
#undef MAX
Packit b5b901
Packit b5b901
  uv__close(sockfd);
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv_free_interface_addresses(uv_interface_address_t* addresses,
Packit b5b901
                                 int count) {
Packit b5b901
  int i;
Packit b5b901
  for (i = 0; i < count; ++i)
Packit b5b901
    uv__free(addresses[i].name);
Packit b5b901
  uv__free(addresses);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
Packit b5b901
  struct epoll_event* events;
Packit b5b901
  struct epoll_event dummy;
Packit b5b901
  uintptr_t i;
Packit b5b901
  uintptr_t nfds;
Packit b5b901
Packit b5b901
  assert(loop->watchers != NULL);
Packit Service e08953
  assert(fd >= 0);
Packit b5b901
Packit b5b901
  events = (struct epoll_event*) loop->watchers[loop->nwatchers];
Packit b5b901
  nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
Packit b5b901
  if (events != NULL)
Packit b5b901
    /* Invalidate events with same file descriptor */
Packit b5b901
    for (i = 0; i < nfds; i++)
Packit b5b901
      if ((int) events[i].fd == fd)
Packit b5b901
        events[i].fd = -1;
Packit b5b901
Packit b5b901
  /* Remove the file descriptor from the epoll. */
Packit b5b901
  if (loop->ep != NULL)
Packit b5b901
    epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, &dummy);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv__io_check_fd(uv_loop_t* loop, int fd) {
Packit b5b901
  struct pollfd p[1];
Packit b5b901
  int rv;
Packit b5b901
Packit b5b901
  p[0].fd = fd;
Packit b5b901
  p[0].events = POLLIN;
Packit b5b901
Packit b5b901
  do
Packit b5b901
    rv = poll(p, 1, 0);
Packit b5b901
  while (rv == -1 && errno == EINTR);
Packit b5b901
Packit b5b901
  if (rv == -1)
Packit b5b901
    abort();
Packit b5b901
Packit b5b901
  if (p[0].revents & POLLNVAL)
Packit b5b901
    return -1;
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv__fs_event_close(uv_fs_event_t* handle) {
Packit b5b901
  uv_fs_event_stop(handle);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
Packit b5b901
  uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
Packit b5b901
                      const char* filename, unsigned int flags) {
Packit b5b901
  uv__os390_epoll* ep;
Packit b5b901
  _RFIS reg_struct;
Packit b5b901
  char* path;
Packit b5b901
  int rc;
Packit b5b901
Packit b5b901
  if (uv__is_active(handle))
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  ep = handle->loop->ep;
Packit b5b901
  assert(ep->msg_queue != -1);
Packit b5b901
Packit b5b901
  reg_struct.__rfis_cmd  = _RFIS_REG;
Packit b5b901
  reg_struct.__rfis_qid  = ep->msg_queue;
Packit b5b901
  reg_struct.__rfis_type = 1;
Packit b5b901
  memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle));
Packit b5b901
Packit b5b901
  path = uv__strdup(filename);
Packit b5b901
  if (path == NULL)
Packit b5b901
    return UV_ENOMEM;
Packit b5b901
Packit b5b901
  rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), &reg_struct);
Packit b5b901
  if (rc != 0)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  uv__handle_start(handle);
Packit b5b901
  handle->path = path;
Packit b5b901
  handle->cb = cb;
Packit b5b901
  memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok,
Packit b5b901
         sizeof(handle->rfis_rftok));
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_fs_event_stop(uv_fs_event_t* handle) {
Packit b5b901
  uv__os390_epoll* ep;
Packit b5b901
  _RFIS reg_struct;
Packit b5b901
  int rc;
Packit b5b901
Packit b5b901
  if (!uv__is_active(handle))
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  ep = handle->loop->ep;
Packit b5b901
  assert(ep->msg_queue != -1);
Packit b5b901
Packit b5b901
  reg_struct.__rfis_cmd  = _RFIS_UNREG;
Packit b5b901
  reg_struct.__rfis_qid  = ep->msg_queue;
Packit b5b901
  reg_struct.__rfis_type = 1;
Packit b5b901
  memcpy(reg_struct.__rfis_rftok, handle->rfis_rftok,
Packit b5b901
         sizeof(handle->rfis_rftok));
Packit b5b901
Packit Service e08953
  /*
Packit b5b901
   * This call will take "/" as the path argument in case we
Packit b5b901
   * don't care to supply the correct path. The system will simply
Packit b5b901
   * ignore it.
Packit b5b901
   */
Packit b5b901
  rc = __w_pioctl("/", _IOCC_REGFILEINT, sizeof(reg_struct), &reg_struct);
Packit b5b901
  if (rc != 0 && errno != EALREADY && errno != ENOENT)
Packit b5b901
    abort();
Packit b5b901
Packit b5b901
  uv__handle_stop(handle);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int os390_message_queue_handler(uv__os390_epoll* ep) {
Packit b5b901
  uv_fs_event_t* handle;
Packit b5b901
  int msglen;
Packit b5b901
  int events;
Packit b5b901
  _RFIM msg;
Packit b5b901
Packit b5b901
  if (ep->msg_queue == -1)
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  msglen = msgrcv(ep->msg_queue, &msg, sizeof(msg), 0, IPC_NOWAIT);
Packit b5b901
Packit b5b901
  if (msglen == -1 && errno == ENOMSG)
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  if (msglen == -1)
Packit b5b901
    abort();
Packit b5b901
Packit b5b901
  events = 0;
Packit b5b901
  if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE)
Packit b5b901
    events = UV_CHANGE;
Packit b5b901
  else if (msg.__rfim_event == _RFIM_RENAME)
Packit b5b901
    events = UV_RENAME;
Packit b5b901
  else
Packit b5b901
    /* Some event that we are not interested in. */
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  handle = *(uv_fs_event_t**)(msg.__rfim_utok);
Packit b5b901
  handle->cb(handle, uv__basename_r(handle->path), events, 0);
Packit b5b901
  return 1;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv__io_poll(uv_loop_t* loop, int timeout) {
Packit b5b901
  static const int max_safe_timeout = 1789569;
Packit b5b901
  struct epoll_event events[1024];
Packit b5b901
  struct epoll_event* pe;
Packit b5b901
  struct epoll_event e;
Packit b5b901
  uv__os390_epoll* ep;
Packit b5b901
  int real_timeout;
Packit b5b901
  QUEUE* q;
Packit b5b901
  uv__io_t* w;
Packit b5b901
  uint64_t base;
Packit b5b901
  int count;
Packit b5b901
  int nfds;
Packit b5b901
  int fd;
Packit b5b901
  int op;
Packit b5b901
  int i;
Packit b5b901
Packit b5b901
  if (loop->nfds == 0) {
Packit b5b901
    assert(QUEUE_EMPTY(&loop->watcher_queue));
Packit b5b901
    return;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  while (!QUEUE_EMPTY(&loop->watcher_queue)) {
Packit b5b901
    uv_stream_t* stream;
Packit b5b901
Packit b5b901
    q = QUEUE_HEAD(&loop->watcher_queue);
Packit b5b901
    QUEUE_REMOVE(q);
Packit b5b901
    QUEUE_INIT(q);
Packit b5b901
    w = QUEUE_DATA(q, uv__io_t, watcher_queue);
Packit b5b901
Packit b5b901
    assert(w->pevents != 0);
Packit b5b901
    assert(w->fd >= 0);
Packit b5b901
Packit b5b901
    stream= container_of(w, uv_stream_t, io_watcher);
Packit b5b901
Packit b5b901
    assert(w->fd < (int) loop->nwatchers);
Packit b5b901
Packit b5b901
    e.events = w->pevents;
Packit b5b901
    e.fd = w->fd;
Packit b5b901
Packit b5b901
    if (w->events == 0)
Packit b5b901
      op = EPOLL_CTL_ADD;
Packit b5b901
    else
Packit b5b901
      op = EPOLL_CTL_MOD;
Packit b5b901
Packit b5b901
    /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
Packit b5b901
     * events, skip the syscall and squelch the events after epoll_wait().
Packit b5b901
     */
Packit b5b901
    if (epoll_ctl(loop->ep, op, w->fd, &e)) {
Packit b5b901
      if (errno != EEXIST)
Packit b5b901
        abort();
Packit b5b901
Packit b5b901
      assert(op == EPOLL_CTL_ADD);
Packit b5b901
Packit b5b901
      /* We've reactivated a file descriptor that's been watched before. */
Packit b5b901
      if (epoll_ctl(loop->ep, EPOLL_CTL_MOD, w->fd, &e))
Packit b5b901
        abort();
Packit b5b901
    }
Packit b5b901
Packit b5b901
    w->events = w->pevents;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  assert(timeout >= -1);
Packit b5b901
  base = loop->time;
Packit b5b901
  count = 48; /* Benchmarks suggest this gives the best throughput. */
Packit b5b901
  real_timeout = timeout;
Packit b5b901
  int nevents = 0;
Packit b5b901
Packit b5b901
  nfds = 0;
Packit b5b901
  for (;;) {
Packit b5b901
    if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
Packit b5b901
      timeout = max_safe_timeout;
Packit b5b901
Packit b5b901
    nfds = epoll_wait(loop->ep, events,
Packit b5b901
                      ARRAY_SIZE(events), timeout);
Packit b5b901
Packit b5b901
    /* Update loop->time unconditionally. It's tempting to skip the update when
Packit b5b901
     * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
Packit b5b901
     * operating system didn't reschedule our process while in the syscall.
Packit b5b901
     */
Packit b5b901
    base = loop->time;
Packit b5b901
    SAVE_ERRNO(uv__update_time(loop));
Packit b5b901
    if (nfds == 0) {
Packit b5b901
      assert(timeout != -1);
Packit b5b901
Packit b5b901
      if (timeout > 0) {
Packit b5b901
        timeout = real_timeout - timeout;
Packit b5b901
        continue;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      return;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    if (nfds == -1) {
Packit b5b901
Packit b5b901
      if (errno != EINTR)
Packit b5b901
        abort();
Packit b5b901
Packit b5b901
      if (timeout == -1)
Packit b5b901
        continue;
Packit b5b901
Packit b5b901
      if (timeout == 0)
Packit b5b901
        return;
Packit b5b901
Packit b5b901
      /* Interrupted by a signal. Update timeout and poll again. */
Packit b5b901
      goto update_timeout;
Packit b5b901
    }
Packit b5b901
Packit b5b901
Packit b5b901
    assert(loop->watchers != NULL);
Packit b5b901
    loop->watchers[loop->nwatchers] = (void*) events;
Packit b5b901
    loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
Packit b5b901
    for (i = 0; i < nfds; i++) {
Packit b5b901
      pe = events + i;
Packit b5b901
      fd = pe->fd;
Packit b5b901
Packit b5b901
      /* Skip invalidated events, see uv__platform_invalidate_fd */
Packit b5b901
      if (fd == -1)
Packit b5b901
        continue;
Packit b5b901
Packit b5b901
      ep = loop->ep;
Packit Service e08953
      if (pe->is_msg) {
Packit b5b901
        os390_message_queue_handler(ep);
Packit b5b901
        continue;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      assert(fd >= 0);
Packit b5b901
      assert((unsigned) fd < loop->nwatchers);
Packit b5b901
Packit b5b901
      w = loop->watchers[fd];
Packit b5b901
Packit b5b901
      if (w == NULL) {
Packit b5b901
        /* File descriptor that we've stopped watching, disarm it.
Packit b5b901
         *
Packit b5b901
         * Ignore all errors because we may be racing with another thread
Packit b5b901
         * when the file descriptor is closed.
Packit b5b901
         */
Packit b5b901
        epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, pe);
Packit b5b901
        continue;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      /* Give users only events they're interested in. Prevents spurious
Packit b5b901
       * callbacks when previous callback invocation in this loop has stopped
Packit b5b901
       * the current watcher. Also, filters out events that users has not
Packit b5b901
       * requested us to watch.
Packit b5b901
       */
Packit b5b901
      pe->events &= w->pevents | POLLERR | POLLHUP;
Packit b5b901
Packit b5b901
      if (pe->events == POLLERR || pe->events == POLLHUP)
Packit b5b901
        pe->events |= w->pevents & (POLLIN | POLLOUT);
Packit b5b901
Packit b5b901
      if (pe->events != 0) {
Packit b5b901
        w->cb(loop, w, pe->events);
Packit b5b901
        nevents++;
Packit b5b901
      }
Packit b5b901
    }
Packit b5b901
    loop->watchers[loop->nwatchers] = NULL;
Packit b5b901
    loop->watchers[loop->nwatchers + 1] = NULL;
Packit b5b901
Packit b5b901
    if (nevents != 0) {
Packit b5b901
      if (nfds == ARRAY_SIZE(events) && --count != 0) {
Packit b5b901
        /* Poll for more events but don't block this time. */
Packit b5b901
        timeout = 0;
Packit b5b901
        continue;
Packit b5b901
      }
Packit b5b901
      return;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    if (timeout == 0)
Packit b5b901
      return;
Packit b5b901
Packit b5b901
    if (timeout == -1)
Packit b5b901
      continue;
Packit b5b901
Packit b5b901
update_timeout:
Packit b5b901
    assert(timeout > 0);
Packit b5b901
Packit b5b901
    real_timeout -= (loop->time - base);
Packit b5b901
    if (real_timeout <= 0)
Packit b5b901
      return;
Packit b5b901
Packit b5b901
    timeout = real_timeout;
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
void uv__set_process_title(const char* title) {
Packit b5b901
  /* do nothing */
Packit b5b901
}
Packit b5b901
Packit b5b901
int uv__io_fork(uv_loop_t* loop) {
Packit Service e08953
  /*
Packit b5b901
    Nullify the msg queue but don't close it because
Packit b5b901
    it is still being used by the parent.
Packit b5b901
  */
Packit b5b901
  loop->ep = NULL;
Packit b5b901
Packit b5b901
  uv__platform_loop_delete(loop);
Packit b5b901
  return uv__platform_loop_init(loop);
Packit b5b901
}