Path: blob/master/Utilities/cmlibuv/src/unix/os390-syscalls.c
3156 views
/* Copyright libuv project contributors. All rights reserved.1*2* Permission is hereby granted, free of charge, to any person obtaining a copy3* of this software and associated documentation files (the "Software"), to4* deal in the Software without restriction, including without limitation the5* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or6* sell copies of the Software, and to permit persons to whom the Software is7* furnished to do so, subject to the following conditions:8*9* The above copyright notice and this permission notice shall be included in10* all copies or substantial portions of the Software.11*12* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR13* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,14* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE15* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER16* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING17* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS18* IN THE SOFTWARE.19*/202122#include "os390-syscalls.h"23#include <errno.h>24#include <stdlib.h>25#include <search.h>26#include <termios.h>27#include <sys/msg.h>2829static QUEUE global_epoll_queue;30static uv_mutex_t global_epoll_lock;31static uv_once_t once = UV_ONCE_INIT;3233int scandir(const char* maindir, struct dirent*** namelist,34int (*filter)(const struct dirent*),35int (*compar)(const struct dirent**,36const struct dirent **)) {37struct dirent** nl;38struct dirent** nl_copy;39struct dirent* dirent;40unsigned count;41size_t allocated;42DIR* mdir;4344nl = NULL;45count = 0;46allocated = 0;47mdir = opendir(maindir);48if (!mdir)49return -1;5051for (;;) {52dirent = readdir(mdir);53if (!dirent)54break;55if (!filter || filter(dirent)) {56struct dirent* copy;57copy = uv__malloc(sizeof(*copy));58if (!copy)59goto error;60memcpy(copy, dirent, sizeof(*copy));6162nl_copy = uv__realloc(nl, sizeof(*copy) * (count + 1));63if (nl_copy == NULL) {64uv__free(copy);65goto error;66}6768nl = nl_copy;69nl[count++] = copy;70}71}7273qsort(nl, count, sizeof(struct dirent *),74(int (*)(const void *, const void *)) compar);7576closedir(mdir);7778*namelist = nl;79return count;8081error:82while (count > 0) {83dirent = nl[--count];84uv__free(dirent);85}86uv__free(nl);87closedir(mdir);88errno = ENOMEM;89return -1;90}919293static unsigned int next_power_of_two(unsigned int val) {94val -= 1;95val |= val >> 1;96val |= val >> 2;97val |= val >> 4;98val |= val >> 8;99val |= val >> 16;100val += 1;101return val;102}103104105static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {106unsigned int newsize;107unsigned int i;108struct pollfd* newlst;109struct pollfd event;110111if (len <= lst->size)112return;113114if (lst->size == 0)115event.fd = -1;116else {117/* Extract the message queue at the end. */118event = lst->items[lst->size - 1];119lst->items[lst->size - 1].fd = -1;120}121122newsize = next_power_of_two(len);123newlst = uv__reallocf(lst->items, newsize * sizeof(lst->items[0]));124125if (newlst == NULL)126abort();127for (i = lst->size; i < newsize; ++i)128newlst[i].fd = -1;129130/* Restore the message queue at the end */131newlst[newsize - 1] = event;132133lst->items = newlst;134lst->size = newsize;135}136137138void uv__os390_cleanup(void) {139msgctl(uv_backend_fd(uv_default_loop()), IPC_RMID, NULL);140}141142143static void init_message_queue(uv__os390_epoll* lst) {144struct {145long int header;146char body;147} msg;148149/* initialize message queue */150lst->msg_queue = msgget(IPC_PRIVATE, 0600 | IPC_CREAT);151if (lst->msg_queue == -1)152abort();153154/*155On z/OS, the message queue will be affiliated with the process only156when a send is performed on it. Once this is done, the system157can be queried for all message queues belonging to our process id.158*/159msg.header = 1;160if (msgsnd(lst->msg_queue, &msg, sizeof(msg.body), 0) != 0)161abort();162163/* Clean up the dummy message sent above */164if (msgrcv(lst->msg_queue, &msg, sizeof(msg.body), 0, 0) != sizeof(msg.body))165abort();166}167168169static void before_fork(void) {170uv_mutex_lock(&global_epoll_lock);171}172173174static void after_fork(void) {175uv_mutex_unlock(&global_epoll_lock);176}177178179static void child_fork(void) {180QUEUE* q;181uv_once_t child_once = UV_ONCE_INIT;182183/* reset once */184memcpy(&once, &child_once, sizeof(child_once));185186/* reset epoll list */187while (!QUEUE_EMPTY(&global_epoll_queue)) {188uv__os390_epoll* lst;189q = QUEUE_HEAD(&global_epoll_queue);190QUEUE_REMOVE(q);191lst = QUEUE_DATA(q, uv__os390_epoll, member);192uv__free(lst->items);193lst->items = NULL;194lst->size = 0;195}196197uv_mutex_unlock(&global_epoll_lock);198uv_mutex_destroy(&global_epoll_lock);199}200201202static void epoll_init(void) {203QUEUE_INIT(&global_epoll_queue);204if (uv_mutex_init(&global_epoll_lock))205abort();206207if (pthread_atfork(&before_fork, &after_fork, &child_fork))208abort();209}210211212uv__os390_epoll* epoll_create1(int flags) {213uv__os390_epoll* lst;214215lst = uv__malloc(sizeof(*lst));216if (lst != NULL) {217/* initialize list */218lst->size = 0;219lst->items = NULL;220init_message_queue(lst);221maybe_resize(lst, 1);222lst->items[lst->size - 1].fd = lst->msg_queue;223lst->items[lst->size - 1].events = POLLIN;224lst->items[lst->size - 1].revents = 0;225uv_once(&once, epoll_init);226uv_mutex_lock(&global_epoll_lock);227QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member);228uv_mutex_unlock(&global_epoll_lock);229}230231return lst;232}233234235int epoll_ctl(uv__os390_epoll* lst,236int op,237int fd,238struct epoll_event *event) {239uv_mutex_lock(&global_epoll_lock);240241if (op == EPOLL_CTL_DEL) {242if (fd >= lst->size || lst->items[fd].fd == -1) {243uv_mutex_unlock(&global_epoll_lock);244errno = ENOENT;245return -1;246}247lst->items[fd].fd = -1;248} else if (op == EPOLL_CTL_ADD) {249250/* Resizing to 'fd + 1' would expand the list to contain at least251* 'fd'. But we need to guarantee that the last index on the list252* is reserved for the message queue. So specify 'fd + 2' instead.253*/254maybe_resize(lst, fd + 2);255if (lst->items[fd].fd != -1) {256uv_mutex_unlock(&global_epoll_lock);257errno = EEXIST;258return -1;259}260lst->items[fd].fd = fd;261lst->items[fd].events = event->events;262lst->items[fd].revents = 0;263} else if (op == EPOLL_CTL_MOD) {264if (fd >= lst->size - 1 || lst->items[fd].fd == -1) {265uv_mutex_unlock(&global_epoll_lock);266errno = ENOENT;267return -1;268}269lst->items[fd].events = event->events;270lst->items[fd].revents = 0;271} else272abort();273274uv_mutex_unlock(&global_epoll_lock);275return 0;276}277278#define EP_MAX_PFDS (ULONG_MAX / sizeof(struct pollfd))279#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))280281int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,282int maxevents, int timeout) {283nmsgsfds_t size;284struct pollfd* pfds;285int pollret;286int pollfdret;287int pollmsgret;288int reventcount;289int nevents;290struct pollfd msg_fd;291int i;292293if (!lst || !lst->items || !events) {294errno = EFAULT;295return -1;296}297298if (lst->size > EP_MAX_PFDS) {299errno = EINVAL;300return -1;301}302303if (maxevents <= 0 || maxevents > EP_MAX_EVENTS) {304errno = EINVAL;305return -1;306}307308assert(lst->size > 0);309_SET_FDS_MSGS(size, 1, lst->size - 1);310pfds = lst->items;311pollret = poll(pfds, size, timeout);312if (pollret <= 0)313return pollret;314315pollfdret = _NFDS(pollret);316pollmsgret = _NMSGS(pollret);317318reventcount = 0;319nevents = 0;320msg_fd = pfds[lst->size - 1]; /* message queue is always last entry */321maxevents = maxevents - pollmsgret; /* allow spot for message queue */322for (i = 0;323i < lst->size - 1 &&324nevents < maxevents &&325reventcount < pollfdret; ++i) {326struct epoll_event ev;327struct pollfd* pfd;328329pfd = &pfds[i];330if (pfd->fd == -1 || pfd->revents == 0)331continue;332333ev.fd = pfd->fd;334ev.events = pfd->revents;335ev.is_msg = 0;336337reventcount++;338events[nevents++] = ev;339}340341if (pollmsgret > 0 && msg_fd.revents != 0 && msg_fd.fd != -1) {342struct epoll_event ev;343ev.fd = msg_fd.fd;344ev.events = msg_fd.revents;345ev.is_msg = 1;346events[nevents++] = ev;347}348349return nevents;350}351352353int epoll_file_close(int fd) {354QUEUE* q;355356uv_once(&once, epoll_init);357uv_mutex_lock(&global_epoll_lock);358QUEUE_FOREACH(q, &global_epoll_queue) {359uv__os390_epoll* lst;360361lst = QUEUE_DATA(q, uv__os390_epoll, member);362if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1)363lst->items[fd].fd = -1;364}365366uv_mutex_unlock(&global_epoll_lock);367return 0;368}369370void epoll_queue_close(uv__os390_epoll* lst) {371/* Remove epoll instance from global queue */372uv_mutex_lock(&global_epoll_lock);373QUEUE_REMOVE(&lst->member);374uv_mutex_unlock(&global_epoll_lock);375376/* Free resources */377msgctl(lst->msg_queue, IPC_RMID, NULL);378lst->msg_queue = -1;379uv__free(lst->items);380lst->items = NULL;381}382383384char* mkdtemp(char* path) {385static const char* tempchars =386"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";387static const size_t num_chars = 62;388static const size_t num_x = 6;389char *ep, *cp;390unsigned int tries, i;391size_t len;392uint64_t v;393int fd;394int retval;395int saved_errno;396397len = strlen(path);398ep = path + len;399if (len < num_x || strncmp(ep - num_x, "XXXXXX", num_x)) {400errno = EINVAL;401return NULL;402}403404fd = open("/dev/urandom", O_RDONLY);405if (fd == -1)406return NULL;407408tries = TMP_MAX;409retval = -1;410do {411if (read(fd, &v, sizeof(v)) != sizeof(v))412break;413414cp = ep - num_x;415for (i = 0; i < num_x; i++) {416*cp++ = tempchars[v % num_chars];417v /= num_chars;418}419420if (mkdir(path, S_IRWXU) == 0) {421retval = 0;422break;423}424else if (errno != EEXIST)425break;426} while (--tries);427428saved_errno = errno;429uv__close(fd);430if (tries == 0) {431errno = EEXIST;432return NULL;433}434435if (retval == -1) {436errno = saved_errno;437return NULL;438}439440return path;441}442443444ssize_t os390_readlink(const char* path, char* buf, size_t len) {445ssize_t rlen;446ssize_t vlen;447ssize_t plen;448char* delimiter;449char old_delim;450char* tmpbuf;451char realpathstr[PATH_MAX + 1];452453tmpbuf = uv__malloc(len + 1);454if (tmpbuf == NULL) {455errno = ENOMEM;456return -1;457}458459rlen = readlink(path, tmpbuf, len);460if (rlen < 0) {461uv__free(tmpbuf);462return rlen;463}464465if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) {466/* Straightforward readlink. */467memcpy(buf, tmpbuf, rlen);468uv__free(tmpbuf);469return rlen;470}471472/*473* There is a parmlib variable at the beginning474* which needs interpretation.475*/476tmpbuf[rlen] = '\0';477delimiter = strchr(tmpbuf + 2, '/');478if (delimiter == NULL)479/* No slash at the end */480delimiter = strchr(tmpbuf + 2, '\0');481482/* Read real path of the variable. */483old_delim = *delimiter;484*delimiter = '\0';485if (realpath(tmpbuf, realpathstr) == NULL) {486uv__free(tmpbuf);487return -1;488}489490/* realpathstr is not guaranteed to end with null byte.*/491realpathstr[PATH_MAX] = '\0';492493/* Reset the delimiter and fill up the buffer. */494*delimiter = old_delim;495plen = strlen(delimiter);496vlen = strlen(realpathstr);497rlen = plen + vlen;498if (rlen > len) {499uv__free(tmpbuf);500errno = ENAMETOOLONG;501return -1;502}503memcpy(buf, realpathstr, vlen);504memcpy(buf + vlen, delimiter, plen);505506/* Done using temporary buffer. */507uv__free(tmpbuf);508509return rlen;510}511512513int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value) {514UNREACHABLE();515}516517518int sem_destroy(UV_PLATFORM_SEM_T* semid) {519UNREACHABLE();520}521522523int sem_post(UV_PLATFORM_SEM_T* semid) {524UNREACHABLE();525}526527528int sem_trywait(UV_PLATFORM_SEM_T* semid) {529UNREACHABLE();530}531532533int sem_wait(UV_PLATFORM_SEM_T* semid) {534UNREACHABLE();535}536537538