Merge branch 'upstream-libuv' into update-libuv

* upstream-libuv:
  libuv 2017-02-21 (52ae8264)
This commit is contained in:
Brad King
2017-02-21 19:38:46 -05:00
34 changed files with 1530 additions and 256 deletions

View File

@@ -18,7 +18,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#define _UV_PTHREAD_BARRIER_
#include <errno.h>
#include <pthread.h>
#if !defined(__MVS__)
#include <semaphore.h> /* sem_t */
#endif
#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345

View File

@@ -24,4 +24,7 @@
#define UV_PLATFORM_SEM_T int
#define UV_PLATFORM_LOOP_FIELDS \
void* ep; \
#endif /* UV_MVS_H */

View File

@@ -36,7 +36,9 @@
#include <termios.h>
#include <pwd.h>
#if !defined(__MVS__)
#include <semaphore.h>
#endif
#include <pthread.h>
#include <signal.h>
@@ -44,6 +46,8 @@
#if defined(__linux__)
# include "uv-linux.h"
#elif defined (__MVS__)
# include "uv-os390.h"
#elif defined(_AIX)
# include "uv-aix.h"
#elif defined(__sun)

View File

@@ -31,8 +31,8 @@
*/
#define UV_VERSION_MAJOR 1
#define UV_VERSION_MINOR 9
#define UV_VERSION_PATCH 2
#define UV_VERSION_MINOR 11
#define UV_VERSION_PATCH 1
#define UV_VERSION_IS_RELEASE 0
#define UV_VERSION_SUFFIX "dev"

View File

@@ -49,6 +49,7 @@ typedef struct pollfd {
#include <process.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>
#if defined(_MSC_VER) && _MSC_VER < 1600

View File

@@ -367,6 +367,8 @@ typedef enum {
} uv_membership;
UV_EXTERN int uv_translate_sys_error(int sys_errno);
UV_EXTERN const char* uv_strerror(int err);
UV_EXTERN const char* uv_err_name(int err);

View File

@@ -64,6 +64,11 @@
#define RDWR_BUF_SIZE 4096
#define EQ(a,b) (strcmp(a,b) == 0)
static void* args_mem = NULL;
static char** process_argv = NULL;
static int process_argc = 0;
static char* process_title_ptr = NULL;
int uv__platform_loop_init(uv_loop_t* loop) {
loop->fs_fd = -1;
@@ -753,6 +758,13 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int
assert((bytes >= 0) && "uv__ahafs_event - Error reading monitor file");
/* In file / directory move cases, AIX Event infrastructure
* produces a second event with no data.
* Ignore it and return gracefully.
*/
if(bytes == 0)
return;
/* Parse the data */
if(bytes > 0)
rc = uv__parse_data(result_data, &events, handle);
@@ -881,24 +893,94 @@ void uv__fs_event_close(uv_fs_event_t* handle) {
char** uv_setup_args(int argc, char** argv) {
return argv;
char** new_argv;
size_t size;
char* s;
int i;
if (argc <= 0)
return argv;
/* Save the original pointer to argv.
* AIX uses argv to read the process name.
* (Not the memory pointed to by argv[0..n] as on Linux.)
*/
process_argv = argv;
process_argc = argc;
/* Calculate how much memory we need for the argv strings. */
size = 0;
for (i = 0; i < argc; i++)
size += strlen(argv[i]) + 1;
/* Add space for the argv pointers. */
size += (argc + 1) * sizeof(char*);
new_argv = uv__malloc(size);
if (new_argv == NULL)
return argv;
args_mem = new_argv;
/* Copy over the strings and set up the pointer table. */
s = (char*) &new_argv[argc + 1];
for (i = 0; i < argc; i++) {
size = strlen(argv[i]) + 1;
memcpy(s, argv[i], size);
new_argv[i] = s;
s += size;
}
new_argv[i] = NULL;
return new_argv;
}
int uv_set_process_title(const char* title) {
char* new_title;
/* We cannot free this pointer when libuv shuts down,
* the process may still be using it.
*/
new_title = uv__strdup(title);
if (new_title == NULL)
return -ENOMEM;
/* If this is the first time this is set,
* don't free and set argv[1] to NULL.
*/
if (process_title_ptr != NULL)
uv__free(process_title_ptr);
process_title_ptr = new_title;
process_argv[0] = process_title_ptr;
if (process_argc > 1)
process_argv[1] = NULL;
return 0;
}
int uv_get_process_title(char* buffer, size_t size) {
size_t len;
len = strlen(process_argv[0]);
if (buffer == NULL || size == 0)
return -EINVAL;
else if (size <= len)
return -ENOBUFS;
memcpy(buffer, process_argv[0], len + 1);
buffer[0] = '\0';
return 0;
}
UV_DESTRUCTOR(static void free_args_mem(void)) {
uv__free(args_mem); /* Keep valgrind happy. */
args_mem = NULL;
}
int uv_resident_set_memory(size_t* rss) {
char pp[64];
psinfo_t psinfo;

View File

@@ -43,8 +43,12 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
__compare_and_swap(ptr, &oldval, newval);
return out;
#elif defined(__MVS__)
return __plo_CS(ptr, (unsigned int*) ptr,
oldval, (unsigned int*) &newval);
unsigned int op4;
if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
(unsigned int*) ptr, *ptr, &op4))
return oldval;
else
return op4;
#else
return __sync_val_compare_and_swap(ptr, oldval, newval);
#endif
@@ -67,13 +71,18 @@ UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) {
# endif /* if defined(__64BIT__) */
return out;
#elif defined (__MVS__)
# ifdef _LP64
return __plo_CSGR(ptr, (unsigned long long*) ptr,
oldval, (unsigned long long*) &newval);
# else
return __plo_CS(ptr, (unsigned int*) ptr,
oldval, (unsigned int*) &newval);
# endif
#ifdef _LP64
unsigned long long op4;
if (__plo_CSSTGR(ptr, (unsigned long long*) &oldval, newval,
(unsigned long long*) ptr, *ptr, &op4))
#else
unsigned long op4;
if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
(unsigned int*) ptr, *ptr, &op4))
#endif
return oldval;
else
return op4;
#else
return __sync_val_compare_and_swap(ptr, oldval, newval);
#endif

View File

@@ -98,7 +98,7 @@ uint64_t uv_hrtime(void) {
void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
assert(!uv__is_closing(handle));
handle->flags |= UV_CLOSING;
handle->close_cb = close_cb;
@@ -517,6 +517,9 @@ int uv__close_nocheckstdio(int fd) {
int uv__close(int fd) {
assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */
#if defined(__MVS__)
epoll_file_close(fd);
#endif
return uv__close_nocheckstdio(fd);
}
@@ -836,13 +839,8 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
* every tick of the event loop but the other backends allow us to
* short-circuit here if the event mask is unchanged.
*/
if (w->events == w->pevents) {
if (w->events == 0 && !QUEUE_EMPTY(&w->watcher_queue)) {
QUEUE_REMOVE(&w->watcher_queue);
QUEUE_INIT(&w->watcher_queue);
}
if (w->events == w->pevents)
return;
}
#endif
if (QUEUE_EMPTY(&w->watcher_queue))
@@ -1236,3 +1234,9 @@ void uv_os_free_passwd(uv_passwd_t* pwd) {
int uv_os_get_passwd(uv_passwd_t* pwd) {
return uv__getpwuid_r(pwd);
}
int uv_translate_sys_error(int sys_errno) {
/* If < 0 then it's already a libuv error. */
return sys_errno <= 0 ? sys_errno : -sys_errno;
}

View File

@@ -129,8 +129,23 @@
static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
#if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
return fdatasync(req->file);
#elif defined(__APPLE__) && defined(SYS_fdatasync)
return syscall(SYS_fdatasync, req->file);
#elif defined(__APPLE__)
/* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache
* to the drive platters. This is in contrast to Linux's fdatasync and fsync
* which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent
* for flushing buffered data to permanent storage.
*/
return fcntl(req->file, F_FULLFSYNC);
#else
return fsync(req->file);
#endif
}
static ssize_t uv__fs_fsync(uv_fs_t* req) {
#if defined(__APPLE__)
/* See the comment in uv__fs_fdatasync. */
return fcntl(req->file, F_FULLFSYNC);
#else
return fsync(req->file);
#endif
@@ -365,7 +380,6 @@ static int uv__fs_scandir_sort(UV_CONST_DIRENT** a, UV_CONST_DIRENT** b) {
static ssize_t uv__fs_scandir(uv_fs_t* req) {
uv__dirent_t **dents;
int saved_errno;
int n;
dents = NULL;
@@ -374,29 +388,18 @@ static ssize_t uv__fs_scandir(uv_fs_t* req) {
/* NOTE: We will use nbufs as an index field */
req->nbufs = 0;
if (n == 0)
goto out; /* osx still needs to deallocate some memory */
else if (n == -1)
if (n == 0) {
/* OS X still needs to deallocate some memory.
* Memory was allocated using the system allocator, so use free() here.
*/
free(dents);
dents = NULL;
} else if (n == -1) {
return n;
}
req->ptr = dents;
return n;
out:
saved_errno = errno;
if (dents != NULL) {
int i;
/* Memory was allocated using the system allocator, so use free() here. */
for (i = 0; i < n; i++)
free(dents[i]);
free(dents);
}
errno = saved_errno;
req->ptr = NULL;
return n;
}
@@ -798,6 +801,10 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
dst->st_flags = 0;
dst->st_gen = 0;
#elif !defined(_AIX) && ( \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
defined(__NetBSD__) || \
defined(_GNU_SOURCE) || \
defined(_BSD_SOURCE) || \
defined(_SVID_SOURCE) || \
@@ -809,9 +816,7 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec;
dst->st_ctim.tv_sec = src->st_ctim.tv_sec;
dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec;
# if defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
# if defined(__FreeBSD__) || \
defined(__NetBSD__)
dst->st_birthtim.tv_sec = src->st_birthtim.tv_sec;
dst->st_birthtim.tv_nsec = src->st_birthtim.tv_nsec;
@@ -945,7 +950,7 @@ static void uv__fs_work(struct uv__work* w) {
X(FCHOWN, fchown(req->file, req->uid, req->gid));
X(FDATASYNC, uv__fs_fdatasync(req));
X(FSTAT, uv__fs_fstat(req->file, &req->statbuf));
X(FSYNC, fsync(req->file));
X(FSYNC, uv__fs_fsync(req));
X(FTRUNCATE, ftruncate(req->file, req->off));
X(FUTIME, uv__fs_futime(req));
X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));

View File

@@ -38,6 +38,10 @@
# include "linux-syscalls.h"
#endif /* __linux__ */
#if defined(__MVS__)
# include "os390-syscalls.h"
#endif /* __MVS__ */
#if defined(__sun)
# include <sys/port.h>
# include <port.h>
@@ -51,6 +55,10 @@
# include <poll.h>
#endif /* _AIX */
#if defined(__APPLE__) && !TARGET_OS_IPHONE
# include <AvailabilityMacros.h>
#endif
#if defined(__ANDROID__)
int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
# ifdef pthread_sigmask
@@ -154,7 +162,8 @@ struct uv__stream_queued_fds_s {
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || \
defined(__linux__)
defined(__linux__) || \
defined(__OpenBSD__)
#define uv__cloexec uv__cloexec_ioctl
#define uv__nonblock uv__nonblock_ioctl
#else
@@ -268,7 +277,6 @@ int uv__make_socketpair(int fds[2], int flags);
int uv__make_pipe(int fds[2], int flags);
#if defined(__APPLE__)
#include <AvailabilityMacros.h>
int uv__fsevents_init(uv_fs_event_t* handle);
int uv__fsevents_close(uv_fs_event_t* handle);

View File

@@ -163,7 +163,7 @@ char** uv_setup_args(int argc, char** argv) {
int uv_set_process_title(const char* title) {
uv__free(process_title);
process_title = uv__strdup(title);
setproctitle(title);
setproctitle("%s", title);
return 0;
}

View File

@@ -0,0 +1,334 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "os390-syscalls.h"
#include <errno.h>
#include <stdlib.h>
#include <assert.h>
#include <search.h>
#define CW_CONDVAR 32
#pragma linkage(BPX4CTW, OS)
#pragma linkage(BPX1CTW, OS)
static int number_of_epolls;
static QUEUE global_epoll_queue;
static uv_mutex_t global_epoll_lock;
static uv_once_t once = UV_ONCE_INIT;
int scandir(const char* maindir, struct dirent*** namelist,
int (*filter)(const struct dirent*),
int (*compar)(const struct dirent**,
const struct dirent **)) {
struct dirent** nl;
struct dirent* dirent;
unsigned count;
size_t allocated;
DIR* mdir;
nl = NULL;
count = 0;
allocated = 0;
mdir = opendir(maindir);
if (!mdir)
return -1;
while (1) {
dirent = readdir(mdir);
if (!dirent)
break;
if (!filter || filter(dirent)) {
struct dirent* copy;
copy = uv__malloc(sizeof(*copy));
if (!copy) {
while (count) {
dirent = nl[--count];
uv__free(dirent);
}
uv__free(nl);
closedir(mdir);
errno = ENOMEM;
return -1;
}
memcpy(copy, dirent, sizeof(*copy));
nl = uv__realloc(nl, sizeof(*copy) * (count + 1));
nl[count++] = copy;
}
}
qsort(nl, count, sizeof(struct dirent *),
(int (*)(const void *, const void *)) compar);
closedir(mdir);
*namelist = nl;
return count;
}
static unsigned int next_power_of_two(unsigned int val) {
val -= 1;
val |= val >> 1;
val |= val >> 2;
val |= val >> 4;
val |= val >> 8;
val |= val >> 16;
val += 1;
return val;
}
static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
unsigned int newsize;
unsigned int i;
struct pollfd* newlst;
if (len <= lst->size)
return;
newsize = next_power_of_two(len);
newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0]));
if (newlst == NULL)
abort();
for (i = lst->size; i < newsize; ++i)
newlst[i].fd = -1;
lst->items = newlst;
lst->size = newsize;
}
static void epoll_init() {
QUEUE_INIT(&global_epoll_queue);
if (uv_mutex_init(&global_epoll_lock))
abort();
}
uv__os390_epoll* epoll_create1(int flags) {
uv__os390_epoll* lst;
uv_once(&once, epoll_init);
uv_mutex_lock(&global_epoll_lock);
lst = uv__malloc(sizeof(*lst));
if (lst == -1)
return NULL;
QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member);
uv_mutex_unlock(&global_epoll_lock);
/* initialize list */
lst->size = 0;
lst->items = NULL;
return lst;
}
int epoll_ctl(uv__os390_epoll* lst,
int op,
int fd,
struct epoll_event *event) {
if(op == EPOLL_CTL_DEL) {
if (fd >= lst->size || lst->items[fd].fd == -1) {
errno = ENOENT;
return -1;
}
lst->items[fd].fd = -1;
} else if(op == EPOLL_CTL_ADD) {
maybe_resize(lst, fd + 1);
if (lst->items[fd].fd != -1) {
errno = EEXIST;
return -1;
}
lst->items[fd].fd = fd;
lst->items[fd].events = event->events;
} else if(op == EPOLL_CTL_MOD) {
if (fd >= lst->size || lst->items[fd].fd == -1) {
errno = ENOENT;
return -1;
}
lst->items[fd].events = event->events;
} else
abort();
return 0;
}
int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
int maxevents, int timeout) {
size_t size;
struct pollfd* pfds;
int pollret;
int reventcount;
uv_mutex_lock(&global_epoll_lock);
uv_mutex_unlock(&global_epoll_lock);
size = lst->size;
pfds = lst->items;
pollret = poll(pfds, size, timeout);
if(pollret == -1)
return pollret;
reventcount = 0;
for (int i = 0; i < lst->size && i < maxevents; ++i) {
struct epoll_event ev;
ev.events = 0;
ev.fd = pfds[i].fd;
if(!pfds[i].revents)
continue;
if(pfds[i].revents & POLLRDNORM)
ev.events = ev.events | POLLIN;
if(pfds[i].revents & POLLWRNORM)
ev.events = ev.events | POLLOUT;
if(pfds[i].revents & POLLHUP)
ev.events = ev.events | POLLHUP;
pfds[i].revents = 0;
events[reventcount++] = ev;
}
return reventcount;
}
int epoll_file_close(int fd) {
QUEUE* q;
uv_once(&once, epoll_init);
uv_mutex_lock(&global_epoll_lock);
QUEUE_FOREACH(q, &global_epoll_queue) {
uv__os390_epoll* lst;
lst = QUEUE_DATA(q, uv__os390_epoll, member);
if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1)
lst->items[fd].fd = -1;
}
uv_mutex_unlock(&global_epoll_lock);
return 0;
}
void epoll_queue_close(uv__os390_epoll* lst) {
uv_mutex_lock(&global_epoll_lock);
QUEUE_REMOVE(&lst->member);
uv_mutex_unlock(&global_epoll_lock);
uv__free(lst->items);
lst->items = NULL;
}
int nanosleep(const struct timespec* req, struct timespec* rem) {
unsigned nano;
unsigned seconds;
unsigned events;
unsigned secrem;
unsigned nanorem;
int rv;
int rc;
int rsn;
nano = (int)req->tv_nsec;
seconds = req->tv_sec;
events = CW_CONDVAR;
#if defined(_LP64)
BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn);
#else
BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn);
#endif
assert(rv == -1 && errno == EAGAIN);
if(rem != NULL) {
rem->tv_nsec = nanorem;
rem->tv_sec = secrem;
}
return 0;
}
char* mkdtemp(char* path) {
static const char* tempchars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static const size_t num_chars = 62;
static const size_t num_x = 6;
char *ep, *cp;
unsigned int tries, i;
size_t len;
uint64_t v;
int fd;
int retval;
int saved_errno;
len = strlen(path);
ep = path + len;
if (len < num_x || strncmp(ep - num_x, "XXXXXX", num_x)) {
errno = EINVAL;
return NULL;
}
fd = open("/dev/urandom", O_RDONLY);
if (fd == -1)
return NULL;
tries = TMP_MAX;
retval = -1;
do {
if (read(fd, &v, sizeof(v)) != sizeof(v))
break;
cp = ep - num_x;
for (i = 0; i < num_x; i++) {
*cp++ = tempchars[v % num_chars];
v /= num_chars;
}
if (mkdir(path, S_IRWXU) == 0) {
retval = 0;
break;
}
else if (errno != EEXIST)
break;
} while (--tries);
saved_errno = errno;
uv__close(fd);
if (tries == 0) {
errno = EEXIST;
return NULL;
}
if (retval == -1) {
errno = saved_errno;
return NULL;
}
return path;
}

View File

@@ -0,0 +1,69 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_OS390_SYSCALL_H_
#define UV_OS390_SYSCALL_H_
#include "uv.h"
#include "internal.h"
#include <dirent.h>
#include <poll.h>
#include <pthread.h>
#define EPOLL_CTL_ADD 1
#define EPOLL_CTL_DEL 2
#define EPOLL_CTL_MOD 3
#define MAX_EPOLL_INSTANCES 256
#define MAX_ITEMS_PER_EPOLL 1024
#define UV__O_CLOEXEC 0x80000
#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC
#define UV__EPOLL_CTL_ADD EPOLL_CTL_ADD
#define UV__EPOLL_CTL_DEL EPOLL_CTL_DEL
#define UV__EPOLL_CTL_MOD EPOLL_CTL_MOD
struct epoll_event {
int events;
int fd;
};
typedef struct {
QUEUE member;
struct pollfd* items;
unsigned long size;
} uv__os390_epoll;
/* epoll api */
uv__os390_epoll* epoll_create1(int flags);
int epoll_ctl(uv__os390_epoll* ep, int op, int fd, struct epoll_event *event);
int epoll_wait(uv__os390_epoll* ep, struct epoll_event *events, int maxevents, int timeout);
int epoll_file_close(int fd);
/* utility functions */
int nanosleep(const struct timespec* req, struct timespec* rem);
int scandir(const char* maindir, struct dirent*** namelist,
int (*filter)(const struct dirent *),
int (*compar)(const struct dirent **,
const struct dirent **));
char *mkdtemp(char* path);
#endif /* UV_OS390_SYSCALL_H_ */

View File

@@ -20,6 +20,628 @@
*/
#include "internal.h"
#include <sys/ioctl.h>
#include <net/if.h>
#include <utmpx.h>
#include <unistd.h>
#include <sys/ps.h>
#if defined(__clang__)
#include "csrsic.h"
#else
#include "//'SYS1.SAMPLIB(CSRSIC)'"
#endif
#define CVT_PTR 0x10
#define CSD_OFFSET 0x294
/*
Long-term average CPU service used by this logical partition,
in millions of service units per hour. If this value is above
the partition's defined capacity, the partition will be capped.
It is calculated using the physical CPU adjustment factor
(RCTPCPUA) so it may not match other measures of service which
are based on the logical CPU adjustment factor. It is available
if the hardware supports LPAR cluster.
*/
#define RCTLACS_OFFSET 0xC4
/* 32-bit count of alive CPUs. This includes both CPs and IFAs */
#define CSD_NUMBER_ONLINE_CPUS 0xD4
/* Address of system resources manager (SRM) control table */
#define CVTOPCTP_OFFSET 0x25C
/* Address of the RCT table */
#define RMCTRCT_OFFSET 0xE4
/* Address of the rsm control and enumeration area. */
#define CVTRCEP_OFFSET 0x490
/*
Number of frames currently available to system.
Excluded are frames backing perm storage, frames offline, and bad frames.
*/
#define RCEPOOL_OFFSET 0x004
/* Total number of frames currently on all available frame queues. */
#define RCEAFC_OFFSET 0x088
/* CPC model length from the CSRSI Service. */
#define CPCMODEL_LENGTH 16
/* Thread Entry constants */
#define PGTH_CURRENT 1
#define PGTH_LEN 26
#define PGTHAPATH 0x20
#pragma linkage(BPX4GTH, OS)
#pragma linkage(BPX1GTH, OS)
typedef unsigned data_area_ptr_assign_type;
typedef union {
struct {
#if defined(_LP64)
data_area_ptr_assign_type lower;
#endif
data_area_ptr_assign_type assign;
};
char* deref;
} data_area_ptr;
void uv_loadavg(double avg[3]) {
/* TODO: implement the following */
avg[0] = 0;
avg[1] = 0;
avg[2] = 0;
}
int uv__platform_loop_init(uv_loop_t* loop) {
uv__os390_epoll* ep;
ep = epoll_create1(UV__EPOLL_CLOEXEC);
loop->ep = ep;
if (ep == NULL)
return -errno;
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
if (loop->ep != NULL) {
epoll_queue_close(loop->ep);
loop->ep = NULL;
}
}
uint64_t uv__hrtime(uv_clocktype_t type) {
struct timeval time;
gettimeofday(&time, NULL);
return (uint64_t) time.tv_sec * 1e9 + time.tv_usec * 1e3;
}
/*
Get the exe path using the thread entry information
in the address space.
*/
static int getexe(const int pid, char* buf, size_t len) {
struct {
int pid;
int thid[2];
char accesspid;
char accessthid;
char asid[2];
char loginname[8];
char flag;
char len;
} Input_data;
union {
struct {
char gthb[4];
int pid;
int thid[2];
char accesspid;
char accessthid[3];
int lenused;
int offsetProcess;
int offsetConTTY;
int offsetPath;
int offsetCommand;
int offsetFileData;
int offsetThread;
} Output_data;
char buf[2048];
} Output_buf;
struct Output_path_type {
char gthe[4];
short int len;
char path[1024];
};
int Input_length;
int Output_length;
void* Input_address;
void* Output_address;
struct Output_path_type* Output_path;
int rv;
int rc;
int rsn;
Input_length = PGTH_LEN;
Output_length = sizeof(Output_buf);
Output_address = &Output_buf;
Input_address = &Input_data;
memset(&Input_data, 0, sizeof Input_data);
Input_data.flag |= PGTHAPATH;
Input_data.pid = pid;
Input_data.accesspid = PGTH_CURRENT;
#ifdef _LP64
BPX4GTH(&Input_length,
&Input_address,
&Output_length,
&Output_address,
&rv,
&rc,
&rsn);
#else
BPX1GTH(&Input_length,
&Input_address,
&Output_length,
&Output_address,
&rv,
&rc,
&rsn);
#endif
if (rv == -1) {
errno = rc;
return -1;
}
/* Check highest byte to ensure data availability */
assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A');
/* Get the offset from the lowest 3 bytes */
Output_path = (char*)(&Output_buf) +
(Output_buf.Output_data.offsetPath & 0x00FFFFFF);
if (Output_path->len >= len) {
errno = ENOBUFS;
return -1;
}
strncpy(buf, Output_path->path, len);
return 0;
}
/*
* We could use a static buffer for the path manipulations that we need outside
* of the function, but this function could be called by multiple consumers and
* we don't want to potentially create a race condition in the use of snprintf.
* There is no direct way of getting the exe path in zOS - either through /procfs
* or through some libc APIs. The below approach is to parse the argv[0]'s pattern
* and use it in conjunction with PATH environment variable to craft one.
*/
int uv_exepath(char* buffer, size_t* size) {
int res;
char args[PATH_MAX];
char abspath[PATH_MAX];
size_t abspath_size;
int pid;
if (buffer == NULL || size == NULL || *size == 0)
return -EINVAL;
pid = getpid();
res = getexe(pid, args, sizeof(args));
if (res < 0)
return -EINVAL;
/*
* Possibilities for args:
* i) an absolute path such as: /home/user/myprojects/nodejs/node
* ii) a relative path such as: ./node or ../myprojects/nodejs/node
* iii) a bare filename such as "node", after exporting PATH variable
* to its location.
*/
/* Case i) and ii) absolute or relative paths */
if (strchr(args, '/') != NULL) {
if (realpath(args, abspath) != abspath)
return -errno;
abspath_size = strlen(abspath);
*size -= 1;
if (*size > abspath_size)
*size = abspath_size;
memcpy(buffer, abspath, *size);
buffer[*size] = '\0';
return 0;
} else {
/* Case iii). Search PATH environment variable */
char trypath[PATH_MAX];
char* clonedpath = NULL;
char* token = NULL;
char* path = getenv("PATH");
if (path == NULL)
return -EINVAL;
clonedpath = uv__strdup(path);
if (clonedpath == NULL)
return -ENOMEM;
token = strtok(clonedpath, ":");
while (token != NULL) {
snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args);
if (realpath(trypath, abspath) == abspath) {
/* Check the match is executable */
if (access(abspath, X_OK) == 0) {
abspath_size = strlen(abspath);
*size -= 1;
if (*size > abspath_size)
*size = abspath_size;
memcpy(buffer, abspath, *size);
buffer[*size] = '\0';
uv__free(clonedpath);
return 0;
}
}
token = strtok(NULL, ":");
}
uv__free(clonedpath);
/* Out of tokens (path entries), and no match found */
return -EINVAL;
}
}
uint64_t uv_get_free_memory(void) {
uint64_t freeram;
data_area_ptr cvt = {0};
data_area_ptr rcep = {0};
cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
freeram = *((uint64_t*)(rcep.deref + RCEAFC_OFFSET)) * 4;
return freeram;
}
uint64_t uv_get_total_memory(void) {
uint64_t totalram;
data_area_ptr cvt = {0};
data_area_ptr rcep = {0};
cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
totalram = *((uint64_t*)(rcep.deref + RCEPOOL_OFFSET)) * 4;
return totalram;
}
int uv_resident_set_memory(size_t* rss) {
W_PSPROC buf;
memset(&buf, 0, sizeof(buf));
if (w_getpsent(0, &buf, sizeof(W_PSPROC)) == -1)
return -EINVAL;
*rss = buf.ps_size;
return 0;
}
int uv_uptime(double* uptime) {
struct utmpx u ;
struct utmpx *v;
time64_t t;
u.ut_type = BOOT_TIME;
v = getutxid(&u);
if (v == NULL)
return -1;
*uptime = difftime64(time64(&t), v->ut_tv.tv_sec);
return 0;
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
uv_cpu_info_t* cpu_info;
int result;
int idx;
siv1v2 info;
data_area_ptr cvt = {0};
data_area_ptr csd = {0};
data_area_ptr rmctrct = {0};
data_area_ptr cvtopctp = {0};
int cpu_usage_avg;
cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
csd.assign = *((data_area_ptr_assign_type *) (cvt.deref + CSD_OFFSET));
cvtopctp.assign = *((data_area_ptr_assign_type *) (cvt.deref + CVTOPCTP_OFFSET));
rmctrct.assign = *((data_area_ptr_assign_type *) (cvtopctp.deref + RMCTRCT_OFFSET));
*count = *((int*) (csd.deref + CSD_NUMBER_ONLINE_CPUS));
cpu_usage_avg = *((unsigned short int*) (rmctrct.deref + RCTLACS_OFFSET));
*cpu_infos = uv__malloc(*count * sizeof(uv_cpu_info_t));
if (!*cpu_infos)
return -ENOMEM;
cpu_info = *cpu_infos;
idx = 0;
while (idx < *count) {
cpu_info->speed = *(int*)(info.siv1v2si22v1.si22v1cpucapability);
cpu_info->model = uv__malloc(CPCMODEL_LENGTH + 1);
memset(cpu_info->model, '\0', CPCMODEL_LENGTH + 1);
memcpy(cpu_info->model, info.siv1v2si11v1.si11v1cpcmodel, CPCMODEL_LENGTH);
cpu_info->cpu_times.user = cpu_usage_avg;
/* TODO: implement the following */
cpu_info->cpu_times.sys = 0;
cpu_info->cpu_times.idle = 0;
cpu_info->cpu_times.irq = 0;
cpu_info->cpu_times.nice = 0;
++cpu_info;
++idx;
}
return 0;
}
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
for (int i = 0; i < count; ++i)
uv__free(cpu_infos[i].model);
uv__free(cpu_infos);
}
static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
int* count) {
uv_interface_address_t* address;
int sockfd;
int maxsize;
__net_ifconf6header_t ifc;
__net_ifconf6entry_t* ifr;
__net_ifconf6entry_t* p;
__net_ifconf6entry_t flg;
*count = 0;
/* Assume maximum buffer size allowable */
maxsize = 16384;
if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)))
return -errno;
ifc.__nif6h_version = 1;
ifc.__nif6h_buflen = maxsize;
ifc.__nif6h_buffer = uv__calloc(1, maxsize);;
if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) {
uv__close(sockfd);
return -errno;
}
*count = 0;
ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
p = ifr;
ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
p->__nif6e_addr.sin6_family == AF_INET))
continue;
if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
continue;
++(*count);
}
/* Alloc the return interface structs */
*addresses = uv__malloc(*count * sizeof(uv_interface_address_t));
if (!(*addresses)) {
uv__close(sockfd);
return -ENOMEM;
}
address = *addresses;
ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
p = ifr;
ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
p->__nif6e_addr.sin6_family == AF_INET))
continue;
if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
continue;
/* All conditions above must match count loop */
address->name = uv__strdup(p->__nif6e_name);
if (p->__nif6e_addr.sin6_family == AF_INET6)
address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr);
else
address->address.address4 = *((struct sockaddr_in*) &p->__nif6e_addr);
/* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
address++;
}
uv__close(sockfd);
return 0;
}
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
uv_interface_address_t* address;
int sockfd;
int maxsize;
struct ifconf ifc;
struct ifreq flg;
struct ifreq* ifr;
struct ifreq* p;
int count_v6;
/* get the ipv6 addresses first */
uv_interface_address_t* addresses_v6;
uv__interface_addresses_v6(&addresses_v6, &count_v6);
/* now get the ipv4 addresses */
*count = 0;
/* Assume maximum buffer size allowable */
maxsize = 16384;
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (0 > sockfd)
return -errno;
ifc.ifc_req = uv__calloc(1, maxsize);
ifc.ifc_len = maxsize;
if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
uv__close(sockfd);
return -errno;
}
#define MAX(a,b) (((a)>(b))?(a):(b))
#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
/* Count all up and running ipv4/ipv6 addresses */
ifr = ifc.ifc_req;
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
p = ifr;
ifr = (struct ifreq*)
((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
if (!(p->ifr_addr.sa_family == AF_INET6 ||
p->ifr_addr.sa_family == AF_INET))
continue;
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
uv__close(sockfd);
return -errno;
}
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
continue;
(*count)++;
}
/* Alloc the return interface structs */
*addresses = uv__malloc((*count + count_v6) *
sizeof(uv_interface_address_t));
if (!(*addresses)) {
uv__close(sockfd);
return -ENOMEM;
}
address = *addresses;
/* copy over the ipv6 addresses */
memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t));
address += count_v6;
*count += count_v6;
uv__free(addresses_v6);
ifr = ifc.ifc_req;
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
p = ifr;
ifr = (struct ifreq*)
((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
if (!(p->ifr_addr.sa_family == AF_INET6 ||
p->ifr_addr.sa_family == AF_INET))
continue;
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
uv__close(sockfd);
return -ENOSYS;
}
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
continue;
/* All conditions above must match count loop */
address->name = uv__strdup(p->ifr_name);
if (p->ifr_addr.sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
} else {
address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
}
address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
address++;
}
#undef ADDR_SIZE
#undef MAX
uv__close(sockfd);
return 0;
}
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {
int i;
for (i = 0; i < count; ++i)
uv__free(addresses[i].name);
uv__free(addresses);
}
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct epoll_event* events;
struct epoll_event dummy;
uintptr_t i;
uintptr_t nfds;
assert(loop->watchers != NULL);
events = (struct epoll_event*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events != NULL)
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if ((int) events[i].fd == fd)
events[i].fd = -1;
/* Remove the file descriptor from the epoll. */
if (loop->ep != NULL)
epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, &dummy);
}
int uv__io_check_fd(uv_loop_t* loop, int fd) {
struct pollfd p[1];
@@ -40,3 +662,204 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) {
return 0;
}
void uv__fs_event_close(uv_fs_event_t* handle) {
UNREACHABLE();
}
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
return -ENOSYS;
}
int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
const char* filename, unsigned int flags) {
return -ENOSYS;
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
return -ENOSYS;
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
static const int max_safe_timeout = 1789569;
struct epoll_event events[1024];
struct epoll_event* pe;
struct epoll_event e;
int real_timeout;
QUEUE* q;
uv__io_t* w;
uint64_t base;
int count;
int nfds;
int fd;
int op;
int i;
if (loop->nfds == 0) {
assert(QUEUE_EMPTY(&loop->watcher_queue));
return;
}
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
uv_stream_t* stream;
q = QUEUE_HEAD(&loop->watcher_queue);
QUEUE_REMOVE(q);
QUEUE_INIT(q);
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
assert(w->pevents != 0);
assert(w->fd >= 0);
stream= container_of(w, uv_stream_t, io_watcher);
assert(w->fd < (int) loop->nwatchers);
e.events = w->pevents;
e.fd = w->fd;
if (w->events == 0)
op = UV__EPOLL_CTL_ADD;
else
op = UV__EPOLL_CTL_MOD;
/* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
* events, skip the syscall and squelch the events after epoll_wait().
*/
if (epoll_ctl(loop->ep, op, w->fd, &e)) {
if (errno != EEXIST)
abort();
assert(op == UV__EPOLL_CTL_ADD);
/* We've reactivated a file descriptor that's been watched before. */
if (epoll_ctl(loop->ep, UV__EPOLL_CTL_MOD, w->fd, &e))
abort();
}
w->events = w->pevents;
}
assert(timeout >= -1);
base = loop->time;
count = 48; /* Benchmarks suggest this gives the best throughput. */
real_timeout = timeout;
int nevents = 0;
nfds = 0;
for (;;) {
if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
timeout = max_safe_timeout;
nfds = epoll_wait(loop->ep, events,
ARRAY_SIZE(events), timeout);
/* Update loop->time unconditionally. It's tempting to skip the update when
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
* operating system didn't reschedule our process while in the syscall.
*/
base = loop->time;
SAVE_ERRNO(uv__update_time(loop));
if (nfds == 0) {
assert(timeout != -1);
timeout = real_timeout - timeout;
if (timeout > 0)
continue;
return;
}
if (nfds == -1) {
if (errno != EINTR)
abort();
if (timeout == -1)
continue;
if (timeout == 0)
return;
/* Interrupted by a signal. Update timeout and poll again. */
goto update_timeout;
}
assert(loop->watchers != NULL);
loop->watchers[loop->nwatchers] = (void*) events;
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
for (i = 0; i < nfds; i++) {
pe = events + i;
fd = pe->fd;
/* Skip invalidated events, see uv__platform_invalidate_fd */
if (fd == -1)
continue;
assert(fd >= 0);
assert((unsigned) fd < loop->nwatchers);
w = loop->watchers[fd];
if (w == NULL) {
/* File descriptor that we've stopped watching, disarm it.
*
* Ignore all errors because we may be racing with another thread
* when the file descriptor is closed.
*/
epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, pe);
continue;
}
/* Give users only events they're interested in. Prevents spurious
* callbacks when previous callback invocation in this loop has stopped
* the current watcher. Also, filters out events that users has not
* requested us to watch.
*/
pe->events &= w->pevents | POLLERR | POLLHUP;
if (pe->events == POLLERR || pe->events == POLLHUP)
pe->events |= w->pevents & (POLLIN | POLLOUT);
if (pe->events != 0) {
w->cb(loop, w, pe->events);
nevents++;
}
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
/* Poll for more events but don't block this time. */
timeout = 0;
continue;
}
return;
}
if (timeout == 0)
return;
if (timeout == -1)
continue;
update_timeout:
assert(timeout > 0);
real_timeout -= (loop->time - base);
if (real_timeout <= 0)
return;
timeout = real_timeout;
}
}
void uv__set_process_title(const char* title) {
/* do nothing */
}

View File

@@ -92,7 +92,7 @@ static void uv__poll_stop(uv_poll_t* handle) {
int uv_poll_stop(uv_poll_t* handle) {
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
assert(!uv__is_closing(handle));
uv__poll_stop(handle);
return 0;
}
@@ -102,7 +102,7 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
int events;
assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
assert(!uv__is_closing(handle));
uv__poll_stop(handle);

View File

@@ -323,7 +323,7 @@ static void uv__process_child_init(const uv_process_options_t* options,
}
if (fd == use_fd)
uv__cloexec(use_fd, 0);
uv__cloexec_fcntl(use_fd, 0);
else
fd = dup2(use_fd, fd);
@@ -333,7 +333,7 @@ static void uv__process_child_init(const uv_process_options_t* options,
}
if (fd <= 2)
uv__nonblock(fd, 0);
uv__nonblock_fcntl(fd, 0);
if (close_fd >= stdio_count)
uv__close(close_fd);

View File

@@ -48,9 +48,15 @@ char** uv_setup_args(int argc, char** argv) {
for (i = 0; i < argc; i++)
size += strlen(argv[i]) + 1;
#if defined(__MVS__)
/* argv is not adjacent. So just use argv[0] */
process_title.str = argv[0];
process_title.len = strlen(argv[0]);
#else
process_title.str = argv[0];
process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0];
assert(process_title.len + 1 == size); /* argv memory should be adjacent. */
#endif
/* Add space for the argv pointers. */
size += (argc + 1) * sizeof(char*);

View File

@@ -73,7 +73,8 @@ int pthread_barrier_wait(pthread_barrier_t* barrier) {
if (++b->in == b->threshold) {
b->in = 0;
b->out = b->threshold - 1;
assert(pthread_cond_signal(&b->cond) == 0);
rc = pthread_cond_signal(&b->cond);
assert(rc == 0);
pthread_mutex_unlock(&b->mutex);
return PTHREAD_BARRIER_SERIAL_THREAD;

View File

@@ -43,7 +43,7 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2);
static void uv__signal_stop(uv_signal_t* handle);
static pthread_once_t uv__signal_global_init_guard = PTHREAD_ONCE_INIT;
static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT;
static struct uv__signal_tree_s uv__signal_tree =
RB_INITIALIZER(uv__signal_tree);
static int uv__signal_lock_pipefd[2];
@@ -64,7 +64,7 @@ static void uv__signal_global_init(void) {
void uv__signal_global_once_init(void) {
pthread_once(&uv__signal_global_init_guard, uv__signal_global_init);
uv_once(&uv__signal_global_init_guard, uv__signal_global_init);
}
@@ -290,7 +290,7 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
sigset_t saved_sigmask;
int err;
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
assert(!uv__is_closing(handle));
/* If the user supplies signum == 0, then return an error already. If the
* signum is otherwise invalid then uv__signal_register will find out
@@ -434,7 +434,7 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
int uv_signal_stop(uv_signal_t* handle) {
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
assert(!uv__is_closing(handle));
uv__signal_stop(handle);
return 0;
}

View File

@@ -390,7 +390,7 @@ failed_malloc:
int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
#if defined(__APPLE__)
#if defined(__APPLE__) || defined(__MVS__)
int enable;
#endif
@@ -409,7 +409,7 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
return -errno;
}
#if defined(__APPLE__)
#if defined(__APPLE__) || defined(__MVS__)
enable = 1;
if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) &&
errno != ENOTSOCK &&
@@ -1194,6 +1194,30 @@ static void uv__read(uv_stream_t* stream) {
return;
}
}
#if defined(__MVS__)
if (is_ipc && msg.msg_controllen > 0) {
uv_buf_t blankbuf;
int nread;
struct iovec *old;
blankbuf.base = 0;
blankbuf.len = 0;
old = msg.msg_iov;
msg.msg_iov = (struct iovec*) &blankbuf;
nread = 0;
do {
nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0);
err = uv__stream_recv_cmsg(stream, &msg);
if (err != 0) {
stream->read_cb(stream, err, &buf);
msg.msg_iov = old;
return;
}
} while (nread == 0 && msg.msg_controllen > 0);
msg.msg_iov = old;
}
#endif
stream->read_cb(stream, nread, &buf);
/* Return if we didn't fill the buffer, there is no more data to read. */
@@ -1221,8 +1245,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
if (!(stream->flags & UV_STREAM_WRITABLE) ||
stream->flags & UV_STREAM_SHUT ||
stream->flags & UV_STREAM_SHUTTING ||
stream->flags & UV_CLOSED ||
stream->flags & UV_CLOSING) {
uv__is_closing(stream)) {
return -ENOTCONN;
}

View File

@@ -695,6 +695,11 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
uv__free(cpu_infos);
}
#ifdef SUNOS_NO_IFADDRS
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
return -ENOSYS;
}
#else /* SUNOS_NO_IFADDRS */
/*
* Inspired By:
* https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris
@@ -742,9 +747,6 @@ static int uv__set_phys_addr(uv_interface_address_t* address,
}
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
#ifdef SUNOS_NO_IFADDRS
return -ENOSYS;
#else
uv_interface_address_t* address;
struct ifaddrs* addrs;
struct ifaddrs* ent;
@@ -805,9 +807,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
freeifaddrs(addrs);
return 0;
#endif /* SUNOS_NO_IFADDRS */
}
#endif /* SUNOS_NO_IFADDRS */
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {

View File

@@ -40,28 +40,8 @@
#undef NANOSEC
#define NANOSEC ((uint64_t) 1e9)
struct thread_ctx {
void (*entry)(void* arg);
void* arg;
};
static void* uv__thread_start(void *arg)
{
struct thread_ctx *ctx_p;
struct thread_ctx ctx;
ctx_p = arg;
ctx = *ctx_p;
uv__free(ctx_p);
ctx.entry(ctx.arg);
return 0;
}
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
struct thread_ctx* ctx;
int err;
pthread_attr_t* attr;
#if defined(__APPLE__)
@@ -69,13 +49,6 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
struct rlimit lim;
#endif
ctx = uv__malloc(sizeof(*ctx));
if (ctx == NULL)
return UV_ENOMEM;
ctx->entry = entry;
ctx->arg = arg;
/* On OSX threads other than the main thread are created with a reduced stack
* size by default, adjust it to RLIMIT_STACK.
*/
@@ -99,14 +72,11 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
attr = NULL;
#endif
err = pthread_create(tid, attr, uv__thread_start, ctx);
err = pthread_create(tid, attr, (void*(*)(void*)) entry, arg);
if (attr != NULL)
pthread_attr_destroy(attr);
if (err)
uv__free(ctx);
return -err;
}

View File

@@ -512,8 +512,18 @@ void uv__fs_scandir_cleanup(uv_fs_t* req) {
int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) {
uv__dirent_t** dents;
uv__dirent_t* dent;
unsigned int* nbufs;
unsigned int* nbufs = uv__get_nbufs(req);
/* Check to see if req passed */
if (req->result < 0)
return req->result;
/* Ptr will be null if req was canceled or no files found */
if (!req->ptr)
return UV_EOF;
nbufs = uv__get_nbufs(req);
assert(nbufs);
dents = req->ptr;

View File

@@ -35,10 +35,6 @@
#include "handle-inl.h"
#include "req-inl.h"
static uv_loop_t default_loop_struct;
static uv_loop_t* default_loop_ptr;
/* uv_once initialization guards */
static uv_once_t uv_init_guard_ = UV_ONCE_INIT;

View File

@@ -71,6 +71,7 @@ int uv_translate_sys_error(int sys_errno) {
switch (sys_errno) {
case ERROR_NOACCESS: return UV_EACCES;
case WSAEACCES: return UV_EACCES;
case ERROR_ELEVATION_REQUIRED: return UV_EACCES;
case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
case WSAEADDRINUSE: return UV_EADDRINUSE;
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;

View File

@@ -188,7 +188,6 @@ int uv_fs_event_start(uv_fs_event_t* handle,
if (is_path_dir) {
/* path is a directory, so that's the directory that we will watch. */
handle->dirw = pathw;
dir_to_watch = pathw;
} else {
/*
@@ -274,6 +273,8 @@ int uv_fs_event_start(uv_fs_event_t* handle,
goto error;
}
assert(is_path_dir ? pathw != NULL : pathw == NULL);
handle->dirw = pathw;
handle->req_pending = 1;
return 0;

View File

@@ -123,7 +123,7 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
const char* new_path, const int copy_path) {
char* buf;
char* pos;
ssize_t buf_sz = 0, path_len, pathw_len = 0, new_pathw_len = 0;
ssize_t buf_sz = 0, path_len = 0, pathw_len = 0, new_pathw_len = 0;
/* new_path can only be set if path is also set. */
assert(new_path == NULL || path != NULL);
@@ -403,7 +403,6 @@ void fs__open(uv_fs_t* req) {
switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
case _O_RDONLY:
access = FILE_GENERIC_READ;
attributes |= FILE_FLAG_BACKUP_SEMANTICS;
break;
case _O_WRONLY:
access = FILE_GENERIC_WRITE;
@@ -418,7 +417,6 @@ void fs__open(uv_fs_t* req) {
if (flags & _O_APPEND) {
access &= ~FILE_WRITE_DATA;
access |= FILE_APPEND_DATA;
attributes &= ~FILE_FLAG_BACKUP_SEMANTICS;
}
/*

View File

@@ -262,8 +262,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
int err;
if (req == NULL || (node == NULL && service == NULL)) {
err = WSAEINVAL;
goto error;
return UV_EINVAL;
}
uv_req_init(loop, (uv_req_t*)req);

View File

@@ -372,6 +372,7 @@ int uv__stdio_create(uv_loop_t* loop,
case FILE_TYPE_PIPE:
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
break;
case FILE_TYPE_CHAR:
case FILE_TYPE_REMOTE:

View File

@@ -492,7 +492,7 @@ WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) {
* input : hello\\"world
* output: "hello\\\\\"world"
* input : hello world\
* output: "hello world\"
* output: "hello world\\"
*/
*(target++) = L'"';

View File

@@ -30,12 +30,14 @@
RB_HEAD(uv_signal_tree_s, uv_signal_s);
static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree);
static ssize_t volatile uv__signal_control_handler_refs = 0;
static CRITICAL_SECTION uv__signal_lock;
static BOOL WINAPI uv__signal_control_handler(DWORD type);
void uv_signals_init() {
InitializeCriticalSection(&uv__signal_lock);
if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
abort();
}
@@ -125,102 +127,6 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) {
}
static int uv__signal_register_control_handler() {
/* When this function is called, the uv__signal_lock must be held. */
/* If the console control handler has already been hooked, just add a */
/* reference. */
if (uv__signal_control_handler_refs > 0) {
uv__signal_control_handler_refs++;
return 0;
}
if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
return GetLastError();
uv__signal_control_handler_refs++;
return 0;
}
static void uv__signal_unregister_control_handler() {
/* When this function is called, the uv__signal_lock must be held. */
BOOL r;
/* Don't unregister if the number of console control handlers exceeds one. */
/* Just remove a reference in that case. */
if (uv__signal_control_handler_refs > 1) {
uv__signal_control_handler_refs--;
return;
}
assert(uv__signal_control_handler_refs == 1);
r = SetConsoleCtrlHandler(uv__signal_control_handler, FALSE);
/* This should never fail; if it does it is probably a bug in libuv. */
assert(r);
uv__signal_control_handler_refs--;
}
static int uv__signal_register(int signum) {
switch (signum) {
case SIGINT:
case SIGBREAK:
case SIGHUP:
return uv__signal_register_control_handler();
case SIGWINCH:
/* SIGWINCH is generated in tty.c. No need to register anything. */
return 0;
case SIGILL:
case SIGABRT_COMPAT:
case SIGFPE:
case SIGSEGV:
case SIGTERM:
case SIGABRT:
/* Signal is never raised. */
return 0;
default:
/* Invalid signal. */
return ERROR_INVALID_PARAMETER;
}
}
static void uv__signal_unregister(int signum) {
switch (signum) {
case SIGINT:
case SIGBREAK:
case SIGHUP:
uv__signal_unregister_control_handler();
return;
case SIGWINCH:
/* SIGWINCH is generated in tty.c. No need to unregister anything. */
return;
case SIGILL:
case SIGABRT_COMPAT:
case SIGFPE:
case SIGSEGV:
case SIGTERM:
case SIGABRT:
/* Nothing is registered for this signal. */
return;
default:
/* Libuv bug. */
assert(0 && "Invalid signum");
return;
}
}
int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
uv_req_t* req;
@@ -247,8 +153,6 @@ int uv_signal_stop(uv_signal_t* handle) {
EnterCriticalSection(&uv__signal_lock);
uv__signal_unregister(handle->signum);
removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
assert(removed_handle == handle);
@@ -262,14 +166,9 @@ int uv_signal_stop(uv_signal_t* handle) {
int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
int err;
/* If the user supplies signum == 0, then return an error already. If the */
/* signum is otherwise invalid then uv__signal_register will find out */
/* eventually. */
if (signum == 0) {
/* Test for invalid signal values. */
if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG))
return UV_EINVAL;
}
/* Short circuit: if the signal watcher is already watching {signum} don't */
/* go through the process of deregistering and registering the handler. */
@@ -289,13 +188,6 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
EnterCriticalSection(&uv__signal_lock);
err = uv__signal_register(signum);
if (err) {
/* Uh-oh, didn't work. */
LeaveCriticalSection(&uv__signal_lock);
return uv_translate_sys_error(err);
}
handle->signum = signum;
RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);

View File

@@ -56,6 +56,7 @@
#define ANSI_BACKSLASH_SEEN 0x80
#define MAX_INPUT_BUFFER_LENGTH 8192
#define MAX_CONSOLE_CHAR 8192
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
@@ -1003,6 +1004,9 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
if (handle->tty.rd.last_key_len > 0) {
SET_REQ_SUCCESS(&handle->read_req);
uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
/* Make sure no attempt is made to insert it again until it's handled. */
handle->flags |= UV_HANDLE_READ_PENDING;
handle->reqs_pending++;
return 0;
}
@@ -1616,17 +1620,29 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
DWORD* error) {
/* We can only write 8k characters at a time. Windows can't handle */
/* much more characters in a single console write anyway. */
WCHAR utf16_buf[8192];
WCHAR utf16_buf[MAX_CONSOLE_CHAR];
WCHAR* utf16_buffer;
DWORD utf16_buf_used = 0;
unsigned int i;
unsigned int i, len, max_len, pos;
int allocate = 0;
#define FLUSH_TEXT() \
do { \
if (utf16_buf_used > 0) { \
uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \
utf16_buf_used = 0; \
} \
} while (0)
#define FLUSH_TEXT() \
do { \
pos = 0; \
do { \
len = utf16_buf_used - pos; \
if (len > MAX_CONSOLE_CHAR) \
len = MAX_CONSOLE_CHAR; \
uv_tty_emit_text(handle, &utf16_buffer[pos], len, error); \
pos += len; \
} while (pos < utf16_buf_used); \
if (allocate) { \
uv__free(utf16_buffer); \
allocate = 0; \
utf16_buffer = utf16_buf; \
} \
utf16_buf_used = 0; \
} while (0)
#define ENSURE_BUFFER_SPACE(wchars_needed) \
if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \
@@ -1644,39 +1660,48 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
/* state. */
*error = ERROR_SUCCESS;
utf16_buffer = utf16_buf;
uv_sem_wait(&uv_tty_output_lock);
for (i = 0; i < nbufs; i++) {
uv_buf_t buf = bufs[i];
unsigned int j;
if (uv__vterm_state == UV_SUPPORTED) {
utf16_buf_used = MultiByteToWideChar(CP_UTF8,
0,
buf.base,
buf.len,
NULL,
0);
if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) {
utf16_buf_used = MultiByteToWideChar(CP_UTF8,
0,
buf.base,
buf.len,
NULL,
0);
if (utf16_buf_used == 0) {
*error = GetLastError();
break;
if (utf16_buf_used == 0) {
*error = GetLastError();
break;
}
max_len = (utf16_buf_used + 1) * sizeof(WCHAR);
allocate = max_len > MAX_CONSOLE_CHAR;
if (allocate)
utf16_buffer = uv__malloc(max_len);
if (!MultiByteToWideChar(CP_UTF8,
0,
buf.base,
buf.len,
utf16_buffer,
utf16_buf_used)) {
if (allocate)
uv__free(utf16_buffer);
*error = GetLastError();
break;
}
FLUSH_TEXT();
continue;
}
if (!MultiByteToWideChar(CP_UTF8,
0,
buf.base,
buf.len,
utf16_buf,
utf16_buf_used)) {
*error = GetLastError();
break;
}
FLUSH_TEXT();
continue;
}
for (j = 0; j < buf.len; j++) {
unsigned char c = buf.base[j];

View File

@@ -4615,6 +4615,10 @@ typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
#endif
/* from winerror.h */
#ifndef ERROR_ELEVATION_REQUIRED
# define ERROR_ELEVATION_REQUIRED 740
#endif
#ifndef ERROR_SYMLINK_NOT_SUPPORTED
# define ERROR_SYMLINK_NOT_SUPPORTED 1464
#endif