Merge branches/quickjs to trunk. This is the way.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3621 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
89
deps/libuv/src/unix/aix-common.c
vendored
Normal file
89
deps/libuv/src/unix/aix-common.c
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
/* 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <procinfo.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
extern char* original_exepath;
|
||||
extern uv_mutex_t process_title_mutex;
|
||||
extern uv_once_t process_title_mutex_once;
|
||||
extern void init_process_title_mutex_once(void);
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
uint64_t G = 1000000000;
|
||||
timebasestruct_t t;
|
||||
read_wall_time(&t, TIMEBASE_SZ);
|
||||
time_base_to_time(&t, TIMEBASE_SZ);
|
||||
return (uint64_t) t.tb_high * G + t.tb_low;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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 AIX - 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[UV__PATH_MAX];
|
||||
size_t cached_len;
|
||||
struct procsinfo pi;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
if (original_exepath != NULL) {
|
||||
cached_len = strlen(original_exepath);
|
||||
*size -= 1;
|
||||
if (*size > cached_len)
|
||||
*size = cached_len;
|
||||
memcpy(buffer, original_exepath, *size);
|
||||
buffer[*size] = '\0';
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return 0;
|
||||
}
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
pi.pi_pid = getpid();
|
||||
res = getargs(&pi, sizeof(pi), args, sizeof(args));
|
||||
|
||||
if (res < 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
return uv__search_path(args, buffer, size);
|
||||
}
|
1304
deps/libuv/src/unix/aix.c
vendored
Normal file
1304
deps/libuv/src/unix/aix.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
713
deps/libuv/src/unix/android-ifaddrs.c
vendored
Normal file
713
deps/libuv/src/unix/android-ifaddrs.c
vendored
Normal file
@ -0,0 +1,713 @@
|
||||
/*
|
||||
Copyright (c) 2013, Kenneth MacKay
|
||||
Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement #289016)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "uv/android-ifaddrs.h"
|
||||
#include "uv-common.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/if_packet.h>
|
||||
|
||||
typedef struct NetlinkList
|
||||
{
|
||||
struct NetlinkList *m_next;
|
||||
struct nlmsghdr *m_data;
|
||||
unsigned int m_size;
|
||||
} NetlinkList;
|
||||
|
||||
static int netlink_socket(pid_t *p_pid)
|
||||
{
|
||||
struct sockaddr_nl l_addr;
|
||||
socklen_t l_len;
|
||||
|
||||
int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if(l_socket < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&l_addr, 0, sizeof(l_addr));
|
||||
l_addr.nl_family = AF_NETLINK;
|
||||
if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
|
||||
{
|
||||
close(l_socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
l_len = sizeof(l_addr);
|
||||
if(getsockname(l_socket, (struct sockaddr *)&l_addr, &l_len) < 0)
|
||||
{
|
||||
close(l_socket);
|
||||
return -1;
|
||||
}
|
||||
*p_pid = l_addr.nl_pid;
|
||||
|
||||
return l_socket;
|
||||
}
|
||||
|
||||
static int netlink_send(int p_socket, int p_request)
|
||||
{
|
||||
char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
|
||||
|
||||
struct nlmsghdr *l_hdr;
|
||||
struct rtgenmsg *l_msg;
|
||||
struct sockaddr_nl l_addr;
|
||||
|
||||
memset(l_buffer, 0, sizeof(l_buffer));
|
||||
|
||||
l_hdr = (struct nlmsghdr *)l_buffer;
|
||||
l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
|
||||
|
||||
l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
|
||||
l_hdr->nlmsg_type = p_request;
|
||||
l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
|
||||
l_hdr->nlmsg_pid = 0;
|
||||
l_hdr->nlmsg_seq = p_socket;
|
||||
l_msg->rtgen_family = AF_UNSPEC;
|
||||
|
||||
memset(&l_addr, 0, sizeof(l_addr));
|
||||
l_addr.nl_family = AF_NETLINK;
|
||||
return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
|
||||
}
|
||||
|
||||
static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
|
||||
{
|
||||
struct sockaddr_nl l_addr;
|
||||
struct msghdr l_msg;
|
||||
|
||||
struct iovec l_iov;
|
||||
l_iov.iov_base = p_buffer;
|
||||
l_iov.iov_len = p_len;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int l_result;
|
||||
l_msg.msg_name = (void *)&l_addr;
|
||||
l_msg.msg_namelen = sizeof(l_addr);
|
||||
l_msg.msg_iov = &l_iov;
|
||||
l_msg.msg_iovlen = 1;
|
||||
l_msg.msg_control = NULL;
|
||||
l_msg.msg_controllen = 0;
|
||||
l_msg.msg_flags = 0;
|
||||
l_result = recvmsg(p_socket, &l_msg, 0);
|
||||
|
||||
if(l_result < 0)
|
||||
{
|
||||
if(errno == EINTR)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Buffer was too small */
|
||||
if(l_msg.msg_flags & MSG_TRUNC)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
|
||||
static struct nlmsghdr *getNetlinkResponse(int p_socket, pid_t p_pid, int *p_size, int *p_done)
|
||||
{
|
||||
size_t l_size = 4096;
|
||||
void *l_buffer = NULL;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int l_read;
|
||||
|
||||
uv__free(l_buffer);
|
||||
l_buffer = uv__malloc(l_size);
|
||||
if (l_buffer == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
l_read = netlink_recv(p_socket, l_buffer, l_size);
|
||||
*p_size = l_read;
|
||||
if(l_read == -2)
|
||||
{
|
||||
uv__free(l_buffer);
|
||||
return NULL;
|
||||
}
|
||||
if(l_read >= 0)
|
||||
{
|
||||
struct nlmsghdr *l_hdr;
|
||||
for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
|
||||
{
|
||||
if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
*p_done = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
uv__free(l_buffer);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return l_buffer;
|
||||
}
|
||||
|
||||
l_size *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
|
||||
{
|
||||
NetlinkList *l_item = uv__malloc(sizeof(NetlinkList));
|
||||
if (l_item == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
l_item->m_next = NULL;
|
||||
l_item->m_data = p_data;
|
||||
l_item->m_size = p_size;
|
||||
return l_item;
|
||||
}
|
||||
|
||||
static void freeResultList(NetlinkList *p_list)
|
||||
{
|
||||
NetlinkList *l_cur;
|
||||
while(p_list)
|
||||
{
|
||||
l_cur = p_list;
|
||||
p_list = p_list->m_next;
|
||||
uv__free(l_cur->m_data);
|
||||
uv__free(l_cur);
|
||||
}
|
||||
}
|
||||
|
||||
static NetlinkList *getResultList(int p_socket, int p_request, pid_t p_pid)
|
||||
{
|
||||
int l_size;
|
||||
int l_done;
|
||||
NetlinkList *l_list;
|
||||
NetlinkList *l_end;
|
||||
|
||||
if(netlink_send(p_socket, p_request) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
l_list = NULL;
|
||||
l_end = NULL;
|
||||
|
||||
l_done = 0;
|
||||
while(!l_done)
|
||||
{
|
||||
NetlinkList *l_item;
|
||||
|
||||
struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, p_pid, &l_size, &l_done);
|
||||
/* Error */
|
||||
if(!l_hdr)
|
||||
{
|
||||
freeResultList(l_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
l_item = newListItem(l_hdr, l_size);
|
||||
if (!l_item)
|
||||
{
|
||||
freeResultList(l_list);
|
||||
return NULL;
|
||||
}
|
||||
if(!l_list)
|
||||
{
|
||||
l_list = l_item;
|
||||
}
|
||||
else
|
||||
{
|
||||
l_end->m_next = l_item;
|
||||
}
|
||||
l_end = l_item;
|
||||
}
|
||||
return l_list;
|
||||
}
|
||||
|
||||
static size_t maxSize(size_t a, size_t b)
|
||||
{
|
||||
return (a > b ? a : b);
|
||||
}
|
||||
|
||||
static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
|
||||
{
|
||||
switch(p_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return sizeof(struct sockaddr_in);
|
||||
case AF_INET6:
|
||||
return sizeof(struct sockaddr_in6);
|
||||
case AF_PACKET:
|
||||
return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
|
||||
default:
|
||||
return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
|
||||
}
|
||||
}
|
||||
|
||||
static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
|
||||
{
|
||||
switch(p_family)
|
||||
{
|
||||
case AF_INET:
|
||||
memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
|
||||
break;
|
||||
case AF_INET6:
|
||||
memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
|
||||
break;
|
||||
case AF_PACKET:
|
||||
memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
|
||||
((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
|
||||
break;
|
||||
default:
|
||||
memcpy(p_dest->sa_data, p_data, p_size);
|
||||
break;
|
||||
}
|
||||
p_dest->sa_family = p_family;
|
||||
}
|
||||
|
||||
static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
|
||||
{
|
||||
if(!*p_resultList)
|
||||
{
|
||||
*p_resultList = p_entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct ifaddrs *l_cur = *p_resultList;
|
||||
while(l_cur->ifa_next)
|
||||
{
|
||||
l_cur = l_cur->ifa_next;
|
||||
}
|
||||
l_cur->ifa_next = p_entry;
|
||||
}
|
||||
}
|
||||
|
||||
static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
|
||||
{
|
||||
struct ifaddrs *l_entry;
|
||||
|
||||
char *l_index;
|
||||
char *l_name;
|
||||
char *l_addr;
|
||||
char *l_data;
|
||||
|
||||
struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
|
||||
|
||||
size_t l_nameSize = 0;
|
||||
size_t l_addrSize = 0;
|
||||
size_t l_dataSize = 0;
|
||||
|
||||
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
|
||||
struct rtattr *l_rta;
|
||||
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFLA_ADDRESS:
|
||||
case IFLA_BROADCAST:
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
|
||||
break;
|
||||
case IFLA_IFNAME:
|
||||
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
|
||||
break;
|
||||
case IFLA_STATS:
|
||||
l_dataSize += NLMSG_ALIGN(l_rtaSize);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
l_entry = uv__malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
|
||||
if (l_entry == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
memset(l_entry, 0, sizeof(struct ifaddrs));
|
||||
l_entry->ifa_name = "";
|
||||
|
||||
l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
|
||||
l_name = l_index + sizeof(int);
|
||||
l_addr = l_name + l_nameSize;
|
||||
l_data = l_addr + l_addrSize;
|
||||
|
||||
/* Save the interface index so we can look it up when handling the
|
||||
* addresses.
|
||||
*/
|
||||
memcpy(l_index, &l_info->ifi_index, sizeof(int));
|
||||
|
||||
l_entry->ifa_flags = l_info->ifi_flags;
|
||||
|
||||
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
|
||||
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
void *l_rtaData = RTA_DATA(l_rta);
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFLA_ADDRESS:
|
||||
case IFLA_BROADCAST:
|
||||
{
|
||||
size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
|
||||
makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
|
||||
((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
|
||||
((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
|
||||
if(l_rta->rta_type == IFLA_ADDRESS)
|
||||
{
|
||||
l_entry->ifa_addr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
l_addr += NLMSG_ALIGN(l_addrLen);
|
||||
break;
|
||||
}
|
||||
case IFLA_IFNAME:
|
||||
strncpy(l_name, l_rtaData, l_rtaDataSize);
|
||||
l_name[l_rtaDataSize] = '\0';
|
||||
l_entry->ifa_name = l_name;
|
||||
break;
|
||||
case IFLA_STATS:
|
||||
memcpy(l_data, l_rtaData, l_rtaDataSize);
|
||||
l_entry->ifa_data = l_data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
addToEnd(p_resultList, l_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
|
||||
{
|
||||
int l_num = 0;
|
||||
struct ifaddrs *l_cur = *p_links;
|
||||
while(l_cur && l_num < p_numLinks)
|
||||
{
|
||||
char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
|
||||
int l_index;
|
||||
memcpy(&l_index, l_indexPtr, sizeof(int));
|
||||
if(l_index == p_index)
|
||||
{
|
||||
return l_cur;
|
||||
}
|
||||
|
||||
l_cur = l_cur->ifa_next;
|
||||
++l_num;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
|
||||
{
|
||||
struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
|
||||
struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
|
||||
|
||||
size_t l_nameSize = 0;
|
||||
size_t l_addrSize = 0;
|
||||
|
||||
int l_addedNetmask = 0;
|
||||
|
||||
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
|
||||
struct rtattr *l_rta;
|
||||
struct ifaddrs *l_entry;
|
||||
|
||||
char *l_name;
|
||||
char *l_addr;
|
||||
|
||||
for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
if(l_info->ifa_family == AF_PACKET)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFA_ADDRESS:
|
||||
case IFA_LOCAL:
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
|
||||
if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
|
||||
{
|
||||
/* Make room for netmask */
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
|
||||
l_addedNetmask = 1;
|
||||
}
|
||||
break;
|
||||
case IFA_BROADCAST:
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
|
||||
break;
|
||||
case IFA_LABEL:
|
||||
l_nameSize += NLMSG_ALIGN(l_rtaDataSize + 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
l_entry = uv__malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
|
||||
if (l_entry == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
memset(l_entry, 0, sizeof(struct ifaddrs));
|
||||
l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
|
||||
|
||||
l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
|
||||
l_addr = l_name + l_nameSize;
|
||||
|
||||
l_entry->ifa_flags = l_info->ifa_flags;
|
||||
if(l_interface)
|
||||
{
|
||||
l_entry->ifa_flags |= l_interface->ifa_flags;
|
||||
}
|
||||
|
||||
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
|
||||
for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
void *l_rtaData = RTA_DATA(l_rta);
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFA_ADDRESS:
|
||||
case IFA_BROADCAST:
|
||||
case IFA_LOCAL:
|
||||
{
|
||||
size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
|
||||
makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
|
||||
if(l_info->ifa_family == AF_INET6)
|
||||
{
|
||||
if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
|
||||
{
|
||||
((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
|
||||
}
|
||||
}
|
||||
|
||||
/* Apparently in a point-to-point network IFA_ADDRESS contains
|
||||
* the dest address and IFA_LOCAL contains the local address
|
||||
*/
|
||||
if(l_rta->rta_type == IFA_ADDRESS)
|
||||
{
|
||||
if(l_entry->ifa_addr)
|
||||
{
|
||||
l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
l_entry->ifa_addr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
}
|
||||
else if(l_rta->rta_type == IFA_LOCAL)
|
||||
{
|
||||
if(l_entry->ifa_addr)
|
||||
{
|
||||
l_entry->ifa_dstaddr = l_entry->ifa_addr;
|
||||
}
|
||||
l_entry->ifa_addr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
l_addr += NLMSG_ALIGN(l_addrLen);
|
||||
break;
|
||||
}
|
||||
case IFA_LABEL:
|
||||
strncpy(l_name, l_rtaData, l_rtaDataSize);
|
||||
l_name[l_rtaDataSize] = '\0';
|
||||
l_entry->ifa_name = l_name;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
|
||||
{
|
||||
unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
|
||||
unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
|
||||
unsigned char l_mask[16] = {0};
|
||||
unsigned i;
|
||||
for(i=0; i<(l_prefix/8); ++i)
|
||||
{
|
||||
l_mask[i] = 0xff;
|
||||
}
|
||||
if(l_prefix % 8)
|
||||
{
|
||||
l_mask[i] = 0xff << (8 - (l_prefix % 8));
|
||||
}
|
||||
|
||||
makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
|
||||
l_entry->ifa_netmask = (struct sockaddr *)l_addr;
|
||||
}
|
||||
|
||||
addToEnd(p_resultList, l_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int interpretLinks(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
|
||||
{
|
||||
|
||||
int l_numLinks = 0;
|
||||
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
|
||||
{
|
||||
unsigned int l_nlsize = p_netlinkList->m_size;
|
||||
struct nlmsghdr *l_hdr;
|
||||
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
|
||||
{
|
||||
if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == RTM_NEWLINK)
|
||||
{
|
||||
if(interpretLink(l_hdr, p_resultList) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
++l_numLinks;
|
||||
}
|
||||
}
|
||||
}
|
||||
return l_numLinks;
|
||||
}
|
||||
|
||||
static int interpretAddrs(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
|
||||
{
|
||||
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
|
||||
{
|
||||
unsigned int l_nlsize = p_netlinkList->m_size;
|
||||
struct nlmsghdr *l_hdr;
|
||||
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
|
||||
{
|
||||
if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == RTM_NEWADDR)
|
||||
{
|
||||
if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getifaddrs(struct ifaddrs **ifap)
|
||||
{
|
||||
int l_socket;
|
||||
int l_result;
|
||||
int l_numLinks;
|
||||
pid_t l_pid;
|
||||
NetlinkList *l_linkResults;
|
||||
NetlinkList *l_addrResults;
|
||||
|
||||
if(!ifap)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
*ifap = NULL;
|
||||
|
||||
l_socket = netlink_socket(&l_pid);
|
||||
if(l_socket < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
l_linkResults = getResultList(l_socket, RTM_GETLINK, l_pid);
|
||||
if(!l_linkResults)
|
||||
{
|
||||
close(l_socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
l_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid);
|
||||
if(!l_addrResults)
|
||||
{
|
||||
close(l_socket);
|
||||
freeResultList(l_linkResults);
|
||||
return -1;
|
||||
}
|
||||
|
||||
l_result = 0;
|
||||
l_numLinks = interpretLinks(l_socket, l_pid, l_linkResults, ifap);
|
||||
if(l_numLinks == -1 || interpretAddrs(l_socket, l_pid, l_addrResults, ifap, l_numLinks) == -1)
|
||||
{
|
||||
l_result = -1;
|
||||
}
|
||||
|
||||
freeResultList(l_linkResults);
|
||||
freeResultList(l_addrResults);
|
||||
close(l_socket);
|
||||
return l_result;
|
||||
}
|
||||
|
||||
void freeifaddrs(struct ifaddrs *ifa)
|
||||
{
|
||||
struct ifaddrs *l_cur;
|
||||
while(ifa)
|
||||
{
|
||||
l_cur = ifa;
|
||||
ifa = ifa->ifa_next;
|
||||
uv__free(l_cur);
|
||||
}
|
||||
}
|
253
deps/libuv/src/unix/async.c
vendored
Normal file
253
deps/libuv/src/unix/async.c
vendored
Normal file
@ -0,0 +1,253 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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.
|
||||
*/
|
||||
|
||||
/* This file contains both the uv__async internal infrastructure and the
|
||||
* user-facing uv_async_t functions.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "atomic-ops.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h> /* snprintf() */
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h> /* sched_yield() */
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
|
||||
static void uv__async_send(uv_loop_t* loop);
|
||||
static int uv__async_start(uv_loop_t* loop);
|
||||
|
||||
|
||||
int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
|
||||
int err;
|
||||
|
||||
err = uv__async_start(loop);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC);
|
||||
handle->async_cb = async_cb;
|
||||
handle->pending = 0;
|
||||
|
||||
QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue);
|
||||
uv__handle_start(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_async_send(uv_async_t* handle) {
|
||||
/* Do a cheap read first. */
|
||||
if (ACCESS_ONCE(int, handle->pending) != 0)
|
||||
return 0;
|
||||
|
||||
/* Tell the other thread we're busy with the handle. */
|
||||
if (cmpxchgi(&handle->pending, 0, 1) != 0)
|
||||
return 0;
|
||||
|
||||
/* Wake up the other thread's event loop. */
|
||||
uv__async_send(handle->loop);
|
||||
|
||||
/* Tell the other thread we're done. */
|
||||
if (cmpxchgi(&handle->pending, 1, 2) != 1)
|
||||
abort();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Only call this from the event loop thread. */
|
||||
static int uv__async_spin(uv_async_t* handle) {
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
for (;;) {
|
||||
/* 997 is not completely chosen at random. It's a prime number, acyclical
|
||||
* by nature, and should therefore hopefully dampen sympathetic resonance.
|
||||
*/
|
||||
for (i = 0; i < 997; i++) {
|
||||
/* rc=0 -- handle is not pending.
|
||||
* rc=1 -- handle is pending, other thread is still working with it.
|
||||
* rc=2 -- handle is pending, other thread is done.
|
||||
*/
|
||||
rc = cmpxchgi(&handle->pending, 2, 0);
|
||||
|
||||
if (rc != 1)
|
||||
return rc;
|
||||
|
||||
/* Other thread is busy with this handle, spin until it's done. */
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
/* Yield the CPU. We may have preempted the other thread while it's
|
||||
* inside the critical section and if it's running on the same CPU
|
||||
* as us, we'll just burn CPU cycles until the end of our time slice.
|
||||
*/
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv__async_close(uv_async_t* handle) {
|
||||
uv__async_spin(handle);
|
||||
QUEUE_REMOVE(&handle->queue);
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
|
||||
|
||||
static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
char buf[1024];
|
||||
ssize_t r;
|
||||
QUEUE queue;
|
||||
QUEUE* q;
|
||||
uv_async_t* h;
|
||||
|
||||
assert(w == &loop->async_io_watcher);
|
||||
|
||||
for (;;) {
|
||||
r = read(w->fd, buf, sizeof(buf));
|
||||
|
||||
if (r == sizeof(buf))
|
||||
continue;
|
||||
|
||||
if (r != -1)
|
||||
break;
|
||||
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
break;
|
||||
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
QUEUE_MOVE(&loop->async_handles, &queue);
|
||||
while (!QUEUE_EMPTY(&queue)) {
|
||||
q = QUEUE_HEAD(&queue);
|
||||
h = QUEUE_DATA(q, uv_async_t, queue);
|
||||
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INSERT_TAIL(&loop->async_handles, q);
|
||||
|
||||
if (0 == uv__async_spin(h))
|
||||
continue; /* Not pending. */
|
||||
|
||||
if (h->async_cb == NULL)
|
||||
continue;
|
||||
|
||||
h->async_cb(h);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void uv__async_send(uv_loop_t* loop) {
|
||||
const void* buf;
|
||||
ssize_t len;
|
||||
int fd;
|
||||
int r;
|
||||
|
||||
buf = "";
|
||||
len = 1;
|
||||
fd = loop->async_wfd;
|
||||
|
||||
#if defined(__linux__)
|
||||
if (fd == -1) {
|
||||
static const uint64_t val = 1;
|
||||
buf = &val;
|
||||
len = sizeof(val);
|
||||
fd = loop->async_io_watcher.fd; /* eventfd */
|
||||
}
|
||||
#endif
|
||||
|
||||
do
|
||||
r = write(fd, buf, len);
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r == len)
|
||||
return;
|
||||
|
||||
if (r == -1)
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
return;
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
static int uv__async_start(uv_loop_t* loop) {
|
||||
int pipefd[2];
|
||||
int err;
|
||||
|
||||
if (loop->async_io_watcher.fd != -1)
|
||||
return 0;
|
||||
|
||||
#ifdef __linux__
|
||||
err = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
||||
if (err < 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
pipefd[0] = err;
|
||||
pipefd[1] = -1;
|
||||
#else
|
||||
err = uv__make_pipe(pipefd, UV__F_NONBLOCK);
|
||||
if (err < 0)
|
||||
return err;
|
||||
#endif
|
||||
|
||||
uv__io_init(&loop->async_io_watcher, uv__async_io, pipefd[0]);
|
||||
uv__io_start(loop, &loop->async_io_watcher, POLLIN);
|
||||
loop->async_wfd = pipefd[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__async_fork(uv_loop_t* loop) {
|
||||
if (loop->async_io_watcher.fd == -1) /* never started */
|
||||
return 0;
|
||||
|
||||
uv__async_stop(loop);
|
||||
|
||||
return uv__async_start(loop);
|
||||
}
|
||||
|
||||
|
||||
void uv__async_stop(uv_loop_t* loop) {
|
||||
if (loop->async_io_watcher.fd == -1)
|
||||
return;
|
||||
|
||||
if (loop->async_wfd != -1) {
|
||||
if (loop->async_wfd != loop->async_io_watcher.fd)
|
||||
uv__close(loop->async_wfd);
|
||||
loop->async_wfd = -1;
|
||||
}
|
||||
|
||||
uv__io_stop(loop, &loop->async_io_watcher, POLLIN);
|
||||
uv__close(loop->async_io_watcher.fd);
|
||||
loop->async_io_watcher.fd = -1;
|
||||
}
|
61
deps/libuv/src/unix/atomic-ops.h
vendored
Normal file
61
deps/libuv/src/unix/atomic-ops.h
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_ATOMIC_OPS_H_
|
||||
#define UV_ATOMIC_OPS_H_
|
||||
|
||||
#include "internal.h" /* UV_UNUSED */
|
||||
|
||||
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
||||
#include <atomic.h>
|
||||
#endif
|
||||
|
||||
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
|
||||
UV_UNUSED(static void cpu_relax(void));
|
||||
|
||||
/* Prefer hand-rolled assembly over the gcc builtins because the latter also
|
||||
* issue full memory barriers.
|
||||
*/
|
||||
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
int out;
|
||||
__asm__ __volatile__ ("lock; cmpxchg %2, %1;"
|
||||
: "=a" (out), "+m" (*(volatile int*) ptr)
|
||||
: "r" (newval), "0" (oldval)
|
||||
: "memory");
|
||||
return out;
|
||||
#elif defined(__MVS__)
|
||||
unsigned int op4;
|
||||
if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
|
||||
(unsigned int*) ptr, *ptr, &op4))
|
||||
return oldval;
|
||||
else
|
||||
return op4;
|
||||
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
||||
return atomic_cas_uint((uint_t *)ptr, (uint_t)oldval, (uint_t)newval);
|
||||
#else
|
||||
return __sync_val_compare_and_swap(ptr, oldval, newval);
|
||||
#endif
|
||||
}
|
||||
|
||||
UV_UNUSED(static void cpu_relax(void)) {
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
__asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */
|
||||
#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
|
||||
__asm__ volatile("yield");
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* UV_ATOMIC_OPS_H_ */
|
163
deps/libuv/src/unix/bsd-ifaddrs.c
vendored
Normal file
163
deps/libuv/src/unix/bsd-ifaddrs.c
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
/* 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#if !defined(__CYGWIN__) && !defined(__MSYS__)
|
||||
#include <net/if_dl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__HAIKU__)
|
||||
#define IFF_RUNNING IFF_LINK
|
||||
#endif
|
||||
|
||||
static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
|
||||
return 1;
|
||||
if (ent->ifa_addr == NULL)
|
||||
return 1;
|
||||
#if !defined(__CYGWIN__) && !defined(__MSYS__)
|
||||
/*
|
||||
* If `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family`
|
||||
* equals to `AF_LINK` or not. Otherwise, the result depends on the operation
|
||||
* system with `AF_LINK` or `PF_INET`.
|
||||
*/
|
||||
if (exclude_type == UV__EXCLUDE_IFPHYS)
|
||||
return (ent->ifa_addr->sa_family != AF_LINK);
|
||||
#endif
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) || \
|
||||
defined(__HAIKU__)
|
||||
/*
|
||||
* On BSD getifaddrs returns information related to the raw underlying
|
||||
* devices. We're not interested in this information.
|
||||
*/
|
||||
if (ent->ifa_addr->sa_family == AF_LINK)
|
||||
return 1;
|
||||
#elif defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
if (ent->ifa_addr->sa_family != PF_INET &&
|
||||
ent->ifa_addr->sa_family != PF_INET6)
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
struct ifaddrs* addrs;
|
||||
struct ifaddrs* ent;
|
||||
uv_interface_address_t* address;
|
||||
#if !(defined(__CYGWIN__) || defined(__MSYS__))
|
||||
int i;
|
||||
#endif
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
if (getifaddrs(&addrs) != 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* Count the number of interfaces */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
|
||||
continue;
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
if (*count == 0) {
|
||||
freeifaddrs(addrs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure the memory is initiallized to zero using calloc() */
|
||||
*addresses = uv__calloc(*count, sizeof(**addresses));
|
||||
|
||||
if (*addresses == NULL) {
|
||||
freeifaddrs(addrs);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
address = *addresses;
|
||||
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
|
||||
continue;
|
||||
|
||||
address->name = uv__strdup(ent->ifa_name);
|
||||
|
||||
if (ent->ifa_addr->sa_family == AF_INET6) {
|
||||
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
|
||||
} else {
|
||||
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
|
||||
}
|
||||
|
||||
if (ent->ifa_netmask == NULL) {
|
||||
memset(&address->netmask, 0, sizeof(address->netmask));
|
||||
} else if (ent->ifa_netmask->sa_family == AF_INET6) {
|
||||
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
|
||||
} else {
|
||||
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
|
||||
}
|
||||
|
||||
address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
|
||||
|
||||
address++;
|
||||
}
|
||||
|
||||
#if !(defined(__CYGWIN__) || defined(__MSYS__))
|
||||
/* Fill in physical addresses for each interface */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
|
||||
continue;
|
||||
|
||||
address = *addresses;
|
||||
|
||||
for (i = 0; i < *count; i++) {
|
||||
if (strcmp(address->name, ent->ifa_name) == 0) {
|
||||
struct sockaddr_dl* sa_addr;
|
||||
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
|
||||
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
|
||||
}
|
||||
address++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
freeifaddrs(addrs);
|
||||
|
||||
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);
|
||||
}
|
100
deps/libuv/src/unix/bsd-proctitle.c
vendored
Normal file
100
deps/libuv/src/unix/bsd-proctitle.c
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
/* 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
static uv_mutex_t process_title_mutex;
|
||||
static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
|
||||
static char* process_title;
|
||||
|
||||
|
||||
static void init_process_title_mutex_once(void) {
|
||||
if (uv_mutex_init(&process_title_mutex))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv__process_title_cleanup(void) {
|
||||
/* TODO(bnoordhuis) uv_mutex_destroy(&process_title_mutex)
|
||||
* and reset process_title_mutex_once?
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
process_title = argc > 0 ? uv__strdup(argv[0]) : NULL;
|
||||
return argv;
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
char* new_title;
|
||||
|
||||
new_title = uv__strdup(title);
|
||||
if (new_title == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
uv__free(process_title);
|
||||
process_title = new_title;
|
||||
setproctitle("%s", title);
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (process_title != NULL) {
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len) {
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
1613
deps/libuv/src/unix/core.c
vendored
Normal file
1613
deps/libuv/src/unix/core.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
53
deps/libuv/src/unix/cygwin.c
vendored
Normal file
53
deps/libuv/src/unix/cygwin.c
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
/* 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <sys/sysinfo.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
struct sysinfo info;
|
||||
|
||||
if (sysinfo(&info) < 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
*uptime = info.uptime;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
/* FIXME: read /proc/meminfo? */
|
||||
*rss = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
/* FIXME: read /proc/stat? */
|
||||
*cpu_infos = NULL;
|
||||
*count = 0;
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
192
deps/libuv/src/unix/darwin-proctitle.c
vendored
Normal file
192
deps/libuv/src/unix/darwin-proctitle.c
vendored
Normal file
@ -0,0 +1,192 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
#include "darwin-stub.h"
|
||||
#endif
|
||||
|
||||
|
||||
static int uv__pthread_setname_np(const char* name) {
|
||||
char namebuf[64]; /* MAXTHREADNAMESIZE */
|
||||
int err;
|
||||
|
||||
strncpy(namebuf, name, sizeof(namebuf) - 1);
|
||||
namebuf[sizeof(namebuf) - 1] = '\0';
|
||||
|
||||
err = pthread_setname_np(namebuf);
|
||||
if (err)
|
||||
return UV__ERR(err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__set_process_title(const char* title) {
|
||||
#if TARGET_OS_IPHONE
|
||||
return uv__pthread_setname_np(title);
|
||||
#else
|
||||
CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
|
||||
const char*,
|
||||
CFStringEncoding);
|
||||
CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef);
|
||||
void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef);
|
||||
void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef);
|
||||
CFTypeRef (*pLSGetCurrentApplicationASN)(void);
|
||||
OSStatus (*pLSSetApplicationInformationItem)(int,
|
||||
CFTypeRef,
|
||||
CFStringRef,
|
||||
CFStringRef,
|
||||
CFDictionaryRef*);
|
||||
void* application_services_handle;
|
||||
void* core_foundation_handle;
|
||||
CFBundleRef launch_services_bundle;
|
||||
CFStringRef* display_name_key;
|
||||
CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef);
|
||||
CFBundleRef (*pCFBundleGetMainBundle)(void);
|
||||
CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
|
||||
void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
|
||||
void*);
|
||||
CFTypeRef asn;
|
||||
int err;
|
||||
|
||||
err = UV_ENOENT;
|
||||
application_services_handle = dlopen("/System/Library/Frameworks/"
|
||||
"ApplicationServices.framework/"
|
||||
"Versions/A/ApplicationServices",
|
||||
RTLD_LAZY | RTLD_LOCAL);
|
||||
core_foundation_handle = dlopen("/System/Library/Frameworks/"
|
||||
"CoreFoundation.framework/"
|
||||
"Versions/A/CoreFoundation",
|
||||
RTLD_LAZY | RTLD_LOCAL);
|
||||
|
||||
if (application_services_handle == NULL || core_foundation_handle == NULL)
|
||||
goto out;
|
||||
|
||||
*(void **)(&pCFStringCreateWithCString) =
|
||||
dlsym(core_foundation_handle, "CFStringCreateWithCString");
|
||||
*(void **)(&pCFBundleGetBundleWithIdentifier) =
|
||||
dlsym(core_foundation_handle, "CFBundleGetBundleWithIdentifier");
|
||||
*(void **)(&pCFBundleGetDataPointerForName) =
|
||||
dlsym(core_foundation_handle, "CFBundleGetDataPointerForName");
|
||||
*(void **)(&pCFBundleGetFunctionPointerForName) =
|
||||
dlsym(core_foundation_handle, "CFBundleGetFunctionPointerForName");
|
||||
|
||||
if (pCFStringCreateWithCString == NULL ||
|
||||
pCFBundleGetBundleWithIdentifier == NULL ||
|
||||
pCFBundleGetDataPointerForName == NULL ||
|
||||
pCFBundleGetFunctionPointerForName == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
|
||||
|
||||
launch_services_bundle =
|
||||
pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices"));
|
||||
|
||||
if (launch_services_bundle == NULL)
|
||||
goto out;
|
||||
|
||||
*(void **)(&pLSGetCurrentApplicationASN) =
|
||||
pCFBundleGetFunctionPointerForName(launch_services_bundle,
|
||||
S("_LSGetCurrentApplicationASN"));
|
||||
|
||||
if (pLSGetCurrentApplicationASN == NULL)
|
||||
goto out;
|
||||
|
||||
*(void **)(&pLSSetApplicationInformationItem) =
|
||||
pCFBundleGetFunctionPointerForName(launch_services_bundle,
|
||||
S("_LSSetApplicationInformationItem"));
|
||||
|
||||
if (pLSSetApplicationInformationItem == NULL)
|
||||
goto out;
|
||||
|
||||
display_name_key = pCFBundleGetDataPointerForName(launch_services_bundle,
|
||||
S("_kLSDisplayNameKey"));
|
||||
|
||||
if (display_name_key == NULL || *display_name_key == NULL)
|
||||
goto out;
|
||||
|
||||
*(void **)(&pCFBundleGetInfoDictionary) = dlsym(core_foundation_handle,
|
||||
"CFBundleGetInfoDictionary");
|
||||
*(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle,
|
||||
"CFBundleGetMainBundle");
|
||||
if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL)
|
||||
goto out;
|
||||
|
||||
*(void **)(&pLSApplicationCheckIn) = pCFBundleGetFunctionPointerForName(
|
||||
launch_services_bundle,
|
||||
S("_LSApplicationCheckIn"));
|
||||
|
||||
if (pLSApplicationCheckIn == NULL)
|
||||
goto out;
|
||||
|
||||
*(void **)(&pLSSetApplicationLaunchServicesServerConnectionStatus) =
|
||||
pCFBundleGetFunctionPointerForName(
|
||||
launch_services_bundle,
|
||||
S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
|
||||
|
||||
if (pLSSetApplicationLaunchServicesServerConnectionStatus == NULL)
|
||||
goto out;
|
||||
|
||||
pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
|
||||
|
||||
/* Check into process manager?! */
|
||||
pLSApplicationCheckIn(-2,
|
||||
pCFBundleGetInfoDictionary(pCFBundleGetMainBundle()));
|
||||
|
||||
asn = pLSGetCurrentApplicationASN();
|
||||
|
||||
err = UV_EBUSY;
|
||||
if (asn == NULL)
|
||||
goto out;
|
||||
|
||||
err = UV_EINVAL;
|
||||
if (pLSSetApplicationInformationItem(-2, /* Magic value. */
|
||||
asn,
|
||||
*display_name_key,
|
||||
S(title),
|
||||
NULL) != noErr) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
uv__pthread_setname_np(title); /* Don't care if it fails. */
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
if (core_foundation_handle != NULL)
|
||||
dlclose(core_foundation_handle);
|
||||
|
||||
if (application_services_handle != NULL)
|
||||
dlclose(application_services_handle);
|
||||
|
||||
return err;
|
||||
#endif /* !TARGET_OS_IPHONE */
|
||||
}
|
113
deps/libuv/src/unix/darwin-stub.h
vendored
Normal file
113
deps/libuv/src/unix/darwin-stub.h
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
/* 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_DARWIN_STUB_H_
|
||||
#define UV_DARWIN_STUB_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct CFArrayCallBacks;
|
||||
struct CFRunLoopSourceContext;
|
||||
struct FSEventStreamContext;
|
||||
struct CFRange;
|
||||
|
||||
typedef double CFAbsoluteTime;
|
||||
typedef double CFTimeInterval;
|
||||
typedef int FSEventStreamEventFlags;
|
||||
typedef int OSStatus;
|
||||
typedef long CFIndex;
|
||||
typedef struct CFArrayCallBacks CFArrayCallBacks;
|
||||
typedef struct CFRunLoopSourceContext CFRunLoopSourceContext;
|
||||
typedef struct FSEventStreamContext FSEventStreamContext;
|
||||
typedef uint32_t FSEventStreamCreateFlags;
|
||||
typedef uint64_t FSEventStreamEventId;
|
||||
typedef unsigned CFStringEncoding;
|
||||
typedef void* CFAllocatorRef;
|
||||
typedef void* CFArrayRef;
|
||||
typedef void* CFBundleRef;
|
||||
typedef void* CFDataRef;
|
||||
typedef void* CFDictionaryRef;
|
||||
typedef void* CFMutableDictionaryRef;
|
||||
typedef struct CFRange CFRange;
|
||||
typedef void* CFRunLoopRef;
|
||||
typedef void* CFRunLoopSourceRef;
|
||||
typedef void* CFStringRef;
|
||||
typedef void* CFTypeRef;
|
||||
typedef void* FSEventStreamRef;
|
||||
|
||||
typedef uint32_t IOOptionBits;
|
||||
typedef unsigned int io_iterator_t;
|
||||
typedef unsigned int io_object_t;
|
||||
typedef unsigned int io_service_t;
|
||||
typedef unsigned int io_registry_entry_t;
|
||||
|
||||
|
||||
typedef void (*FSEventStreamCallback)(const FSEventStreamRef,
|
||||
void*,
|
||||
size_t,
|
||||
void*,
|
||||
const FSEventStreamEventFlags*,
|
||||
const FSEventStreamEventId*);
|
||||
|
||||
struct CFRunLoopSourceContext {
|
||||
CFIndex version;
|
||||
void* info;
|
||||
void* pad[7];
|
||||
void (*perform)(void*);
|
||||
};
|
||||
|
||||
struct FSEventStreamContext {
|
||||
CFIndex version;
|
||||
void* info;
|
||||
void* pad[3];
|
||||
};
|
||||
|
||||
struct CFRange {
|
||||
CFIndex location;
|
||||
CFIndex length;
|
||||
};
|
||||
|
||||
static const CFStringEncoding kCFStringEncodingUTF8 = 0x8000100;
|
||||
static const OSStatus noErr = 0;
|
||||
|
||||
static const FSEventStreamEventId kFSEventStreamEventIdSinceNow = -1;
|
||||
|
||||
static const int kFSEventStreamCreateFlagNoDefer = 2;
|
||||
static const int kFSEventStreamCreateFlagFileEvents = 16;
|
||||
|
||||
static const int kFSEventStreamEventFlagEventIdsWrapped = 8;
|
||||
static const int kFSEventStreamEventFlagHistoryDone = 16;
|
||||
static const int kFSEventStreamEventFlagItemChangeOwner = 0x4000;
|
||||
static const int kFSEventStreamEventFlagItemCreated = 0x100;
|
||||
static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x2000;
|
||||
static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x400;
|
||||
static const int kFSEventStreamEventFlagItemIsDir = 0x20000;
|
||||
static const int kFSEventStreamEventFlagItemModified = 0x1000;
|
||||
static const int kFSEventStreamEventFlagItemRemoved = 0x200;
|
||||
static const int kFSEventStreamEventFlagItemRenamed = 0x800;
|
||||
static const int kFSEventStreamEventFlagItemXattrMod = 0x8000;
|
||||
static const int kFSEventStreamEventFlagKernelDropped = 4;
|
||||
static const int kFSEventStreamEventFlagMount = 64;
|
||||
static const int kFSEventStreamEventFlagRootChanged = 32;
|
||||
static const int kFSEventStreamEventFlagUnmount = 128;
|
||||
static const int kFSEventStreamEventFlagUserDropped = 2;
|
||||
|
||||
#endif /* UV_DARWIN_STUB_H_ */
|
371
deps/libuv/src/unix/darwin.c
vendored
Normal file
371
deps/libuv/src/unix/darwin.c
vendored
Normal file
@ -0,0 +1,371 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach-o/dyld.h> /* _NSGetExecutablePath */
|
||||
#include <sys/resource.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <unistd.h> /* sysconf */
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
#include "darwin-stub.h"
|
||||
#endif
|
||||
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
static uint64_t (*time_func)(void);
|
||||
static mach_timebase_info_data_t timebase;
|
||||
|
||||
typedef unsigned char UInt8;
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
loop->cf_state = NULL;
|
||||
|
||||
if (uv__kqueue_init(loop))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
uv__fsevents_loop_delete(loop);
|
||||
}
|
||||
|
||||
|
||||
static void uv__hrtime_init_once(void) {
|
||||
if (KERN_SUCCESS != mach_timebase_info(&timebase))
|
||||
abort();
|
||||
|
||||
time_func = (uint64_t (*)(void)) dlsym(RTLD_DEFAULT, "mach_continuous_time");
|
||||
if (time_func == NULL)
|
||||
time_func = mach_absolute_time;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
uv_once(&once, uv__hrtime_init_once);
|
||||
return time_func() * timebase.numer / timebase.denom;
|
||||
}
|
||||
|
||||
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
/* realpath(exepath) may be > PATH_MAX so double it to be on the safe side. */
|
||||
char abspath[PATH_MAX * 2 + 1];
|
||||
char exepath[PATH_MAX + 1];
|
||||
uint32_t exepath_size;
|
||||
size_t abspath_size;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
exepath_size = sizeof(exepath);
|
||||
if (_NSGetExecutablePath(exepath, &exepath_size))
|
||||
return UV_EIO;
|
||||
|
||||
if (realpath(exepath, abspath) != abspath)
|
||||
return UV__ERR(errno);
|
||||
|
||||
abspath_size = strlen(abspath);
|
||||
if (abspath_size == 0)
|
||||
return UV_EIO;
|
||||
|
||||
*size -= 1;
|
||||
if (*size > abspath_size)
|
||||
*size = abspath_size;
|
||||
|
||||
memcpy(buffer, abspath, *size);
|
||||
buffer[*size] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
vm_statistics_data_t info;
|
||||
mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t);
|
||||
|
||||
if (host_statistics(mach_host_self(), HOST_VM_INFO,
|
||||
(host_info_t)&info, &count) != KERN_SUCCESS) {
|
||||
return UV_EINVAL; /* FIXME(bnoordhuis) Translate error. */
|
||||
}
|
||||
|
||||
return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
uint64_t info;
|
||||
int which[] = {CTL_HW, HW_MEMSIZE};
|
||||
size_t size = sizeof(info);
|
||||
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
struct loadavg info;
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_LOADAVG};
|
||||
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) < 0) return;
|
||||
|
||||
avg[0] = (double) info.ldavg[0] / info.fscale;
|
||||
avg[1] = (double) info.ldavg[1] / info.fscale;
|
||||
avg[2] = (double) info.ldavg[2] / info.fscale;
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
mach_msg_type_number_t count;
|
||||
task_basic_info_data_t info;
|
||||
kern_return_t err;
|
||||
|
||||
count = TASK_BASIC_INFO_COUNT;
|
||||
err = task_info(mach_task_self(),
|
||||
TASK_BASIC_INFO,
|
||||
(task_info_t) &info,
|
||||
&count);
|
||||
(void) &err;
|
||||
/* task_info(TASK_BASIC_INFO) cannot really fail. Anything other than
|
||||
* KERN_SUCCESS implies a libuv bug.
|
||||
*/
|
||||
assert(err == KERN_SUCCESS);
|
||||
*rss = info.resident_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
time_t now;
|
||||
struct timeval info;
|
||||
size_t size = sizeof(info);
|
||||
static int which[] = {CTL_KERN, KERN_BOOTTIME};
|
||||
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
now = time(NULL);
|
||||
*uptime = now - info.tv_sec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uv__get_cpu_speed(uint64_t* speed) {
|
||||
/* IOKit */
|
||||
void (*pIOObjectRelease)(io_object_t);
|
||||
kern_return_t (*pIOMasterPort)(mach_port_t, mach_port_t*);
|
||||
CFMutableDictionaryRef (*pIOServiceMatching)(const char*);
|
||||
kern_return_t (*pIOServiceGetMatchingServices)(mach_port_t,
|
||||
CFMutableDictionaryRef,
|
||||
io_iterator_t*);
|
||||
io_service_t (*pIOIteratorNext)(io_iterator_t);
|
||||
CFTypeRef (*pIORegistryEntryCreateCFProperty)(io_registry_entry_t,
|
||||
CFStringRef,
|
||||
CFAllocatorRef,
|
||||
IOOptionBits);
|
||||
|
||||
/* CoreFoundation */
|
||||
CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
|
||||
const char*,
|
||||
CFStringEncoding);
|
||||
CFStringEncoding (*pCFStringGetSystemEncoding)(void);
|
||||
UInt8 *(*pCFDataGetBytePtr)(CFDataRef);
|
||||
CFIndex (*pCFDataGetLength)(CFDataRef);
|
||||
void (*pCFDataGetBytes)(CFDataRef, CFRange, UInt8*);
|
||||
void (*pCFRelease)(CFTypeRef);
|
||||
|
||||
void* core_foundation_handle;
|
||||
void* iokit_handle;
|
||||
int err;
|
||||
|
||||
kern_return_t kr;
|
||||
mach_port_t mach_port;
|
||||
io_iterator_t it;
|
||||
io_object_t service;
|
||||
|
||||
mach_port = 0;
|
||||
|
||||
err = UV_ENOENT;
|
||||
core_foundation_handle = dlopen("/System/Library/Frameworks/"
|
||||
"CoreFoundation.framework/"
|
||||
"Versions/A/CoreFoundation",
|
||||
RTLD_LAZY | RTLD_LOCAL);
|
||||
iokit_handle = dlopen("/System/Library/Frameworks/IOKit.framework/"
|
||||
"Versions/A/IOKit",
|
||||
RTLD_LAZY | RTLD_LOCAL);
|
||||
|
||||
if (core_foundation_handle == NULL || iokit_handle == NULL)
|
||||
goto out;
|
||||
|
||||
#define V(handle, symbol) \
|
||||
do { \
|
||||
*(void **)(&p ## symbol) = dlsym((handle), #symbol); \
|
||||
if (p ## symbol == NULL) \
|
||||
goto out; \
|
||||
} \
|
||||
while (0)
|
||||
V(iokit_handle, IOMasterPort);
|
||||
V(iokit_handle, IOServiceMatching);
|
||||
V(iokit_handle, IOServiceGetMatchingServices);
|
||||
V(iokit_handle, IOIteratorNext);
|
||||
V(iokit_handle, IOObjectRelease);
|
||||
V(iokit_handle, IORegistryEntryCreateCFProperty);
|
||||
V(core_foundation_handle, CFStringCreateWithCString);
|
||||
V(core_foundation_handle, CFStringGetSystemEncoding);
|
||||
V(core_foundation_handle, CFDataGetBytePtr);
|
||||
V(core_foundation_handle, CFDataGetLength);
|
||||
V(core_foundation_handle, CFDataGetBytes);
|
||||
V(core_foundation_handle, CFRelease);
|
||||
#undef V
|
||||
|
||||
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
|
||||
|
||||
kr = pIOMasterPort(MACH_PORT_NULL, &mach_port);
|
||||
assert(kr == KERN_SUCCESS);
|
||||
CFMutableDictionaryRef classes_to_match
|
||||
= pIOServiceMatching("IOPlatformDevice");
|
||||
kr = pIOServiceGetMatchingServices(mach_port, classes_to_match, &it);
|
||||
assert(kr == KERN_SUCCESS);
|
||||
service = pIOIteratorNext(it);
|
||||
|
||||
CFStringRef device_type_str = S("device_type");
|
||||
CFStringRef clock_frequency_str = S("clock-frequency");
|
||||
|
||||
while (service != 0) {
|
||||
CFDataRef data;
|
||||
data = pIORegistryEntryCreateCFProperty(service,
|
||||
device_type_str,
|
||||
NULL,
|
||||
0);
|
||||
if (data) {
|
||||
const UInt8* raw = pCFDataGetBytePtr(data);
|
||||
if (strncmp((char*)raw, "cpu", 3) == 0 ||
|
||||
strncmp((char*)raw, "processor", 9) == 0) {
|
||||
CFDataRef freq_ref;
|
||||
freq_ref = pIORegistryEntryCreateCFProperty(service,
|
||||
clock_frequency_str,
|
||||
NULL,
|
||||
0);
|
||||
if (freq_ref) {
|
||||
uint32_t freq;
|
||||
CFIndex len = pCFDataGetLength(freq_ref);
|
||||
CFRange range;
|
||||
range.location = 0;
|
||||
range.length = len;
|
||||
|
||||
pCFDataGetBytes(freq_ref, range, (UInt8*)&freq);
|
||||
*speed = freq;
|
||||
pCFRelease(freq_ref);
|
||||
pCFRelease(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pCFRelease(data);
|
||||
}
|
||||
|
||||
service = pIOIteratorNext(it);
|
||||
}
|
||||
|
||||
pIOObjectRelease(it);
|
||||
|
||||
err = 0;
|
||||
out:
|
||||
if (core_foundation_handle != NULL)
|
||||
dlclose(core_foundation_handle);
|
||||
|
||||
if (iokit_handle != NULL)
|
||||
dlclose(iokit_handle);
|
||||
|
||||
mach_port_deallocate(mach_task_self(), mach_port);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
|
||||
multiplier = ((uint64_t)1000L / ticks);
|
||||
char model[512];
|
||||
size_t size;
|
||||
unsigned int i;
|
||||
natural_t numcpus;
|
||||
mach_msg_type_number_t msg_type;
|
||||
processor_cpu_load_info_data_t *info;
|
||||
uv_cpu_info_t* cpu_info;
|
||||
uint64_t cpuspeed;
|
||||
int err;
|
||||
|
||||
size = sizeof(model);
|
||||
if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) &&
|
||||
sysctlbyname("hw.model", &model, &size, NULL, 0)) {
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
err = uv__get_cpu_speed(&cpuspeed);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus,
|
||||
(processor_info_array_t*)&info,
|
||||
&msg_type) != KERN_SUCCESS) {
|
||||
return UV_EINVAL; /* FIXME(bnoordhuis) Translate error. */
|
||||
}
|
||||
|
||||
*cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
|
||||
if (!(*cpu_infos)) {
|
||||
vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
*count = numcpus;
|
||||
|
||||
for (i = 0; i < numcpus; i++) {
|
||||
cpu_info = &(*cpu_infos)[i];
|
||||
|
||||
cpu_info->cpu_times.user = (uint64_t)(info[i].cpu_ticks[0]) * multiplier;
|
||||
cpu_info->cpu_times.nice = (uint64_t)(info[i].cpu_ticks[3]) * multiplier;
|
||||
cpu_info->cpu_times.sys = (uint64_t)(info[i].cpu_ticks[1]) * multiplier;
|
||||
cpu_info->cpu_times.idle = (uint64_t)(info[i].cpu_ticks[2]) * multiplier;
|
||||
cpu_info->cpu_times.irq = 0;
|
||||
|
||||
cpu_info->model = uv__strdup(model);
|
||||
cpu_info->speed = cpuspeed/1000000;
|
||||
}
|
||||
vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
|
||||
|
||||
return 0;
|
||||
}
|
80
deps/libuv/src/unix/dl.c
vendored
Normal file
80
deps/libuv/src/unix/dl.c
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <locale.h>
|
||||
|
||||
static int uv__dlerror(uv_lib_t* lib);
|
||||
|
||||
|
||||
int uv_dlopen(const char* filename, uv_lib_t* lib) {
|
||||
dlerror(); /* Reset error status. */
|
||||
lib->errmsg = NULL;
|
||||
lib->handle = dlopen(filename, RTLD_LAZY);
|
||||
return lib->handle ? 0 : uv__dlerror(lib);
|
||||
}
|
||||
|
||||
|
||||
void uv_dlclose(uv_lib_t* lib) {
|
||||
uv__free(lib->errmsg);
|
||||
lib->errmsg = NULL;
|
||||
|
||||
if (lib->handle) {
|
||||
/* Ignore errors. No good way to signal them without leaking memory. */
|
||||
dlclose(lib->handle);
|
||||
lib->handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
|
||||
dlerror(); /* Reset error status. */
|
||||
*ptr = dlsym(lib->handle, name);
|
||||
return uv__dlerror(lib);
|
||||
}
|
||||
|
||||
|
||||
const char* uv_dlerror(const uv_lib_t* lib) {
|
||||
return lib->errmsg ? lib->errmsg : "no error";
|
||||
}
|
||||
|
||||
|
||||
static int uv__dlerror(uv_lib_t* lib) {
|
||||
const char* errmsg;
|
||||
|
||||
uv__free(lib->errmsg);
|
||||
|
||||
errmsg = dlerror();
|
||||
|
||||
if (errmsg) {
|
||||
lib->errmsg = uv__strdup(errmsg);
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
lib->errmsg = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
282
deps/libuv/src/unix/freebsd.c
vendored
Normal file
282
deps/libuv/src/unix/freebsd.c
vendored
Normal file
@ -0,0 +1,282 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <paths.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <vm/vm_param.h> /* VM_LOADAVG */
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h> /* sysconf */
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef CPUSTATES
|
||||
# define CPUSTATES 5U
|
||||
#endif
|
||||
#ifndef CP_USER
|
||||
# define CP_USER 0
|
||||
# define CP_NICE 1
|
||||
# define CP_SYS 2
|
||||
# define CP_IDLE 3
|
||||
# define CP_INTR 4
|
||||
#endif
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
return uv__kqueue_init(loop);
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
char abspath[PATH_MAX * 2 + 1];
|
||||
int mib[4];
|
||||
size_t abspath_size;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PATHNAME;
|
||||
mib[3] = -1;
|
||||
|
||||
abspath_size = sizeof abspath;
|
||||
if (sysctl(mib, ARRAY_SIZE(mib), abspath, &abspath_size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
assert(abspath_size > 0);
|
||||
abspath_size -= 1;
|
||||
*size -= 1;
|
||||
|
||||
if (*size > abspath_size)
|
||||
*size = abspath_size;
|
||||
|
||||
memcpy(buffer, abspath, *size);
|
||||
buffer[*size] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
int freecount;
|
||||
size_t size = sizeof(freecount);
|
||||
|
||||
if (sysctlbyname("vm.stats.vm.v_free_count", &freecount, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) freecount * sysconf(_SC_PAGESIZE);
|
||||
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
unsigned long info;
|
||||
int which[] = {CTL_HW, HW_PHYSMEM};
|
||||
|
||||
size_t size = sizeof(info);
|
||||
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
struct loadavg info;
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_LOADAVG};
|
||||
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) < 0) return;
|
||||
|
||||
avg[0] = (double) info.ldavg[0] / info.fscale;
|
||||
avg[1] = (double) info.ldavg[1] / info.fscale;
|
||||
avg[2] = (double) info.ldavg[2] / info.fscale;
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
struct kinfo_proc kinfo;
|
||||
size_t page_size;
|
||||
size_t kinfo_size;
|
||||
int mib[4];
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PID;
|
||||
mib[3] = getpid();
|
||||
|
||||
kinfo_size = sizeof(kinfo);
|
||||
|
||||
if (sysctl(mib, ARRAY_SIZE(mib), &kinfo, &kinfo_size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
page_size = getpagesize();
|
||||
|
||||
#ifdef __DragonFly__
|
||||
*rss = kinfo.kp_vm_rssize * page_size;
|
||||
#else
|
||||
*rss = kinfo.ki_rssize * page_size;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
int r;
|
||||
struct timespec sp;
|
||||
r = clock_gettime(CLOCK_MONOTONIC, &sp);
|
||||
if (r)
|
||||
return UV__ERR(errno);
|
||||
|
||||
*uptime = sp.tv_sec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
|
||||
multiplier = ((uint64_t)1000L / ticks), cpuspeed, maxcpus,
|
||||
cur = 0;
|
||||
uv_cpu_info_t* cpu_info;
|
||||
const char* maxcpus_key;
|
||||
const char* cptimes_key;
|
||||
const char* model_key;
|
||||
char model[512];
|
||||
long* cp_times;
|
||||
int numcpus;
|
||||
size_t size;
|
||||
int i;
|
||||
|
||||
#if defined(__DragonFly__)
|
||||
/* This is not quite correct but DragonFlyBSD doesn't seem to have anything
|
||||
* comparable to kern.smp.maxcpus or kern.cp_times (kern.cp_time is a total,
|
||||
* not per CPU). At least this stops uv_cpu_info() from failing completely.
|
||||
*/
|
||||
maxcpus_key = "hw.ncpu";
|
||||
cptimes_key = "kern.cp_time";
|
||||
#else
|
||||
maxcpus_key = "kern.smp.maxcpus";
|
||||
cptimes_key = "kern.cp_times";
|
||||
#endif
|
||||
|
||||
#if defined(__arm__) || defined(__aarch64__)
|
||||
/* The key hw.model and hw.clockrate are not available on FreeBSD ARM. */
|
||||
model_key = "hw.machine";
|
||||
cpuspeed = 0;
|
||||
#else
|
||||
model_key = "hw.model";
|
||||
|
||||
size = sizeof(cpuspeed);
|
||||
if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0))
|
||||
return -errno;
|
||||
#endif
|
||||
|
||||
size = sizeof(model);
|
||||
if (sysctlbyname(model_key, &model, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
size = sizeof(numcpus);
|
||||
if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
*cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
|
||||
if (!(*cpu_infos))
|
||||
return UV_ENOMEM;
|
||||
|
||||
*count = numcpus;
|
||||
|
||||
/* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of
|
||||
* ncpu.
|
||||
*/
|
||||
size = sizeof(maxcpus);
|
||||
if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) {
|
||||
uv__free(*cpu_infos);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
size = maxcpus * CPUSTATES * sizeof(long);
|
||||
|
||||
cp_times = uv__malloc(size);
|
||||
if (cp_times == NULL) {
|
||||
uv__free(*cpu_infos);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) {
|
||||
uv__free(cp_times);
|
||||
uv__free(*cpu_infos);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
for (i = 0; i < numcpus; i++) {
|
||||
cpu_info = &(*cpu_infos)[i];
|
||||
|
||||
cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
|
||||
cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
|
||||
cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
|
||||
cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
|
||||
cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
|
||||
|
||||
cpu_info->model = uv__strdup(model);
|
||||
cpu_info->speed = cpuspeed;
|
||||
|
||||
cur+=CPUSTATES;
|
||||
}
|
||||
|
||||
uv__free(cp_times);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
|
||||
#if __FreeBSD__ >= 11
|
||||
return sendmmsg(fd, mmsg, vlen, /* flags */ 0);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
|
||||
#if __FreeBSD__ >= 11
|
||||
return recvmmsg(fd, mmsg, vlen, 0 /* flags */, NULL /* timeout */);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
2134
deps/libuv/src/unix/fs.c
vendored
Normal file
2134
deps/libuv/src/unix/fs.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
923
deps/libuv/src/unix/fsevents.c
vendored
Normal file
923
deps/libuv/src/unix/fsevents.c
vendored
Normal file
@ -0,0 +1,923 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#if TARGET_OS_IPHONE || MAC_OS_X_VERSION_MAX_ALLOWED < 1070
|
||||
|
||||
/* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */
|
||||
/* macOS prior to 10.7 doesn't provide the full FSEvents API so use kqueue */
|
||||
|
||||
int uv__fsevents_init(uv_fs_event_t* handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__fsevents_close(uv_fs_event_t* handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__fsevents_loop_delete(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
#else /* TARGET_OS_IPHONE */
|
||||
|
||||
#include "darwin-stub.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static const int kFSEventsModified =
|
||||
kFSEventStreamEventFlagItemChangeOwner |
|
||||
kFSEventStreamEventFlagItemFinderInfoMod |
|
||||
kFSEventStreamEventFlagItemInodeMetaMod |
|
||||
kFSEventStreamEventFlagItemModified |
|
||||
kFSEventStreamEventFlagItemXattrMod;
|
||||
|
||||
static const int kFSEventsRenamed =
|
||||
kFSEventStreamEventFlagItemCreated |
|
||||
kFSEventStreamEventFlagItemRemoved |
|
||||
kFSEventStreamEventFlagItemRenamed;
|
||||
|
||||
static const int kFSEventsSystem =
|
||||
kFSEventStreamEventFlagUserDropped |
|
||||
kFSEventStreamEventFlagKernelDropped |
|
||||
kFSEventStreamEventFlagEventIdsWrapped |
|
||||
kFSEventStreamEventFlagHistoryDone |
|
||||
kFSEventStreamEventFlagMount |
|
||||
kFSEventStreamEventFlagUnmount |
|
||||
kFSEventStreamEventFlagRootChanged;
|
||||
|
||||
typedef struct uv__fsevents_event_s uv__fsevents_event_t;
|
||||
typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
|
||||
typedef struct uv__cf_loop_state_s uv__cf_loop_state_t;
|
||||
|
||||
enum uv__cf_loop_signal_type_e {
|
||||
kUVCFLoopSignalRegular,
|
||||
kUVCFLoopSignalClosing
|
||||
};
|
||||
typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t;
|
||||
|
||||
struct uv__cf_loop_signal_s {
|
||||
QUEUE member;
|
||||
uv_fs_event_t* handle;
|
||||
uv__cf_loop_signal_type_t type;
|
||||
};
|
||||
|
||||
struct uv__fsevents_event_s {
|
||||
QUEUE member;
|
||||
int events;
|
||||
char path[1];
|
||||
};
|
||||
|
||||
struct uv__cf_loop_state_s {
|
||||
CFRunLoopRef loop;
|
||||
CFRunLoopSourceRef signal_source;
|
||||
int fsevent_need_reschedule;
|
||||
FSEventStreamRef fsevent_stream;
|
||||
uv_sem_t fsevent_sem;
|
||||
uv_mutex_t fsevent_mutex;
|
||||
void* fsevent_handles[2];
|
||||
unsigned int fsevent_handle_count;
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
static void uv__cf_loop_cb(void* arg);
|
||||
static void* uv__cf_loop_runner(void* arg);
|
||||
static int uv__cf_loop_signal(uv_loop_t* loop,
|
||||
uv_fs_event_t* handle,
|
||||
uv__cf_loop_signal_type_t type);
|
||||
|
||||
/* Lazy-loaded by uv__fsevents_global_init(). */
|
||||
static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef,
|
||||
const void**,
|
||||
CFIndex,
|
||||
const CFArrayCallBacks*);
|
||||
static void (*pCFRelease)(CFTypeRef);
|
||||
static void (*pCFRunLoopAddSource)(CFRunLoopRef,
|
||||
CFRunLoopSourceRef,
|
||||
CFStringRef);
|
||||
static CFRunLoopRef (*pCFRunLoopGetCurrent)(void);
|
||||
static void (*pCFRunLoopRemoveSource)(CFRunLoopRef,
|
||||
CFRunLoopSourceRef,
|
||||
CFStringRef);
|
||||
static void (*pCFRunLoopRun)(void);
|
||||
static CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef,
|
||||
CFIndex,
|
||||
CFRunLoopSourceContext*);
|
||||
static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef);
|
||||
static void (*pCFRunLoopStop)(CFRunLoopRef);
|
||||
static void (*pCFRunLoopWakeUp)(CFRunLoopRef);
|
||||
static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)(
|
||||
CFAllocatorRef,
|
||||
const char*);
|
||||
static CFStringEncoding (*pCFStringGetSystemEncoding)(void);
|
||||
static CFStringRef (*pkCFRunLoopDefaultMode);
|
||||
static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef,
|
||||
FSEventStreamCallback,
|
||||
FSEventStreamContext*,
|
||||
CFArrayRef,
|
||||
FSEventStreamEventId,
|
||||
CFTimeInterval,
|
||||
FSEventStreamCreateFlags);
|
||||
static void (*pFSEventStreamFlushSync)(FSEventStreamRef);
|
||||
static void (*pFSEventStreamInvalidate)(FSEventStreamRef);
|
||||
static void (*pFSEventStreamRelease)(FSEventStreamRef);
|
||||
static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef,
|
||||
CFRunLoopRef,
|
||||
CFStringRef);
|
||||
static int (*pFSEventStreamStart)(FSEventStreamRef);
|
||||
static void (*pFSEventStreamStop)(FSEventStreamRef);
|
||||
|
||||
#define UV__FSEVENTS_PROCESS(handle, block) \
|
||||
do { \
|
||||
QUEUE events; \
|
||||
QUEUE* q; \
|
||||
uv__fsevents_event_t* event; \
|
||||
int err; \
|
||||
uv_mutex_lock(&(handle)->cf_mutex); \
|
||||
/* Split-off all events and empty original queue */ \
|
||||
QUEUE_MOVE(&(handle)->cf_events, &events); \
|
||||
/* Get error (if any) and zero original one */ \
|
||||
err = (handle)->cf_error; \
|
||||
(handle)->cf_error = 0; \
|
||||
uv_mutex_unlock(&(handle)->cf_mutex); \
|
||||
/* Loop through events, deallocating each after processing */ \
|
||||
while (!QUEUE_EMPTY(&events)) { \
|
||||
q = QUEUE_HEAD(&events); \
|
||||
event = QUEUE_DATA(q, uv__fsevents_event_t, member); \
|
||||
QUEUE_REMOVE(q); \
|
||||
/* NOTE: Checking uv__is_active() is required here, because handle \
|
||||
* callback may close handle and invoking it after it will lead to \
|
||||
* incorrect behaviour */ \
|
||||
if (!uv__is_closing((handle)) && uv__is_active((handle))) \
|
||||
block \
|
||||
/* Free allocated data */ \
|
||||
uv__free(event); \
|
||||
} \
|
||||
if (err != 0 && !uv__is_closing((handle)) && uv__is_active((handle))) \
|
||||
(handle)->cb((handle), NULL, 0, err); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Runs in UV loop's thread, when there're events to report to handle */
|
||||
static void uv__fsevents_cb(uv_async_t* cb) {
|
||||
uv_fs_event_t* handle;
|
||||
|
||||
handle = cb->data;
|
||||
|
||||
UV__FSEVENTS_PROCESS(handle, {
|
||||
handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* Runs in CF thread, pushed event into handle's event list */
|
||||
static void uv__fsevents_push_event(uv_fs_event_t* handle,
|
||||
QUEUE* events,
|
||||
int err) {
|
||||
assert(events != NULL || err != 0);
|
||||
uv_mutex_lock(&handle->cf_mutex);
|
||||
|
||||
/* Concatenate two queues */
|
||||
if (events != NULL)
|
||||
QUEUE_ADD(&handle->cf_events, events);
|
||||
|
||||
/* Propagate error */
|
||||
if (err != 0)
|
||||
handle->cf_error = err;
|
||||
uv_mutex_unlock(&handle->cf_mutex);
|
||||
|
||||
uv_async_send(handle->cf_cb);
|
||||
}
|
||||
|
||||
|
||||
/* Runs in CF thread, when there're events in FSEventStream */
|
||||
static void uv__fsevents_event_cb(const FSEventStreamRef streamRef,
|
||||
void* info,
|
||||
size_t numEvents,
|
||||
void* eventPaths,
|
||||
const FSEventStreamEventFlags eventFlags[],
|
||||
const FSEventStreamEventId eventIds[]) {
|
||||
size_t i;
|
||||
int len;
|
||||
char** paths;
|
||||
char* path;
|
||||
char* pos;
|
||||
uv_fs_event_t* handle;
|
||||
QUEUE* q;
|
||||
uv_loop_t* loop;
|
||||
uv__cf_loop_state_t* state;
|
||||
uv__fsevents_event_t* event;
|
||||
FSEventStreamEventFlags flags;
|
||||
QUEUE head;
|
||||
|
||||
loop = info;
|
||||
state = loop->cf_state;
|
||||
assert(state != NULL);
|
||||
paths = eventPaths;
|
||||
|
||||
/* For each handle */
|
||||
uv_mutex_lock(&state->fsevent_mutex);
|
||||
QUEUE_FOREACH(q, &state->fsevent_handles) {
|
||||
handle = QUEUE_DATA(q, uv_fs_event_t, cf_member);
|
||||
QUEUE_INIT(&head);
|
||||
|
||||
/* Process and filter out events */
|
||||
for (i = 0; i < numEvents; i++) {
|
||||
flags = eventFlags[i];
|
||||
|
||||
/* Ignore system events */
|
||||
if (flags & kFSEventsSystem)
|
||||
continue;
|
||||
|
||||
path = paths[i];
|
||||
len = strlen(path);
|
||||
|
||||
if (handle->realpath_len == 0)
|
||||
continue; /* This should be unreachable */
|
||||
|
||||
/* Filter out paths that are outside handle's request */
|
||||
if (len < handle->realpath_len)
|
||||
continue;
|
||||
|
||||
/* Make sure that realpath actually named a directory,
|
||||
* (unless watching root, which alone keeps a trailing slash on the realpath)
|
||||
* or that we matched the whole string */
|
||||
if (handle->realpath_len != len &&
|
||||
handle->realpath_len > 1 &&
|
||||
path[handle->realpath_len] != '/')
|
||||
continue;
|
||||
|
||||
if (memcmp(path, handle->realpath, handle->realpath_len) != 0)
|
||||
continue;
|
||||
|
||||
if (!(handle->realpath_len == 1 && handle->realpath[0] == '/')) {
|
||||
/* Remove common prefix, unless the watched folder is "/" */
|
||||
path += handle->realpath_len;
|
||||
len -= handle->realpath_len;
|
||||
|
||||
/* Ignore events with path equal to directory itself */
|
||||
if (len <= 1 && (flags & kFSEventStreamEventFlagItemIsDir))
|
||||
continue;
|
||||
|
||||
if (len == 0) {
|
||||
/* Since we're using fsevents to watch the file itself,
|
||||
* realpath == path, and we now need to get the basename of the file back
|
||||
* (for commonality with other codepaths and platforms). */
|
||||
while (len < handle->realpath_len && path[-1] != '/') {
|
||||
path--;
|
||||
len++;
|
||||
}
|
||||
/* Created and Removed seem to be always set, but don't make sense */
|
||||
flags &= ~kFSEventsRenamed;
|
||||
} else {
|
||||
/* Skip forward slash */
|
||||
path++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do not emit events from subdirectories (without option set) */
|
||||
if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != '\0') {
|
||||
pos = strchr(path + 1, '/');
|
||||
if (pos != NULL)
|
||||
continue;
|
||||
}
|
||||
|
||||
event = uv__malloc(sizeof(*event) + len);
|
||||
if (event == NULL)
|
||||
break;
|
||||
|
||||
memset(event, 0, sizeof(*event));
|
||||
memcpy(event->path, path, len + 1);
|
||||
event->events = UV_RENAME;
|
||||
|
||||
if (0 == (flags & kFSEventsRenamed)) {
|
||||
if (0 != (flags & kFSEventsModified) ||
|
||||
0 == (flags & kFSEventStreamEventFlagItemIsDir))
|
||||
event->events = UV_CHANGE;
|
||||
}
|
||||
|
||||
QUEUE_INSERT_TAIL(&head, &event->member);
|
||||
}
|
||||
|
||||
if (!QUEUE_EMPTY(&head))
|
||||
uv__fsevents_push_event(handle, &head, 0);
|
||||
}
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
}
|
||||
|
||||
|
||||
/* Runs in CF thread */
|
||||
static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
|
||||
uv__cf_loop_state_t* state;
|
||||
FSEventStreamContext ctx;
|
||||
FSEventStreamRef ref;
|
||||
CFAbsoluteTime latency;
|
||||
FSEventStreamCreateFlags flags;
|
||||
|
||||
/* Initialize context */
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.info = loop;
|
||||
|
||||
latency = 0.05;
|
||||
|
||||
/* Explanation of selected flags:
|
||||
* 1. NoDefer - without this flag, events that are happening continuously
|
||||
* (i.e. each event is happening after time interval less than `latency`,
|
||||
* counted from previous event), will be deferred and passed to callback
|
||||
* once they'll either fill whole OS buffer, or when this continuous stream
|
||||
* will stop (i.e. there'll be delay between events, bigger than
|
||||
* `latency`).
|
||||
* Specifying this flag will invoke callback after `latency` time passed
|
||||
* since event.
|
||||
* 2. FileEvents - fire callback for file changes too (by default it is firing
|
||||
* it only for directory changes).
|
||||
*/
|
||||
flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents;
|
||||
|
||||
/*
|
||||
* NOTE: It might sound like a good idea to remember last seen StreamEventId,
|
||||
* but in reality one dir might have last StreamEventId less than, the other,
|
||||
* that is being watched now. Which will cause FSEventStream API to report
|
||||
* changes to files from the past.
|
||||
*/
|
||||
ref = pFSEventStreamCreate(NULL,
|
||||
&uv__fsevents_event_cb,
|
||||
&ctx,
|
||||
paths,
|
||||
kFSEventStreamEventIdSinceNow,
|
||||
latency,
|
||||
flags);
|
||||
assert(ref != NULL);
|
||||
|
||||
state = loop->cf_state;
|
||||
pFSEventStreamScheduleWithRunLoop(ref,
|
||||
state->loop,
|
||||
*pkCFRunLoopDefaultMode);
|
||||
if (!pFSEventStreamStart(ref)) {
|
||||
pFSEventStreamInvalidate(ref);
|
||||
pFSEventStreamRelease(ref);
|
||||
return UV_EMFILE;
|
||||
}
|
||||
|
||||
state->fsevent_stream = ref;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Runs in CF thread */
|
||||
static void uv__fsevents_destroy_stream(uv_loop_t* loop) {
|
||||
uv__cf_loop_state_t* state;
|
||||
|
||||
state = loop->cf_state;
|
||||
|
||||
if (state->fsevent_stream == NULL)
|
||||
return;
|
||||
|
||||
/* Stop emitting events */
|
||||
pFSEventStreamStop(state->fsevent_stream);
|
||||
|
||||
/* Release stream */
|
||||
pFSEventStreamInvalidate(state->fsevent_stream);
|
||||
pFSEventStreamRelease(state->fsevent_stream);
|
||||
state->fsevent_stream = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Runs in CF thread, when there're new fsevent handles to add to stream */
|
||||
static void uv__fsevents_reschedule(uv_fs_event_t* handle,
|
||||
uv__cf_loop_signal_type_t type) {
|
||||
uv__cf_loop_state_t* state;
|
||||
QUEUE* q;
|
||||
uv_fs_event_t* curr;
|
||||
CFArrayRef cf_paths;
|
||||
CFStringRef* paths;
|
||||
unsigned int i;
|
||||
int err;
|
||||
unsigned int path_count;
|
||||
|
||||
state = handle->loop->cf_state;
|
||||
paths = NULL;
|
||||
cf_paths = NULL;
|
||||
err = 0;
|
||||
/* NOTE: `i` is used in deallocation loop below */
|
||||
i = 0;
|
||||
|
||||
/* Optimization to prevent O(n^2) time spent when starting to watch
|
||||
* many files simultaneously
|
||||
*/
|
||||
uv_mutex_lock(&state->fsevent_mutex);
|
||||
if (state->fsevent_need_reschedule == 0) {
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
goto final;
|
||||
}
|
||||
state->fsevent_need_reschedule = 0;
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
|
||||
/* Destroy previous FSEventStream */
|
||||
uv__fsevents_destroy_stream(handle->loop);
|
||||
|
||||
/* Any failure below will be a memory failure */
|
||||
err = UV_ENOMEM;
|
||||
|
||||
/* Create list of all watched paths */
|
||||
uv_mutex_lock(&state->fsevent_mutex);
|
||||
path_count = state->fsevent_handle_count;
|
||||
if (path_count != 0) {
|
||||
paths = uv__malloc(sizeof(*paths) * path_count);
|
||||
if (paths == NULL) {
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
goto final;
|
||||
}
|
||||
|
||||
q = &state->fsevent_handles;
|
||||
for (; i < path_count; i++) {
|
||||
q = QUEUE_NEXT(q);
|
||||
assert(q != &state->fsevent_handles);
|
||||
curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
|
||||
|
||||
assert(curr->realpath != NULL);
|
||||
paths[i] =
|
||||
pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath);
|
||||
if (paths[i] == NULL) {
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
goto final;
|
||||
}
|
||||
}
|
||||
}
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
err = 0;
|
||||
|
||||
if (path_count != 0) {
|
||||
/* Create new FSEventStream */
|
||||
cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL);
|
||||
if (cf_paths == NULL) {
|
||||
err = UV_ENOMEM;
|
||||
goto final;
|
||||
}
|
||||
err = uv__fsevents_create_stream(handle->loop, cf_paths);
|
||||
}
|
||||
|
||||
final:
|
||||
/* Deallocate all paths in case of failure */
|
||||
if (err != 0) {
|
||||
if (cf_paths == NULL) {
|
||||
while (i != 0)
|
||||
pCFRelease(paths[--i]);
|
||||
uv__free(paths);
|
||||
} else {
|
||||
/* CFArray takes ownership of both strings and original C-array */
|
||||
pCFRelease(cf_paths);
|
||||
}
|
||||
|
||||
/* Broadcast error to all handles */
|
||||
uv_mutex_lock(&state->fsevent_mutex);
|
||||
QUEUE_FOREACH(q, &state->fsevent_handles) {
|
||||
curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
|
||||
uv__fsevents_push_event(curr, NULL, err);
|
||||
}
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main thread will block until the removal of handle from the list,
|
||||
* we must tell it when we're ready.
|
||||
*
|
||||
* NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close`
|
||||
*/
|
||||
if (type == kUVCFLoopSignalClosing)
|
||||
uv_sem_post(&state->fsevent_sem);
|
||||
}
|
||||
|
||||
|
||||
static int uv__fsevents_global_init(void) {
|
||||
static pthread_mutex_t global_init_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static void* core_foundation_handle;
|
||||
static void* core_services_handle;
|
||||
int err;
|
||||
|
||||
err = 0;
|
||||
pthread_mutex_lock(&global_init_mutex);
|
||||
if (core_foundation_handle != NULL)
|
||||
goto out;
|
||||
|
||||
/* The libraries are never unloaded because we currently don't have a good
|
||||
* mechanism for keeping a reference count. It's unlikely to be an issue
|
||||
* but if it ever becomes one, we can turn the dynamic library handles into
|
||||
* per-event loop properties and have the dynamic linker keep track for us.
|
||||
*/
|
||||
err = UV_ENOSYS;
|
||||
core_foundation_handle = dlopen("/System/Library/Frameworks/"
|
||||
"CoreFoundation.framework/"
|
||||
"Versions/A/CoreFoundation",
|
||||
RTLD_LAZY | RTLD_LOCAL);
|
||||
if (core_foundation_handle == NULL)
|
||||
goto out;
|
||||
|
||||
core_services_handle = dlopen("/System/Library/Frameworks/"
|
||||
"CoreServices.framework/"
|
||||
"Versions/A/CoreServices",
|
||||
RTLD_LAZY | RTLD_LOCAL);
|
||||
if (core_services_handle == NULL)
|
||||
goto out;
|
||||
|
||||
err = UV_ENOENT;
|
||||
#define V(handle, symbol) \
|
||||
do { \
|
||||
*(void **)(&p ## symbol) = dlsym((handle), #symbol); \
|
||||
if (p ## symbol == NULL) \
|
||||
goto out; \
|
||||
} \
|
||||
while (0)
|
||||
V(core_foundation_handle, CFArrayCreate);
|
||||
V(core_foundation_handle, CFRelease);
|
||||
V(core_foundation_handle, CFRunLoopAddSource);
|
||||
V(core_foundation_handle, CFRunLoopGetCurrent);
|
||||
V(core_foundation_handle, CFRunLoopRemoveSource);
|
||||
V(core_foundation_handle, CFRunLoopRun);
|
||||
V(core_foundation_handle, CFRunLoopSourceCreate);
|
||||
V(core_foundation_handle, CFRunLoopSourceSignal);
|
||||
V(core_foundation_handle, CFRunLoopStop);
|
||||
V(core_foundation_handle, CFRunLoopWakeUp);
|
||||
V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation);
|
||||
V(core_foundation_handle, CFStringGetSystemEncoding);
|
||||
V(core_foundation_handle, kCFRunLoopDefaultMode);
|
||||
V(core_services_handle, FSEventStreamCreate);
|
||||
V(core_services_handle, FSEventStreamFlushSync);
|
||||
V(core_services_handle, FSEventStreamInvalidate);
|
||||
V(core_services_handle, FSEventStreamRelease);
|
||||
V(core_services_handle, FSEventStreamScheduleWithRunLoop);
|
||||
V(core_services_handle, FSEventStreamStart);
|
||||
V(core_services_handle, FSEventStreamStop);
|
||||
#undef V
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
if (err && core_services_handle != NULL) {
|
||||
dlclose(core_services_handle);
|
||||
core_services_handle = NULL;
|
||||
}
|
||||
|
||||
if (err && core_foundation_handle != NULL) {
|
||||
dlclose(core_foundation_handle);
|
||||
core_foundation_handle = NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&global_init_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Runs in UV loop */
|
||||
static int uv__fsevents_loop_init(uv_loop_t* loop) {
|
||||
CFRunLoopSourceContext ctx;
|
||||
uv__cf_loop_state_t* state;
|
||||
pthread_attr_t attr_storage;
|
||||
pthread_attr_t* attr;
|
||||
int err;
|
||||
|
||||
if (loop->cf_state != NULL)
|
||||
return 0;
|
||||
|
||||
err = uv__fsevents_global_init();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
state = uv__calloc(1, sizeof(*state));
|
||||
if (state == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
err = uv_mutex_init(&loop->cf_mutex);
|
||||
if (err)
|
||||
goto fail_mutex_init;
|
||||
|
||||
err = uv_sem_init(&loop->cf_sem, 0);
|
||||
if (err)
|
||||
goto fail_sem_init;
|
||||
|
||||
QUEUE_INIT(&loop->cf_signals);
|
||||
|
||||
err = uv_sem_init(&state->fsevent_sem, 0);
|
||||
if (err)
|
||||
goto fail_fsevent_sem_init;
|
||||
|
||||
err = uv_mutex_init(&state->fsevent_mutex);
|
||||
if (err)
|
||||
goto fail_fsevent_mutex_init;
|
||||
|
||||
QUEUE_INIT(&state->fsevent_handles);
|
||||
state->fsevent_need_reschedule = 0;
|
||||
state->fsevent_handle_count = 0;
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.info = loop;
|
||||
ctx.perform = uv__cf_loop_cb;
|
||||
state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx);
|
||||
if (state->signal_source == NULL) {
|
||||
err = UV_ENOMEM;
|
||||
goto fail_signal_source_create;
|
||||
}
|
||||
|
||||
/* In the unlikely event that pthread_attr_init() fails, create the thread
|
||||
* with the default stack size. We'll use a little more address space but
|
||||
* that in itself is not a fatal error.
|
||||
*/
|
||||
attr = &attr_storage;
|
||||
if (pthread_attr_init(attr))
|
||||
attr = NULL;
|
||||
|
||||
if (attr != NULL)
|
||||
if (pthread_attr_setstacksize(attr, 4 * PTHREAD_STACK_MIN))
|
||||
abort();
|
||||
|
||||
loop->cf_state = state;
|
||||
|
||||
/* uv_thread_t is an alias for pthread_t. */
|
||||
err = UV__ERR(pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop));
|
||||
|
||||
if (attr != NULL)
|
||||
pthread_attr_destroy(attr);
|
||||
|
||||
if (err)
|
||||
goto fail_thread_create;
|
||||
|
||||
/* Synchronize threads */
|
||||
uv_sem_wait(&loop->cf_sem);
|
||||
return 0;
|
||||
|
||||
fail_thread_create:
|
||||
loop->cf_state = NULL;
|
||||
|
||||
fail_signal_source_create:
|
||||
uv_mutex_destroy(&state->fsevent_mutex);
|
||||
|
||||
fail_fsevent_mutex_init:
|
||||
uv_sem_destroy(&state->fsevent_sem);
|
||||
|
||||
fail_fsevent_sem_init:
|
||||
uv_sem_destroy(&loop->cf_sem);
|
||||
|
||||
fail_sem_init:
|
||||
uv_mutex_destroy(&loop->cf_mutex);
|
||||
|
||||
fail_mutex_init:
|
||||
uv__free(state);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Runs in UV loop */
|
||||
void uv__fsevents_loop_delete(uv_loop_t* loop) {
|
||||
uv__cf_loop_signal_t* s;
|
||||
uv__cf_loop_state_t* state;
|
||||
QUEUE* q;
|
||||
|
||||
if (loop->cf_state == NULL)
|
||||
return;
|
||||
|
||||
if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0)
|
||||
abort();
|
||||
|
||||
uv_thread_join(&loop->cf_thread);
|
||||
uv_sem_destroy(&loop->cf_sem);
|
||||
uv_mutex_destroy(&loop->cf_mutex);
|
||||
|
||||
/* Free any remaining data */
|
||||
while (!QUEUE_EMPTY(&loop->cf_signals)) {
|
||||
q = QUEUE_HEAD(&loop->cf_signals);
|
||||
s = QUEUE_DATA(q, uv__cf_loop_signal_t, member);
|
||||
QUEUE_REMOVE(q);
|
||||
uv__free(s);
|
||||
}
|
||||
|
||||
/* Destroy state */
|
||||
state = loop->cf_state;
|
||||
uv_sem_destroy(&state->fsevent_sem);
|
||||
uv_mutex_destroy(&state->fsevent_mutex);
|
||||
pCFRelease(state->signal_source);
|
||||
uv__free(state);
|
||||
loop->cf_state = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Runs in CF thread. This is the CF loop's body */
|
||||
static void* uv__cf_loop_runner(void* arg) {
|
||||
uv_loop_t* loop;
|
||||
uv__cf_loop_state_t* state;
|
||||
|
||||
loop = arg;
|
||||
state = loop->cf_state;
|
||||
state->loop = pCFRunLoopGetCurrent();
|
||||
|
||||
pCFRunLoopAddSource(state->loop,
|
||||
state->signal_source,
|
||||
*pkCFRunLoopDefaultMode);
|
||||
|
||||
uv_sem_post(&loop->cf_sem);
|
||||
|
||||
pCFRunLoopRun();
|
||||
pCFRunLoopRemoveSource(state->loop,
|
||||
state->signal_source,
|
||||
*pkCFRunLoopDefaultMode);
|
||||
|
||||
state->loop = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Runs in CF thread, executed after `uv__cf_loop_signal()` */
|
||||
static void uv__cf_loop_cb(void* arg) {
|
||||
uv_loop_t* loop;
|
||||
uv__cf_loop_state_t* state;
|
||||
QUEUE* item;
|
||||
QUEUE split_head;
|
||||
uv__cf_loop_signal_t* s;
|
||||
|
||||
loop = arg;
|
||||
state = loop->cf_state;
|
||||
|
||||
uv_mutex_lock(&loop->cf_mutex);
|
||||
QUEUE_MOVE(&loop->cf_signals, &split_head);
|
||||
uv_mutex_unlock(&loop->cf_mutex);
|
||||
|
||||
while (!QUEUE_EMPTY(&split_head)) {
|
||||
item = QUEUE_HEAD(&split_head);
|
||||
QUEUE_REMOVE(item);
|
||||
|
||||
s = QUEUE_DATA(item, uv__cf_loop_signal_t, member);
|
||||
|
||||
/* This was a termination signal */
|
||||
if (s->handle == NULL)
|
||||
pCFRunLoopStop(state->loop);
|
||||
else
|
||||
uv__fsevents_reschedule(s->handle, s->type);
|
||||
|
||||
uv__free(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Runs in UV loop to notify CF thread */
|
||||
int uv__cf_loop_signal(uv_loop_t* loop,
|
||||
uv_fs_event_t* handle,
|
||||
uv__cf_loop_signal_type_t type) {
|
||||
uv__cf_loop_signal_t* item;
|
||||
uv__cf_loop_state_t* state;
|
||||
|
||||
item = uv__malloc(sizeof(*item));
|
||||
if (item == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
item->handle = handle;
|
||||
item->type = type;
|
||||
|
||||
uv_mutex_lock(&loop->cf_mutex);
|
||||
QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member);
|
||||
|
||||
state = loop->cf_state;
|
||||
assert(state != NULL);
|
||||
pCFRunLoopSourceSignal(state->signal_source);
|
||||
pCFRunLoopWakeUp(state->loop);
|
||||
|
||||
uv_mutex_unlock(&loop->cf_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Runs in UV loop to initialize handle */
|
||||
int uv__fsevents_init(uv_fs_event_t* handle) {
|
||||
int err;
|
||||
uv__cf_loop_state_t* state;
|
||||
|
||||
err = uv__fsevents_loop_init(handle->loop);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Get absolute path to file */
|
||||
handle->realpath = realpath(handle->path, NULL);
|
||||
if (handle->realpath == NULL)
|
||||
return UV__ERR(errno);
|
||||
handle->realpath_len = strlen(handle->realpath);
|
||||
|
||||
/* Initialize event queue */
|
||||
QUEUE_INIT(&handle->cf_events);
|
||||
handle->cf_error = 0;
|
||||
|
||||
/*
|
||||
* Events will occur in other thread.
|
||||
* Initialize callback for getting them back into event loop's thread
|
||||
*/
|
||||
handle->cf_cb = uv__malloc(sizeof(*handle->cf_cb));
|
||||
if (handle->cf_cb == NULL) {
|
||||
err = UV_ENOMEM;
|
||||
goto fail_cf_cb_malloc;
|
||||
}
|
||||
|
||||
handle->cf_cb->data = handle;
|
||||
uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb);
|
||||
handle->cf_cb->flags |= UV_HANDLE_INTERNAL;
|
||||
uv_unref((uv_handle_t*) handle->cf_cb);
|
||||
|
||||
err = uv_mutex_init(&handle->cf_mutex);
|
||||
if (err)
|
||||
goto fail_cf_mutex_init;
|
||||
|
||||
/* Insert handle into the list */
|
||||
state = handle->loop->cf_state;
|
||||
uv_mutex_lock(&state->fsevent_mutex);
|
||||
QUEUE_INSERT_TAIL(&state->fsevent_handles, &handle->cf_member);
|
||||
state->fsevent_handle_count++;
|
||||
state->fsevent_need_reschedule = 1;
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
|
||||
/* Reschedule FSEventStream */
|
||||
assert(handle != NULL);
|
||||
err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular);
|
||||
if (err)
|
||||
goto fail_loop_signal;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_loop_signal:
|
||||
uv_mutex_destroy(&handle->cf_mutex);
|
||||
|
||||
fail_cf_mutex_init:
|
||||
uv__free(handle->cf_cb);
|
||||
handle->cf_cb = NULL;
|
||||
|
||||
fail_cf_cb_malloc:
|
||||
uv__free(handle->realpath);
|
||||
handle->realpath = NULL;
|
||||
handle->realpath_len = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Runs in UV loop to de-initialize handle */
|
||||
int uv__fsevents_close(uv_fs_event_t* handle) {
|
||||
int err;
|
||||
uv__cf_loop_state_t* state;
|
||||
|
||||
if (handle->cf_cb == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Remove handle from the list */
|
||||
state = handle->loop->cf_state;
|
||||
uv_mutex_lock(&state->fsevent_mutex);
|
||||
QUEUE_REMOVE(&handle->cf_member);
|
||||
state->fsevent_handle_count--;
|
||||
state->fsevent_need_reschedule = 1;
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
|
||||
/* Reschedule FSEventStream */
|
||||
assert(handle != NULL);
|
||||
err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing);
|
||||
if (err)
|
||||
return UV__ERR(err);
|
||||
|
||||
/* Wait for deinitialization */
|
||||
uv_sem_wait(&state->fsevent_sem);
|
||||
|
||||
uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) uv__free);
|
||||
handle->cf_cb = NULL;
|
||||
|
||||
/* Free data in queue */
|
||||
UV__FSEVENTS_PROCESS(handle, {
|
||||
/* NOP */
|
||||
});
|
||||
|
||||
uv_mutex_destroy(&handle->cf_mutex);
|
||||
uv__free(handle->realpath);
|
||||
handle->realpath = NULL;
|
||||
handle->realpath_len = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* TARGET_OS_IPHONE */
|
255
deps/libuv/src/unix/getaddrinfo.c
vendored
Normal file
255
deps/libuv/src/unix/getaddrinfo.c
vendored
Normal file
@ -0,0 +1,255 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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.
|
||||
*/
|
||||
|
||||
/* Expose glibc-specific EAI_* error codes. Needs to be defined before we
|
||||
* include any headers.
|
||||
*/
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "idna.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h> /* NULL */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <net/if.h> /* if_indextoname() */
|
||||
|
||||
/* EAI_* constants. */
|
||||
#include <netdb.h>
|
||||
|
||||
|
||||
int uv__getaddrinfo_translate_error(int sys_err) {
|
||||
switch (sys_err) {
|
||||
case 0: return 0;
|
||||
#if defined(EAI_ADDRFAMILY)
|
||||
case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY;
|
||||
#endif
|
||||
#if defined(EAI_AGAIN)
|
||||
case EAI_AGAIN: return UV_EAI_AGAIN;
|
||||
#endif
|
||||
#if defined(EAI_BADFLAGS)
|
||||
case EAI_BADFLAGS: return UV_EAI_BADFLAGS;
|
||||
#endif
|
||||
#if defined(EAI_BADHINTS)
|
||||
case EAI_BADHINTS: return UV_EAI_BADHINTS;
|
||||
#endif
|
||||
#if defined(EAI_CANCELED)
|
||||
case EAI_CANCELED: return UV_EAI_CANCELED;
|
||||
#endif
|
||||
#if defined(EAI_FAIL)
|
||||
case EAI_FAIL: return UV_EAI_FAIL;
|
||||
#endif
|
||||
#if defined(EAI_FAMILY)
|
||||
case EAI_FAMILY: return UV_EAI_FAMILY;
|
||||
#endif
|
||||
#if defined(EAI_MEMORY)
|
||||
case EAI_MEMORY: return UV_EAI_MEMORY;
|
||||
#endif
|
||||
#if defined(EAI_NODATA)
|
||||
case EAI_NODATA: return UV_EAI_NODATA;
|
||||
#endif
|
||||
#if defined(EAI_NONAME)
|
||||
# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME
|
||||
case EAI_NONAME: return UV_EAI_NONAME;
|
||||
# endif
|
||||
#endif
|
||||
#if defined(EAI_OVERFLOW)
|
||||
case EAI_OVERFLOW: return UV_EAI_OVERFLOW;
|
||||
#endif
|
||||
#if defined(EAI_PROTOCOL)
|
||||
case EAI_PROTOCOL: return UV_EAI_PROTOCOL;
|
||||
#endif
|
||||
#if defined(EAI_SERVICE)
|
||||
case EAI_SERVICE: return UV_EAI_SERVICE;
|
||||
#endif
|
||||
#if defined(EAI_SOCKTYPE)
|
||||
case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE;
|
||||
#endif
|
||||
#if defined(EAI_SYSTEM)
|
||||
case EAI_SYSTEM: return UV__ERR(errno);
|
||||
#endif
|
||||
}
|
||||
assert(!"unknown EAI_* error code");
|
||||
abort();
|
||||
#ifndef __SUNPRO_C
|
||||
return 0; /* Pacify compiler. */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void uv__getaddrinfo_work(struct uv__work* w) {
|
||||
uv_getaddrinfo_t* req;
|
||||
int err;
|
||||
|
||||
req = container_of(w, uv_getaddrinfo_t, work_req);
|
||||
err = getaddrinfo(req->hostname, req->service, req->hints, &req->addrinfo);
|
||||
req->retcode = uv__getaddrinfo_translate_error(err);
|
||||
}
|
||||
|
||||
|
||||
static void uv__getaddrinfo_done(struct uv__work* w, int status) {
|
||||
uv_getaddrinfo_t* req;
|
||||
|
||||
req = container_of(w, uv_getaddrinfo_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
|
||||
/* See initialization in uv_getaddrinfo(). */
|
||||
if (req->hints)
|
||||
uv__free(req->hints);
|
||||
else if (req->service)
|
||||
uv__free(req->service);
|
||||
else if (req->hostname)
|
||||
uv__free(req->hostname);
|
||||
else
|
||||
assert(0);
|
||||
|
||||
req->hints = NULL;
|
||||
req->service = NULL;
|
||||
req->hostname = NULL;
|
||||
|
||||
if (status == UV_ECANCELED) {
|
||||
assert(req->retcode == 0);
|
||||
req->retcode = UV_EAI_CANCELED;
|
||||
}
|
||||
|
||||
if (req->cb)
|
||||
req->cb(req, req->retcode, req->addrinfo);
|
||||
}
|
||||
|
||||
|
||||
int uv_getaddrinfo(uv_loop_t* loop,
|
||||
uv_getaddrinfo_t* req,
|
||||
uv_getaddrinfo_cb cb,
|
||||
const char* hostname,
|
||||
const char* service,
|
||||
const struct addrinfo* hints) {
|
||||
char hostname_ascii[256];
|
||||
size_t hostname_len;
|
||||
size_t service_len;
|
||||
size_t hints_len;
|
||||
size_t len;
|
||||
char* buf;
|
||||
long rc;
|
||||
|
||||
if (req == NULL || (hostname == NULL && service == NULL))
|
||||
return UV_EINVAL;
|
||||
|
||||
/* FIXME(bnoordhuis) IDNA does not seem to work z/OS,
|
||||
* probably because it uses EBCDIC rather than ASCII.
|
||||
*/
|
||||
#ifdef __MVS__
|
||||
(void) &hostname_ascii;
|
||||
#else
|
||||
if (hostname != NULL) {
|
||||
rc = uv__idna_toascii(hostname,
|
||||
hostname + strlen(hostname),
|
||||
hostname_ascii,
|
||||
hostname_ascii + sizeof(hostname_ascii));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
hostname = hostname_ascii;
|
||||
}
|
||||
#endif
|
||||
|
||||
hostname_len = hostname ? strlen(hostname) + 1 : 0;
|
||||
service_len = service ? strlen(service) + 1 : 0;
|
||||
hints_len = hints ? sizeof(*hints) : 0;
|
||||
buf = uv__malloc(hostname_len + service_len + hints_len);
|
||||
|
||||
if (buf == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
uv__req_init(loop, req, UV_GETADDRINFO);
|
||||
req->loop = loop;
|
||||
req->cb = cb;
|
||||
req->addrinfo = NULL;
|
||||
req->hints = NULL;
|
||||
req->service = NULL;
|
||||
req->hostname = NULL;
|
||||
req->retcode = 0;
|
||||
|
||||
/* order matters, see uv_getaddrinfo_done() */
|
||||
len = 0;
|
||||
|
||||
if (hints) {
|
||||
req->hints = memcpy(buf + len, hints, sizeof(*hints));
|
||||
len += sizeof(*hints);
|
||||
}
|
||||
|
||||
if (service) {
|
||||
req->service = memcpy(buf + len, service, service_len);
|
||||
len += service_len;
|
||||
}
|
||||
|
||||
if (hostname)
|
||||
req->hostname = memcpy(buf + len, hostname, hostname_len);
|
||||
|
||||
if (cb) {
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
UV__WORK_SLOW_IO,
|
||||
uv__getaddrinfo_work,
|
||||
uv__getaddrinfo_done);
|
||||
return 0;
|
||||
} else {
|
||||
uv__getaddrinfo_work(&req->work_req);
|
||||
uv__getaddrinfo_done(&req->work_req, 0);
|
||||
return req->retcode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_freeaddrinfo(struct addrinfo* ai) {
|
||||
if (ai)
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
|
||||
|
||||
int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
|
||||
char ifname_buf[UV_IF_NAMESIZE];
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (if_indextoname(ifindex, ifname_buf) == NULL)
|
||||
return UV__ERR(errno);
|
||||
|
||||
len = strnlen(ifname_buf, sizeof(ifname_buf));
|
||||
|
||||
if (*size <= len) {
|
||||
*size = len + 1;
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, ifname_buf, len);
|
||||
buffer[len] = '\0';
|
||||
*size = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
|
||||
return uv_if_indextoname(ifindex, buffer, size);
|
||||
}
|
121
deps/libuv/src/unix/getnameinfo.c
vendored
Normal file
121
deps/libuv/src/unix/getnameinfo.c
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
static void uv__getnameinfo_work(struct uv__work* w) {
|
||||
uv_getnameinfo_t* req;
|
||||
int err;
|
||||
socklen_t salen;
|
||||
|
||||
req = container_of(w, uv_getnameinfo_t, work_req);
|
||||
|
||||
if (req->storage.ss_family == AF_INET)
|
||||
salen = sizeof(struct sockaddr_in);
|
||||
else if (req->storage.ss_family == AF_INET6)
|
||||
salen = sizeof(struct sockaddr_in6);
|
||||
else
|
||||
abort();
|
||||
|
||||
err = getnameinfo((struct sockaddr*) &req->storage,
|
||||
salen,
|
||||
req->host,
|
||||
sizeof(req->host),
|
||||
req->service,
|
||||
sizeof(req->service),
|
||||
req->flags);
|
||||
req->retcode = uv__getaddrinfo_translate_error(err);
|
||||
}
|
||||
|
||||
static void uv__getnameinfo_done(struct uv__work* w, int status) {
|
||||
uv_getnameinfo_t* req;
|
||||
char* host;
|
||||
char* service;
|
||||
|
||||
req = container_of(w, uv_getnameinfo_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
host = service = NULL;
|
||||
|
||||
if (status == UV_ECANCELED) {
|
||||
assert(req->retcode == 0);
|
||||
req->retcode = UV_EAI_CANCELED;
|
||||
} else if (req->retcode == 0) {
|
||||
host = req->host;
|
||||
service = req->service;
|
||||
}
|
||||
|
||||
if (req->getnameinfo_cb)
|
||||
req->getnameinfo_cb(req, req->retcode, host, service);
|
||||
}
|
||||
|
||||
/*
|
||||
* Entry point for getnameinfo
|
||||
* return 0 if a callback will be made
|
||||
* return error code if validation fails
|
||||
*/
|
||||
int uv_getnameinfo(uv_loop_t* loop,
|
||||
uv_getnameinfo_t* req,
|
||||
uv_getnameinfo_cb getnameinfo_cb,
|
||||
const struct sockaddr* addr,
|
||||
int flags) {
|
||||
if (req == NULL || addr == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (addr->sa_family == AF_INET) {
|
||||
memcpy(&req->storage,
|
||||
addr,
|
||||
sizeof(struct sockaddr_in));
|
||||
} else if (addr->sa_family == AF_INET6) {
|
||||
memcpy(&req->storage,
|
||||
addr,
|
||||
sizeof(struct sockaddr_in6));
|
||||
} else {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
uv__req_init(loop, (uv_req_t*)req, UV_GETNAMEINFO);
|
||||
|
||||
req->getnameinfo_cb = getnameinfo_cb;
|
||||
req->flags = flags;
|
||||
req->type = UV_GETNAMEINFO;
|
||||
req->loop = loop;
|
||||
req->retcode = 0;
|
||||
|
||||
if (getnameinfo_cb) {
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
UV__WORK_SLOW_IO,
|
||||
uv__getnameinfo_work,
|
||||
uv__getnameinfo_done);
|
||||
return 0;
|
||||
} else {
|
||||
uv__getnameinfo_work(&req->work_req);
|
||||
uv__getnameinfo_done(&req->work_req, 0);
|
||||
return req->retcode;
|
||||
}
|
||||
}
|
167
deps/libuv/src/unix/haiku.c
vendored
Normal file
167
deps/libuv/src/unix/haiku.c
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
/* 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <FindDirectory.h> /* find_path() */
|
||||
#include <OS.h>
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
avg[0] = 0;
|
||||
avg[1] = 0;
|
||||
avg[2] = 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
char abspath[B_PATH_NAME_LENGTH];
|
||||
status_t status;
|
||||
ssize_t abspath_len;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
status = find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, NULL, abspath,
|
||||
sizeof(abspath));
|
||||
if (status != B_OK)
|
||||
return UV__ERR(status);
|
||||
|
||||
abspath_len = uv__strscpy(buffer, abspath, *size);
|
||||
*size -= 1;
|
||||
if (abspath_len >= 0 && *size > (size_t)abspath_len)
|
||||
*size = (size_t)abspath_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
status_t status;
|
||||
system_info sinfo;
|
||||
|
||||
status = get_system_info(&sinfo);
|
||||
if (status != B_OK)
|
||||
return 0;
|
||||
|
||||
return (sinfo.max_pages - sinfo.used_pages) * B_PAGE_SIZE;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
status_t status;
|
||||
system_info sinfo;
|
||||
|
||||
status = get_system_info(&sinfo);
|
||||
if (status != B_OK)
|
||||
return 0;
|
||||
|
||||
return sinfo.max_pages * B_PAGE_SIZE;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
area_info area;
|
||||
ssize_t cookie;
|
||||
status_t status;
|
||||
thread_info thread;
|
||||
|
||||
status = get_thread_info(find_thread(NULL), &thread);
|
||||
if (status != B_OK)
|
||||
return UV__ERR(status);
|
||||
|
||||
cookie = 0;
|
||||
*rss = 0;
|
||||
while (get_next_area_info(thread.team, &cookie, &area) == B_OK)
|
||||
*rss += area.ram_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
/* system_time() returns time since booting in microseconds */
|
||||
*uptime = (double)system_time() / 1000000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
cpu_topology_node_info* topology_infos;
|
||||
int i;
|
||||
status_t status;
|
||||
system_info system;
|
||||
uint32_t topology_count;
|
||||
uint64_t cpuspeed;
|
||||
uv_cpu_info_t* cpu_info;
|
||||
|
||||
if (cpu_infos == NULL || count == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
status = get_cpu_topology_info(NULL, &topology_count);
|
||||
if (status != B_OK)
|
||||
return UV__ERR(status);
|
||||
|
||||
topology_infos = uv__malloc(topology_count * sizeof(*topology_infos));
|
||||
if (topology_infos == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
status = get_cpu_topology_info(topology_infos, &topology_count);
|
||||
if (status != B_OK) {
|
||||
uv__free(topology_infos);
|
||||
return UV__ERR(status);
|
||||
}
|
||||
|
||||
cpuspeed = 0;
|
||||
for (i = 0; i < (int)topology_count; i++) {
|
||||
if (topology_infos[i].type == B_TOPOLOGY_CORE) {
|
||||
cpuspeed = topology_infos[i].data.core.default_frequency;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uv__free(topology_infos);
|
||||
|
||||
status = get_system_info(&system);
|
||||
if (status != B_OK)
|
||||
return UV__ERR(status);
|
||||
|
||||
*cpu_infos = uv__calloc(system.cpu_count, sizeof(**cpu_infos));
|
||||
if (*cpu_infos == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
/* CPU time and model are not exposed by Haiku. */
|
||||
cpu_info = *cpu_infos;
|
||||
for (i = 0; i < (int)system.cpu_count; i++) {
|
||||
cpu_info->model = uv__strdup("unknown");
|
||||
cpu_info->speed = (int)(cpuspeed / 1000000);
|
||||
cpu_info++;
|
||||
}
|
||||
*count = system.cpu_count;
|
||||
|
||||
return 0;
|
||||
}
|
501
deps/libuv/src/unix/ibmi.c
vendored
Normal file
501
deps/libuv/src/unix/ibmi.c
vendored
Normal file
@ -0,0 +1,501 @@
|
||||
/* 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <utmp.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include <sys/protosw.h>
|
||||
#include <procinfo.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/procfs.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <sys/mntctl.h>
|
||||
#include <sys/vmount.h>
|
||||
#include <limits.h>
|
||||
#include <strings.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <as400_protos.h>
|
||||
#include <as400_types.h>
|
||||
|
||||
char* original_exepath = NULL;
|
||||
uv_mutex_t process_title_mutex;
|
||||
uv_once_t process_title_mutex_once = UV_ONCE_INIT;
|
||||
|
||||
typedef struct {
|
||||
int bytes_available;
|
||||
int bytes_returned;
|
||||
char current_date_and_time[8];
|
||||
char system_name[8];
|
||||
char elapsed_time[6];
|
||||
char restricted_state_flag;
|
||||
char reserved;
|
||||
int percent_processing_unit_used;
|
||||
int jobs_in_system;
|
||||
int percent_permanent_addresses;
|
||||
int percent_temporary_addresses;
|
||||
int system_asp;
|
||||
int percent_system_asp_used;
|
||||
int total_auxiliary_storage;
|
||||
int current_unprotected_storage_used;
|
||||
int maximum_unprotected_storage_used;
|
||||
int percent_db_capability;
|
||||
int main_storage_size;
|
||||
int number_of_partitions;
|
||||
int partition_identifier;
|
||||
int reserved1;
|
||||
int current_processing_capacity;
|
||||
char processor_sharing_attribute;
|
||||
char reserved2[3];
|
||||
int number_of_processors;
|
||||
int active_jobs_in_system;
|
||||
int active_threads_in_system;
|
||||
int maximum_jobs_in_system;
|
||||
int percent_temporary_256mb_segments_used;
|
||||
int percent_temporary_4gb_segments_used;
|
||||
int percent_permanent_256mb_segments_used;
|
||||
int percent_permanent_4gb_segments_used;
|
||||
int percent_current_interactive_performance;
|
||||
int percent_uncapped_cpu_capacity_used;
|
||||
int percent_shared_processor_pool_used;
|
||||
long main_storage_size_long;
|
||||
} SSTS0200;
|
||||
|
||||
|
||||
typedef struct {
|
||||
char header[208];
|
||||
unsigned char loca_adapter_address[12];
|
||||
} LIND0500;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int bytes_provided;
|
||||
int bytes_available;
|
||||
char msgid[7];
|
||||
} errcode_s;
|
||||
|
||||
|
||||
static const unsigned char e2a[256] = {
|
||||
0, 1, 2, 3, 156, 9, 134, 127, 151, 141, 142, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 157, 133, 8, 135, 24, 25, 146, 143, 28, 29, 30, 31,
|
||||
128, 129, 130, 131, 132, 10, 23, 27, 136, 137, 138, 139, 140, 5, 6, 7,
|
||||
144, 145, 22, 147, 148, 149, 150, 4, 152, 153, 154, 155, 20, 21, 158, 26,
|
||||
32, 160, 161, 162, 163, 164, 165, 166, 167, 168, 91, 46, 60, 40, 43, 33,
|
||||
38, 169, 170, 171, 172, 173, 174, 175, 176, 177, 93, 36, 42, 41, 59, 94,
|
||||
45, 47, 178, 179, 180, 181, 182, 183, 184, 185, 124, 44, 37, 95, 62, 63,
|
||||
186, 187, 188, 189, 190, 191, 192, 193, 194, 96, 58, 35, 64, 39, 61, 34,
|
||||
195, 97, 98, 99, 100, 101, 102, 103, 104, 105, 196, 197, 198, 199, 200, 201,
|
||||
202, 106, 107, 108, 109, 110, 111, 112, 113, 114, 203, 204, 205, 206, 207, 208,
|
||||
209, 126, 115, 116, 117, 118, 119, 120, 121, 122, 210, 211, 212, 213, 214, 215,
|
||||
216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231,
|
||||
123, 65, 66, 67, 68, 69, 70, 71, 72, 73, 232, 233, 234, 235, 236, 237,
|
||||
125, 74, 75, 76, 77, 78, 79, 80, 81, 82, 238, 239, 240, 241, 242, 243,
|
||||
92, 159, 83, 84, 85, 86, 87, 88, 89, 90, 244, 245, 246, 247, 248, 249,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 250, 251, 252, 253, 254, 255};
|
||||
|
||||
|
||||
static const unsigned char a2e[256] = {
|
||||
0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31,
|
||||
64, 79, 127, 123, 91, 108, 80, 125, 77, 93, 92, 78, 107, 96, 75, 97,
|
||||
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 122, 94, 76, 126, 110, 111,
|
||||
124, 193, 194, 195, 196, 197, 198, 199, 200, 201, 209, 210, 211, 212, 213, 214,
|
||||
215, 216, 217, 226, 227, 228, 229, 230, 231, 232, 233, 74, 224, 90, 95, 109,
|
||||
121, 129, 130, 131, 132, 133, 134, 135, 136, 137, 145, 146, 147, 148, 149, 150,
|
||||
151, 152, 153, 162, 163, 164, 165, 166, 167, 168, 169, 192, 106, 208, 161, 7,
|
||||
32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27,
|
||||
48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62, 225,
|
||||
65, 66, 67, 68, 69, 70, 71, 72, 73, 81, 82, 83, 84, 85, 86, 87,
|
||||
88, 89, 98, 99, 100, 101, 102, 103, 104, 105, 112, 113, 114, 115, 116, 117,
|
||||
118, 119, 120, 128, 138, 139, 140, 141, 142, 143, 144, 154, 155, 156, 157, 158,
|
||||
159, 160, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183,
|
||||
184, 185, 186, 187, 188, 189, 190, 191, 202, 203, 204, 205, 206, 207, 218, 219,
|
||||
220, 221, 222, 223, 234, 235, 236, 237, 238, 239, 250, 251, 252, 253, 254, 255};
|
||||
|
||||
|
||||
static void iconv_e2a(unsigned char src[], unsigned char dst[], size_t length) {
|
||||
size_t i;
|
||||
for (i = 0; i < length; i++)
|
||||
dst[i] = e2a[src[i]];
|
||||
}
|
||||
|
||||
|
||||
static void iconv_a2e(const char* src, unsigned char dst[], size_t length) {
|
||||
size_t srclen;
|
||||
size_t i;
|
||||
|
||||
srclen = strlen(src);
|
||||
if (srclen > length)
|
||||
abort();
|
||||
for (i = 0; i < srclen; i++)
|
||||
dst[i] = a2e[src[i]];
|
||||
/* padding the remaining part with spaces */
|
||||
for (; i < length; i++)
|
||||
dst[i] = a2e[' '];
|
||||
}
|
||||
|
||||
void init_process_title_mutex_once(void) {
|
||||
uv_mutex_init(&process_title_mutex);
|
||||
}
|
||||
|
||||
static int get_ibmi_system_status(SSTS0200* rcvr) {
|
||||
/* rcvrlen is input parameter 2 to QWCRSSTS */
|
||||
unsigned int rcvrlen = sizeof(*rcvr);
|
||||
unsigned char format[8], reset_status[10];
|
||||
|
||||
/* format is input parameter 3 to QWCRSSTS */
|
||||
iconv_a2e("SSTS0200", format, sizeof(format));
|
||||
/* reset_status is input parameter 4 */
|
||||
iconv_a2e("*NO", reset_status, sizeof(reset_status));
|
||||
|
||||
/* errcode is input parameter 5 to QWCRSSTS */
|
||||
errcode_s errcode;
|
||||
|
||||
/* qwcrssts_pointer is the 16-byte tagged system pointer to QWCRSSTS */
|
||||
ILEpointer __attribute__((aligned(16))) qwcrssts_pointer;
|
||||
|
||||
/* qwcrssts_argv is the array of argument pointers to QWCRSSTS */
|
||||
void* qwcrssts_argv[6];
|
||||
|
||||
/* Set the IBM i pointer to the QSYS/QWCRSSTS *PGM object */
|
||||
int rc = _RSLOBJ2(&qwcrssts_pointer, RSLOBJ_TS_PGM, "QWCRSSTS", "QSYS");
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
/* initialize the QWCRSSTS returned info structure */
|
||||
memset(rcvr, 0, sizeof(*rcvr));
|
||||
|
||||
/* initialize the QWCRSSTS error code structure */
|
||||
memset(&errcode, 0, sizeof(errcode));
|
||||
errcode.bytes_provided = sizeof(errcode);
|
||||
|
||||
/* initialize the array of argument pointers for the QWCRSSTS API */
|
||||
qwcrssts_argv[0] = rcvr;
|
||||
qwcrssts_argv[1] = &rcvrlen;
|
||||
qwcrssts_argv[2] = &format;
|
||||
qwcrssts_argv[3] = &reset_status;
|
||||
qwcrssts_argv[4] = &errcode;
|
||||
qwcrssts_argv[5] = NULL;
|
||||
|
||||
/* Call the IBM i QWCRSSTS API from PASE */
|
||||
rc = _PGMCALL(&qwcrssts_pointer, qwcrssts_argv, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
SSTS0200 rcvr;
|
||||
|
||||
if (get_ibmi_system_status(&rcvr))
|
||||
return 0;
|
||||
|
||||
return (uint64_t)rcvr.main_storage_size * 1024ULL;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
SSTS0200 rcvr;
|
||||
|
||||
if (get_ibmi_system_status(&rcvr))
|
||||
return 0;
|
||||
|
||||
return (uint64_t)rcvr.main_storage_size * 1024ULL;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
SSTS0200 rcvr;
|
||||
|
||||
if (get_ibmi_system_status(&rcvr)) {
|
||||
avg[0] = avg[1] = avg[2] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* The average (in tenths) of the elapsed time during which the processing
|
||||
* units were in use. For example, a value of 411 in binary would be 41.1%.
|
||||
* This percentage could be greater than 100% for an uncapped partition.
|
||||
*/
|
||||
double processing_unit_used_percent =
|
||||
rcvr.percent_processing_unit_used / 1000.0;
|
||||
|
||||
avg[0] = avg[1] = avg[2] = processing_unit_used_percent;
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
*rss = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
unsigned int numcpus, idx = 0;
|
||||
uv_cpu_info_t* cpu_info;
|
||||
|
||||
*cpu_infos = NULL;
|
||||
*count = 0;
|
||||
|
||||
numcpus = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
|
||||
*cpu_infos = uv__malloc(numcpus * sizeof(uv_cpu_info_t));
|
||||
if (!*cpu_infos) {
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
cpu_info = *cpu_infos;
|
||||
for (idx = 0; idx < numcpus; idx++) {
|
||||
cpu_info->speed = 0;
|
||||
cpu_info->model = uv__strdup("unknown");
|
||||
cpu_info->cpu_times.user = 0;
|
||||
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++;
|
||||
}
|
||||
*count = numcpus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int get_ibmi_physical_address(const char* line, char (*phys_addr)[6]) {
|
||||
LIND0500 rcvr;
|
||||
/* rcvrlen is input parameter 2 to QDCRLIND */
|
||||
unsigned int rcvrlen = sizeof(rcvr);
|
||||
unsigned char format[8], line_name[10];
|
||||
unsigned char mac_addr[sizeof(rcvr.loca_adapter_address)];
|
||||
int c[6];
|
||||
|
||||
/* format is input parameter 3 to QDCRLIND */
|
||||
iconv_a2e("LIND0500", format, sizeof(format));
|
||||
|
||||
/* line_name is input parameter 4 to QDCRLIND */
|
||||
iconv_a2e(line, line_name, sizeof(line_name));
|
||||
|
||||
/* err is input parameter 5 to QDCRLIND */
|
||||
errcode_s err;
|
||||
|
||||
/* qwcrssts_pointer is the 16-byte tagged system pointer to QDCRLIND */
|
||||
ILEpointer __attribute__((aligned(16))) qdcrlind_pointer;
|
||||
|
||||
/* qwcrssts_argv is the array of argument pointers to QDCRLIND */
|
||||
void* qdcrlind_argv[6];
|
||||
|
||||
/* Set the IBM i pointer to the QSYS/QDCRLIND *PGM object */
|
||||
int rc = _RSLOBJ2(&qdcrlind_pointer, RSLOBJ_TS_PGM, "QDCRLIND", "QSYS");
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
/* initialize the QDCRLIND returned info structure */
|
||||
memset(&rcvr, 0, sizeof(rcvr));
|
||||
|
||||
/* initialize the QDCRLIND error code structure */
|
||||
memset(&err, 0, sizeof(err));
|
||||
err.bytes_provided = sizeof(err);
|
||||
|
||||
/* initialize the array of argument pointers for the QDCRLIND API */
|
||||
qdcrlind_argv[0] = &rcvr;
|
||||
qdcrlind_argv[1] = &rcvrlen;
|
||||
qdcrlind_argv[2] = &format;
|
||||
qdcrlind_argv[3] = &line_name;
|
||||
qdcrlind_argv[4] = &err;
|
||||
qdcrlind_argv[5] = NULL;
|
||||
|
||||
/* Call the IBM i QDCRLIND API from PASE */
|
||||
rc = _PGMCALL(&qdcrlind_pointer, qdcrlind_argv, 0);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
/* convert ebcdic loca_adapter_address to ascii first */
|
||||
iconv_e2a(rcvr.loca_adapter_address, mac_addr,
|
||||
sizeof(rcvr.loca_adapter_address));
|
||||
|
||||
/* convert loca_adapter_address(char[12]) to phys_addr(char[6]) */
|
||||
int r = sscanf(mac_addr, "%02x%02x%02x%02x%02x%02x",
|
||||
&c[0], &c[1], &c[2], &c[3], &c[4], &c[5]);
|
||||
|
||||
if (r == ARRAY_SIZE(c)) {
|
||||
(*phys_addr)[0] = c[0];
|
||||
(*phys_addr)[1] = c[1];
|
||||
(*phys_addr)[2] = c[2];
|
||||
(*phys_addr)[3] = c[3];
|
||||
(*phys_addr)[4] = c[4];
|
||||
(*phys_addr)[5] = c[5];
|
||||
} else {
|
||||
memset(*phys_addr, 0, sizeof(*phys_addr));
|
||||
rc = -1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
uv_interface_address_t* address;
|
||||
struct ifaddrs_pase *ifap = NULL, *cur;
|
||||
int inet6, r = 0;
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
if (Qp2getifaddrs(&ifap))
|
||||
return UV_ENOSYS;
|
||||
|
||||
/* The first loop to get the size of the array to be allocated */
|
||||
for (cur = ifap; cur; cur = cur->ifa_next) {
|
||||
if (!(cur->ifa_addr->sa_family == AF_INET6 ||
|
||||
cur->ifa_addr->sa_family == AF_INET))
|
||||
continue;
|
||||
|
||||
if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
|
||||
continue;
|
||||
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
if (*count == 0) {
|
||||
Qp2freeifaddrs(ifap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Alloc the return interface structs */
|
||||
*addresses = uv__calloc(*count, sizeof(**addresses));
|
||||
if (*addresses == NULL) {
|
||||
Qp2freeifaddrs(ifap);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
address = *addresses;
|
||||
|
||||
/* The second loop to fill in the array */
|
||||
for (cur = ifap; cur; cur = cur->ifa_next) {
|
||||
if (!(cur->ifa_addr->sa_family == AF_INET6 ||
|
||||
cur->ifa_addr->sa_family == AF_INET))
|
||||
continue;
|
||||
|
||||
if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
|
||||
continue;
|
||||
|
||||
address->name = uv__strdup(cur->ifa_name);
|
||||
|
||||
inet6 = (cur->ifa_addr->sa_family == AF_INET6);
|
||||
|
||||
if (inet6) {
|
||||
address->address.address6 = *((struct sockaddr_in6*)cur->ifa_addr);
|
||||
address->netmask.netmask6 = *((struct sockaddr_in6*)cur->ifa_netmask);
|
||||
address->netmask.netmask6.sin6_family = AF_INET6;
|
||||
} else {
|
||||
address->address.address4 = *((struct sockaddr_in*)cur->ifa_addr);
|
||||
address->netmask.netmask4 = *((struct sockaddr_in*)cur->ifa_netmask);
|
||||
address->netmask.netmask4.sin_family = AF_INET;
|
||||
}
|
||||
address->is_internal = cur->ifa_flags & IFF_LOOPBACK ? 1 : 0;
|
||||
if (!address->is_internal) {
|
||||
int rc = get_ibmi_physical_address(address->name, &address->phys_addr);
|
||||
if (rc != 0)
|
||||
r = rc;
|
||||
}
|
||||
|
||||
address++;
|
||||
}
|
||||
|
||||
Qp2freeifaddrs(ifap);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
char exepath[UV__PATH_MAX];
|
||||
char* s;
|
||||
size_t size;
|
||||
|
||||
if (argc > 0) {
|
||||
/* Use argv[0] to determine value for uv_exepath(). */
|
||||
size = sizeof(exepath);
|
||||
if (uv__search_path(argv[0], exepath, &size) == 0) {
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
original_exepath = uv__strdup(exepath);
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
return argv;
|
||||
}
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
if (buffer == NULL || size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
buffer[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uv__process_title_cleanup(void) {
|
||||
}
|
344
deps/libuv/src/unix/internal.h
vendored
Normal file
344
deps/libuv/src/unix/internal.h
vendored
Normal file
@ -0,0 +1,344 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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_UNIX_INTERNAL_H_
|
||||
#define UV_UNIX_INTERNAL_H_
|
||||
|
||||
#include "uv-common.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h> /* _POSIX_PATH_MAX, PATH_MAX */
|
||||
#include <stdlib.h> /* abort */
|
||||
#include <string.h> /* strrchr */
|
||||
#include <fcntl.h> /* O_CLOEXEC and O_NONBLOCK, if supported. */
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#if defined(__STRICT_ANSI__)
|
||||
# define inline __inline
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
# 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>
|
||||
#endif /* __sun */
|
||||
|
||||
#if defined(_AIX)
|
||||
# define reqevents events
|
||||
# define rtnevents revents
|
||||
# include <sys/poll.h>
|
||||
#else
|
||||
# include <poll.h>
|
||||
#endif /* _AIX */
|
||||
|
||||
#if defined(__APPLE__) && !TARGET_OS_IPHONE
|
||||
# include <AvailabilityMacros.h>
|
||||
#endif
|
||||
|
||||
#if defined(PATH_MAX)
|
||||
# define UV__PATH_MAX PATH_MAX
|
||||
#else
|
||||
# define UV__PATH_MAX 8192
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
|
||||
# ifdef pthread_sigmask
|
||||
# undef pthread_sigmask
|
||||
# endif
|
||||
# define pthread_sigmask(how, set, oldset) uv__pthread_sigmask(how, set, oldset)
|
||||
#endif
|
||||
|
||||
#define ACCESS_ONCE(type, var) \
|
||||
(*(volatile type*) &(var))
|
||||
|
||||
#define ROUND_UP(a, b) \
|
||||
((a) % (b) ? ((a) + (b)) - ((a) % (b)) : (a))
|
||||
|
||||
#define UNREACHABLE() \
|
||||
do { \
|
||||
assert(0 && "unreachable code"); \
|
||||
abort(); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define SAVE_ERRNO(block) \
|
||||
do { \
|
||||
int _saved_errno = errno; \
|
||||
do { block; } while (0); \
|
||||
errno = _saved_errno; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* The __clang__ and __INTEL_COMPILER checks are superfluous because they
|
||||
* define __GNUC__. They are here to convey to you, dear reader, that these
|
||||
* macros are enabled when compiling with clang or icc.
|
||||
*/
|
||||
#if defined(__clang__) || \
|
||||
defined(__GNUC__) || \
|
||||
defined(__INTEL_COMPILER)
|
||||
# define UV_UNUSED(declaration) __attribute__((unused)) declaration
|
||||
#else
|
||||
# define UV_UNUSED(declaration) declaration
|
||||
#endif
|
||||
|
||||
/* Leans on the fact that, on Linux, POLLRDHUP == EPOLLRDHUP. */
|
||||
#ifdef POLLRDHUP
|
||||
# define UV__POLLRDHUP POLLRDHUP
|
||||
#else
|
||||
# define UV__POLLRDHUP 0x2000
|
||||
#endif
|
||||
|
||||
#ifdef POLLPRI
|
||||
# define UV__POLLPRI POLLPRI
|
||||
#else
|
||||
# define UV__POLLPRI 0
|
||||
#endif
|
||||
|
||||
#if !defined(O_CLOEXEC) && defined(__FreeBSD__)
|
||||
/*
|
||||
* It may be that we are just missing `__POSIX_VISIBLE >= 200809`.
|
||||
* Try using fixed value const and give up, if it doesn't work
|
||||
*/
|
||||
# define O_CLOEXEC 0x00100000
|
||||
#endif
|
||||
|
||||
typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
|
||||
|
||||
/* loop flags */
|
||||
enum {
|
||||
UV_LOOP_BLOCK_SIGPROF = 1
|
||||
};
|
||||
|
||||
/* flags of excluding ifaddr */
|
||||
enum {
|
||||
UV__EXCLUDE_IFPHYS,
|
||||
UV__EXCLUDE_IFADDR
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */
|
||||
UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */
|
||||
} uv_clocktype_t;
|
||||
|
||||
struct uv__stream_queued_fds_s {
|
||||
unsigned int size;
|
||||
unsigned int offset;
|
||||
int fds[1];
|
||||
};
|
||||
|
||||
|
||||
#if defined(_AIX) || \
|
||||
defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__linux__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
#define uv__cloexec uv__cloexec_ioctl
|
||||
#define uv__nonblock uv__nonblock_ioctl
|
||||
#else
|
||||
#define uv__cloexec uv__cloexec_fcntl
|
||||
#define uv__nonblock uv__nonblock_fcntl
|
||||
#endif
|
||||
|
||||
/* On Linux, uv__nonblock_fcntl() and uv__nonblock_ioctl() do not commute
|
||||
* when O_NDELAY is not equal to O_NONBLOCK. Case in point: linux/sparc32
|
||||
* and linux/sparc64, where O_NDELAY is O_NONBLOCK + another bit.
|
||||
*
|
||||
* Libuv uses uv__nonblock_fcntl() directly sometimes so ensure that it
|
||||
* commutes with uv__nonblock().
|
||||
*/
|
||||
#if defined(__linux__) && O_NDELAY != O_NONBLOCK
|
||||
#undef uv__nonblock
|
||||
#define uv__nonblock uv__nonblock_fcntl
|
||||
#endif
|
||||
|
||||
/* core */
|
||||
int uv__cloexec_ioctl(int fd, int set);
|
||||
int uv__cloexec_fcntl(int fd, int set);
|
||||
int uv__nonblock_ioctl(int fd, int set);
|
||||
int uv__nonblock_fcntl(int fd, int set);
|
||||
int uv__close(int fd); /* preserves errno */
|
||||
int uv__close_nocheckstdio(int fd);
|
||||
int uv__close_nocancel(int fd);
|
||||
int uv__socket(int domain, int type, int protocol);
|
||||
ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
|
||||
void uv__make_close_pending(uv_handle_t* handle);
|
||||
int uv__getiovmax(void);
|
||||
|
||||
void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd);
|
||||
void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events);
|
||||
void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events);
|
||||
void uv__io_close(uv_loop_t* loop, uv__io_t* w);
|
||||
void uv__io_feed(uv_loop_t* loop, uv__io_t* w);
|
||||
int uv__io_active(const uv__io_t* w, unsigned int events);
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd);
|
||||
void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */
|
||||
int uv__io_fork(uv_loop_t* loop);
|
||||
int uv__fd_exists(uv_loop_t* loop, int fd);
|
||||
|
||||
/* async */
|
||||
void uv__async_stop(uv_loop_t* loop);
|
||||
int uv__async_fork(uv_loop_t* loop);
|
||||
|
||||
|
||||
/* loop */
|
||||
void uv__run_idle(uv_loop_t* loop);
|
||||
void uv__run_check(uv_loop_t* loop);
|
||||
void uv__run_prepare(uv_loop_t* loop);
|
||||
|
||||
/* stream */
|
||||
void uv__stream_init(uv_loop_t* loop, uv_stream_t* stream,
|
||||
uv_handle_type type);
|
||||
int uv__stream_open(uv_stream_t*, int fd, int flags);
|
||||
void uv__stream_destroy(uv_stream_t* stream);
|
||||
#if defined(__APPLE__)
|
||||
int uv__stream_try_select(uv_stream_t* stream, int* fd);
|
||||
#endif /* defined(__APPLE__) */
|
||||
void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
|
||||
int uv__accept(int sockfd);
|
||||
int uv__dup2_cloexec(int oldfd, int newfd);
|
||||
int uv__open_cloexec(const char* path, int flags);
|
||||
|
||||
/* tcp */
|
||||
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
|
||||
int uv__tcp_nodelay(int fd, int on);
|
||||
int uv__tcp_keepalive(int fd, int on, unsigned int delay);
|
||||
|
||||
/* pipe */
|
||||
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
|
||||
|
||||
/* signal */
|
||||
void uv__signal_close(uv_signal_t* handle);
|
||||
void uv__signal_global_once_init(void);
|
||||
void uv__signal_loop_cleanup(uv_loop_t* loop);
|
||||
int uv__signal_loop_fork(uv_loop_t* loop);
|
||||
|
||||
/* platform specific */
|
||||
uint64_t uv__hrtime(uv_clocktype_t type);
|
||||
int uv__kqueue_init(uv_loop_t* loop);
|
||||
int uv__platform_loop_init(uv_loop_t* loop);
|
||||
void uv__platform_loop_delete(uv_loop_t* loop);
|
||||
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd);
|
||||
|
||||
/* various */
|
||||
void uv__async_close(uv_async_t* handle);
|
||||
void uv__check_close(uv_check_t* handle);
|
||||
void uv__fs_event_close(uv_fs_event_t* handle);
|
||||
void uv__idle_close(uv_idle_t* handle);
|
||||
void uv__pipe_close(uv_pipe_t* handle);
|
||||
void uv__poll_close(uv_poll_t* handle);
|
||||
void uv__prepare_close(uv_prepare_t* handle);
|
||||
void uv__process_close(uv_process_t* handle);
|
||||
void uv__stream_close(uv_stream_t* handle);
|
||||
void uv__tcp_close(uv_tcp_t* handle);
|
||||
void uv__udp_close(uv_udp_t* handle);
|
||||
void uv__udp_finish_close(uv_udp_t* handle);
|
||||
uv_handle_type uv__handle_type(int fd);
|
||||
FILE* uv__open_file(const char* path);
|
||||
int uv__getpwuid_r(uv_passwd_t* pwd);
|
||||
int uv__search_path(const char* prog, char* buf, size_t* buflen);
|
||||
|
||||
/* random */
|
||||
int uv__random_devurandom(void* buf, size_t buflen);
|
||||
int uv__random_getrandom(void* buf, size_t buflen);
|
||||
int uv__random_getentropy(void* buf, size_t buflen);
|
||||
int uv__random_readpath(const char* path, void* buf, size_t buflen);
|
||||
int uv__random_sysctl(void* buf, size_t buflen);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
int uv___stream_fd(const uv_stream_t* handle);
|
||||
#define uv__stream_fd(handle) (uv___stream_fd((const uv_stream_t*) (handle)))
|
||||
#else
|
||||
#define uv__stream_fd(handle) ((handle)->io_watcher.fd)
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
#ifdef O_NONBLOCK
|
||||
# define UV__F_NONBLOCK O_NONBLOCK
|
||||
#else
|
||||
# define UV__F_NONBLOCK 1
|
||||
#endif
|
||||
|
||||
int uv__make_pipe(int fds[2], int flags);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
int uv__fsevents_init(uv_fs_event_t* handle);
|
||||
int uv__fsevents_close(uv_fs_event_t* handle);
|
||||
void uv__fsevents_loop_delete(uv_loop_t* loop);
|
||||
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
|
||||
/* Use a fast time source if available. We only need millisecond precision.
|
||||
*/
|
||||
loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000;
|
||||
}
|
||||
|
||||
UV_UNUSED(static char* uv__basename_r(const char* path)) {
|
||||
char* s;
|
||||
|
||||
s = strrchr(path, '/');
|
||||
if (s == NULL)
|
||||
return (char*) path;
|
||||
|
||||
return s + 1;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
int uv__inotify_fork(uv_loop_t* loop, void* old_watchers);
|
||||
#endif
|
||||
|
||||
typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*);
|
||||
|
||||
int uv__getsockpeername(const uv_handle_t* handle,
|
||||
uv__peersockfunc func,
|
||||
struct sockaddr* name,
|
||||
int* namelen);
|
||||
|
||||
#if defined(__linux__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__)
|
||||
#define HAVE_MMSG 1
|
||||
struct uv__mmsghdr {
|
||||
struct msghdr msg_hdr;
|
||||
unsigned int msg_len;
|
||||
};
|
||||
|
||||
int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen);
|
||||
int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen);
|
||||
#else
|
||||
#define HAVE_MMSG 0
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* UV_UNIX_INTERNAL_H_ */
|
585
deps/libuv/src/unix/kqueue.c
vendored
Normal file
585
deps/libuv/src/unix/kqueue.c
vendored
Normal file
@ -0,0 +1,585 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
|
||||
/*
|
||||
* Required on
|
||||
* - Until at least FreeBSD 11.0
|
||||
* - Older versions of Mac OS X
|
||||
*
|
||||
* http://www.boost.org/doc/libs/1_61_0/boost/asio/detail/kqueue_reactor.hpp
|
||||
*/
|
||||
#ifndef EV_OOBAND
|
||||
#define EV_OOBAND EV_FLAG1
|
||||
#endif
|
||||
|
||||
static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags);
|
||||
|
||||
|
||||
int uv__kqueue_init(uv_loop_t* loop) {
|
||||
loop->backend_fd = kqueue();
|
||||
if (loop->backend_fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
uv__cloexec(loop->backend_fd, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
static int uv__has_forked_with_cfrunloop;
|
||||
#endif
|
||||
|
||||
int uv__io_fork(uv_loop_t* loop) {
|
||||
int err;
|
||||
loop->backend_fd = -1;
|
||||
err = uv__kqueue_init(loop);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
if (loop->cf_state != NULL) {
|
||||
/* We cannot start another CFRunloop and/or thread in the child
|
||||
process; CF aborts if you try or if you try to touch the thread
|
||||
at all to kill it. So the best we can do is ignore it from now
|
||||
on. This means we can't watch directories in the same way
|
||||
anymore (like other BSDs). It also means we cannot properly
|
||||
clean up the allocated resources; calling
|
||||
uv__fsevents_loop_delete from uv_loop_close will crash the
|
||||
process. So we sidestep the issue by pretending like we never
|
||||
started it in the first place.
|
||||
*/
|
||||
uv__store_relaxed(&uv__has_forked_with_cfrunloop, 1);
|
||||
uv__free(loop->cf_state);
|
||||
loop->cf_state = NULL;
|
||||
}
|
||||
#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
struct kevent ev;
|
||||
int rc;
|
||||
|
||||
rc = 0;
|
||||
EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
|
||||
if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
|
||||
rc = UV__ERR(errno);
|
||||
|
||||
EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
|
||||
if (rc == 0)
|
||||
if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
|
||||
abort();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
struct kevent events[1024];
|
||||
struct kevent* ev;
|
||||
struct timespec spec;
|
||||
unsigned int nevents;
|
||||
unsigned int revents;
|
||||
QUEUE* q;
|
||||
uv__io_t* w;
|
||||
sigset_t* pset;
|
||||
sigset_t set;
|
||||
uint64_t base;
|
||||
uint64_t diff;
|
||||
int have_signals;
|
||||
int filter;
|
||||
int fflags;
|
||||
int count;
|
||||
int nfds;
|
||||
int fd;
|
||||
int op;
|
||||
int i;
|
||||
int user_timeout;
|
||||
int reset_timeout;
|
||||
|
||||
if (loop->nfds == 0) {
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
return;
|
||||
}
|
||||
|
||||
nevents = 0;
|
||||
|
||||
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
|
||||
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);
|
||||
assert(w->fd < (int) loop->nwatchers);
|
||||
|
||||
if ((w->events & POLLIN) == 0 && (w->pevents & POLLIN) != 0) {
|
||||
filter = EVFILT_READ;
|
||||
fflags = 0;
|
||||
op = EV_ADD;
|
||||
|
||||
if (w->cb == uv__fs_event) {
|
||||
filter = EVFILT_VNODE;
|
||||
fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME
|
||||
| NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
|
||||
op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */
|
||||
}
|
||||
|
||||
EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0);
|
||||
|
||||
if (++nevents == ARRAY_SIZE(events)) {
|
||||
if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
|
||||
abort();
|
||||
nevents = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((w->events & POLLOUT) == 0 && (w->pevents & POLLOUT) != 0) {
|
||||
EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
|
||||
|
||||
if (++nevents == ARRAY_SIZE(events)) {
|
||||
if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
|
||||
abort();
|
||||
nevents = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((w->events & UV__POLLPRI) == 0 && (w->pevents & UV__POLLPRI) != 0) {
|
||||
EV_SET(events + nevents, w->fd, EV_OOBAND, EV_ADD, 0, 0, 0);
|
||||
|
||||
if (++nevents == ARRAY_SIZE(events)) {
|
||||
if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
|
||||
abort();
|
||||
nevents = 0;
|
||||
}
|
||||
}
|
||||
|
||||
w->events = w->pevents;
|
||||
}
|
||||
|
||||
pset = NULL;
|
||||
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
|
||||
pset = &set;
|
||||
sigemptyset(pset);
|
||||
sigaddset(pset, SIGPROF);
|
||||
}
|
||||
|
||||
assert(timeout >= -1);
|
||||
base = loop->time;
|
||||
count = 48; /* Benchmarks suggest this gives the best throughput. */
|
||||
|
||||
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
|
||||
reset_timeout = 1;
|
||||
user_timeout = timeout;
|
||||
timeout = 0;
|
||||
} else {
|
||||
reset_timeout = 0;
|
||||
}
|
||||
|
||||
for (;; nevents = 0) {
|
||||
/* Only need to set the provider_entry_time if timeout != 0. The function
|
||||
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
|
||||
*/
|
||||
if (timeout != 0)
|
||||
uv__metrics_set_provider_entry_time(loop);
|
||||
|
||||
if (timeout != -1) {
|
||||
spec.tv_sec = timeout / 1000;
|
||||
spec.tv_nsec = (timeout % 1000) * 1000000;
|
||||
}
|
||||
|
||||
if (pset != NULL)
|
||||
pthread_sigmask(SIG_BLOCK, pset, NULL);
|
||||
|
||||
nfds = kevent(loop->backend_fd,
|
||||
events,
|
||||
nevents,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
timeout == -1 ? NULL : &spec);
|
||||
|
||||
if (pset != NULL)
|
||||
pthread_sigmask(SIG_UNBLOCK, pset, NULL);
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
SAVE_ERRNO(uv__update_time(loop));
|
||||
|
||||
if (nfds == 0) {
|
||||
if (reset_timeout != 0) {
|
||||
timeout = user_timeout;
|
||||
reset_timeout = 0;
|
||||
if (timeout == -1)
|
||||
continue;
|
||||
if (timeout > 0)
|
||||
goto update_timeout;
|
||||
}
|
||||
|
||||
assert(timeout != -1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nfds == -1) {
|
||||
if (errno != EINTR)
|
||||
abort();
|
||||
|
||||
if (reset_timeout != 0) {
|
||||
timeout = user_timeout;
|
||||
reset_timeout = 0;
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
if (timeout == -1)
|
||||
continue;
|
||||
|
||||
/* Interrupted by a signal. Update timeout and poll again. */
|
||||
goto update_timeout;
|
||||
}
|
||||
|
||||
have_signals = 0;
|
||||
nevents = 0;
|
||||
|
||||
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++) {
|
||||
ev = events + i;
|
||||
fd = ev->ident;
|
||||
/* Skip invalidated events, see uv__platform_invalidate_fd */
|
||||
if (fd == -1)
|
||||
continue;
|
||||
w = loop->watchers[fd];
|
||||
|
||||
if (w == NULL) {
|
||||
/* File descriptor that we've stopped watching, disarm it.
|
||||
* TODO: batch up. */
|
||||
struct kevent events[1];
|
||||
|
||||
EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
|
||||
if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
|
||||
if (errno != EBADF && errno != ENOENT)
|
||||
abort();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ev->filter == EVFILT_VNODE) {
|
||||
assert(w->events == POLLIN);
|
||||
assert(w->pevents == POLLIN);
|
||||
uv__metrics_update_idle_time(loop);
|
||||
w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */
|
||||
nevents++;
|
||||
continue;
|
||||
}
|
||||
|
||||
revents = 0;
|
||||
|
||||
if (ev->filter == EVFILT_READ) {
|
||||
if (w->pevents & POLLIN) {
|
||||
revents |= POLLIN;
|
||||
w->rcount = ev->data;
|
||||
} else {
|
||||
/* TODO batch up */
|
||||
struct kevent events[1];
|
||||
EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
|
||||
if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
|
||||
if (errno != ENOENT)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (ev->filter == EV_OOBAND) {
|
||||
if (w->pevents & UV__POLLPRI) {
|
||||
revents |= UV__POLLPRI;
|
||||
w->rcount = ev->data;
|
||||
} else {
|
||||
/* TODO batch up */
|
||||
struct kevent events[1];
|
||||
EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
|
||||
if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
|
||||
if (errno != ENOENT)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (ev->filter == EVFILT_WRITE) {
|
||||
if (w->pevents & POLLOUT) {
|
||||
revents |= POLLOUT;
|
||||
w->wcount = ev->data;
|
||||
} else {
|
||||
/* TODO batch up */
|
||||
struct kevent events[1];
|
||||
EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
|
||||
if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
|
||||
if (errno != ENOENT)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (ev->flags & EV_ERROR)
|
||||
revents |= POLLERR;
|
||||
|
||||
if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP))
|
||||
revents |= UV__POLLRDHUP;
|
||||
|
||||
if (revents == 0)
|
||||
continue;
|
||||
|
||||
/* Run signal watchers last. This also affects child process watchers
|
||||
* because those are implemented in terms of signal watchers.
|
||||
*/
|
||||
if (w == &loop->signal_io_watcher) {
|
||||
have_signals = 1;
|
||||
} else {
|
||||
uv__metrics_update_idle_time(loop);
|
||||
w->cb(loop, w, revents);
|
||||
}
|
||||
|
||||
nevents++;
|
||||
}
|
||||
|
||||
if (reset_timeout != 0) {
|
||||
timeout = user_timeout;
|
||||
reset_timeout = 0;
|
||||
}
|
||||
|
||||
if (have_signals != 0) {
|
||||
uv__metrics_update_idle_time(loop);
|
||||
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
|
||||
}
|
||||
|
||||
loop->watchers[loop->nwatchers] = NULL;
|
||||
loop->watchers[loop->nwatchers + 1] = NULL;
|
||||
|
||||
if (have_signals != 0)
|
||||
return; /* Event loop should cycle now so don't poll again. */
|
||||
|
||||
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);
|
||||
|
||||
diff = loop->time - base;
|
||||
if (diff >= (uint64_t) timeout)
|
||||
return;
|
||||
|
||||
timeout -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
struct kevent* events;
|
||||
uintptr_t i;
|
||||
uintptr_t nfds;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
assert(fd >= 0);
|
||||
|
||||
events = (struct kevent*) loop->watchers[loop->nwatchers];
|
||||
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
|
||||
if (events == NULL)
|
||||
return;
|
||||
|
||||
/* Invalidate events with same file descriptor */
|
||||
for (i = 0; i < nfds; i++)
|
||||
if ((int) events[i].ident == fd)
|
||||
events[i].ident = -1;
|
||||
}
|
||||
|
||||
|
||||
static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
|
||||
uv_fs_event_t* handle;
|
||||
struct kevent ev;
|
||||
int events;
|
||||
const char* path;
|
||||
#if defined(F_GETPATH)
|
||||
/* MAXPATHLEN == PATH_MAX but the former is what XNU calls it internally. */
|
||||
char pathbuf[MAXPATHLEN];
|
||||
#endif
|
||||
|
||||
handle = container_of(w, uv_fs_event_t, event_watcher);
|
||||
|
||||
if (fflags & (NOTE_ATTRIB | NOTE_EXTEND))
|
||||
events = UV_CHANGE;
|
||||
else
|
||||
events = UV_RENAME;
|
||||
|
||||
path = NULL;
|
||||
#if defined(F_GETPATH)
|
||||
/* Also works when the file has been unlinked from the file system. Passing
|
||||
* in the path when the file has been deleted is arguably a little strange
|
||||
* but it's consistent with what the inotify backend does.
|
||||
*/
|
||||
if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0)
|
||||
path = uv__basename_r(pathbuf);
|
||||
#endif
|
||||
handle->cb(handle, path, events, 0);
|
||||
|
||||
if (handle->event_watcher.fd == -1)
|
||||
return;
|
||||
|
||||
/* Watcher operates in one-shot mode, re-arm it. */
|
||||
fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME
|
||||
| NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
|
||||
|
||||
EV_SET(&ev, w->fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, fflags, 0, 0);
|
||||
|
||||
if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
uv_fs_event_cb cb,
|
||||
const char* path,
|
||||
unsigned int flags) {
|
||||
int fd;
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
struct stat statbuf;
|
||||
#endif
|
||||
|
||||
if (uv__is_active(handle))
|
||||
return UV_EINVAL;
|
||||
|
||||
handle->cb = cb;
|
||||
handle->path = uv__strdup(path);
|
||||
if (handle->path == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
/* TODO open asynchronously - but how do we report back errors? */
|
||||
fd = open(handle->path, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
/* Nullify field to perform checks later */
|
||||
handle->cf_cb = NULL;
|
||||
handle->realpath = NULL;
|
||||
handle->realpath_len = 0;
|
||||
handle->cf_flags = flags;
|
||||
|
||||
if (fstat(fd, &statbuf))
|
||||
goto fallback;
|
||||
/* FSEvents works only with directories */
|
||||
if (!(statbuf.st_mode & S_IFDIR))
|
||||
goto fallback;
|
||||
|
||||
if (0 == uv__load_relaxed(&uv__has_forked_with_cfrunloop)) {
|
||||
int r;
|
||||
/* The fallback fd is no longer needed */
|
||||
uv__close_nocheckstdio(fd);
|
||||
handle->event_watcher.fd = -1;
|
||||
r = uv__fsevents_init(handle);
|
||||
if (r == 0) {
|
||||
uv__handle_start(handle);
|
||||
} else {
|
||||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
fallback:
|
||||
#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
|
||||
|
||||
uv__handle_start(handle);
|
||||
uv__io_init(&handle->event_watcher, uv__fs_event, fd);
|
||||
uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
int r;
|
||||
r = 0;
|
||||
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
uv__handle_stop(handle);
|
||||
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
if (0 == uv__load_relaxed(&uv__has_forked_with_cfrunloop))
|
||||
if (handle->cf_cb != NULL)
|
||||
r = uv__fsevents_close(handle);
|
||||
#endif
|
||||
|
||||
if (handle->event_watcher.fd != -1) {
|
||||
uv__io_close(handle->loop, &handle->event_watcher);
|
||||
uv__close(handle->event_watcher.fd);
|
||||
handle->event_watcher.fd = -1;
|
||||
}
|
||||
|
||||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void uv__fs_event_close(uv_fs_event_t* handle) {
|
||||
uv_fs_event_stop(handle);
|
||||
}
|
1146
deps/libuv/src/unix/linux-core.c
vendored
Normal file
1146
deps/libuv/src/unix/linux-core.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
327
deps/libuv/src/unix/linux-inotify.c
vendored
Normal file
327
deps/libuv/src/unix/linux-inotify.c
vendored
Normal file
@ -0,0 +1,327 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "uv/tree.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct watcher_list {
|
||||
RB_ENTRY(watcher_list) entry;
|
||||
QUEUE watchers;
|
||||
int iterating;
|
||||
char* path;
|
||||
int wd;
|
||||
};
|
||||
|
||||
struct watcher_root {
|
||||
struct watcher_list* rbh_root;
|
||||
};
|
||||
#define CAST(p) ((struct watcher_root*)(p))
|
||||
|
||||
|
||||
static int compare_watchers(const struct watcher_list* a,
|
||||
const struct watcher_list* b) {
|
||||
if (a->wd < b->wd) return -1;
|
||||
if (a->wd > b->wd) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
RB_GENERATE_STATIC(watcher_root, watcher_list, entry, compare_watchers)
|
||||
|
||||
|
||||
static void uv__inotify_read(uv_loop_t* loop,
|
||||
uv__io_t* w,
|
||||
unsigned int revents);
|
||||
|
||||
static void maybe_free_watcher_list(struct watcher_list* w,
|
||||
uv_loop_t* loop);
|
||||
|
||||
static int init_inotify(uv_loop_t* loop) {
|
||||
int fd;
|
||||
|
||||
if (loop->inotify_fd != -1)
|
||||
return 0;
|
||||
|
||||
fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
loop->inotify_fd = fd;
|
||||
uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd);
|
||||
uv__io_start(loop, &loop->inotify_read_watcher, POLLIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__inotify_fork(uv_loop_t* loop, void* old_watchers) {
|
||||
/* Open the inotify_fd, and re-arm all the inotify watchers. */
|
||||
int err;
|
||||
struct watcher_list* tmp_watcher_list_iter;
|
||||
struct watcher_list* watcher_list;
|
||||
struct watcher_list tmp_watcher_list;
|
||||
QUEUE queue;
|
||||
QUEUE* q;
|
||||
uv_fs_event_t* handle;
|
||||
char* tmp_path;
|
||||
|
||||
if (old_watchers != NULL) {
|
||||
/* We must restore the old watcher list to be able to close items
|
||||
* out of it.
|
||||
*/
|
||||
loop->inotify_watchers = old_watchers;
|
||||
|
||||
QUEUE_INIT(&tmp_watcher_list.watchers);
|
||||
/* Note that the queue we use is shared with the start and stop()
|
||||
* functions, making QUEUE_FOREACH unsafe to use. So we use the
|
||||
* QUEUE_MOVE trick to safely iterate. Also don't free the watcher
|
||||
* list until we're done iterating. c.f. uv__inotify_read.
|
||||
*/
|
||||
RB_FOREACH_SAFE(watcher_list, watcher_root,
|
||||
CAST(&old_watchers), tmp_watcher_list_iter) {
|
||||
watcher_list->iterating = 1;
|
||||
QUEUE_MOVE(&watcher_list->watchers, &queue);
|
||||
while (!QUEUE_EMPTY(&queue)) {
|
||||
q = QUEUE_HEAD(&queue);
|
||||
handle = QUEUE_DATA(q, uv_fs_event_t, watchers);
|
||||
/* It's critical to keep a copy of path here, because it
|
||||
* will be set to NULL by stop() and then deallocated by
|
||||
* maybe_free_watcher_list
|
||||
*/
|
||||
tmp_path = uv__strdup(handle->path);
|
||||
assert(tmp_path != NULL);
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INSERT_TAIL(&watcher_list->watchers, q);
|
||||
uv_fs_event_stop(handle);
|
||||
|
||||
QUEUE_INSERT_TAIL(&tmp_watcher_list.watchers, &handle->watchers);
|
||||
handle->path = tmp_path;
|
||||
}
|
||||
watcher_list->iterating = 0;
|
||||
maybe_free_watcher_list(watcher_list, loop);
|
||||
}
|
||||
|
||||
QUEUE_MOVE(&tmp_watcher_list.watchers, &queue);
|
||||
while (!QUEUE_EMPTY(&queue)) {
|
||||
q = QUEUE_HEAD(&queue);
|
||||
QUEUE_REMOVE(q);
|
||||
handle = QUEUE_DATA(q, uv_fs_event_t, watchers);
|
||||
tmp_path = handle->path;
|
||||
handle->path = NULL;
|
||||
err = uv_fs_event_start(handle, handle->cb, tmp_path, 0);
|
||||
uv__free(tmp_path);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) {
|
||||
struct watcher_list w;
|
||||
w.wd = wd;
|
||||
return RB_FIND(watcher_root, CAST(&loop->inotify_watchers), &w);
|
||||
}
|
||||
|
||||
static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) {
|
||||
/* if the watcher_list->watchers is being iterated over, we can't free it. */
|
||||
if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) {
|
||||
/* No watchers left for this path. Clean up. */
|
||||
RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w);
|
||||
inotify_rm_watch(loop->inotify_fd, w->wd);
|
||||
uv__free(w);
|
||||
}
|
||||
}
|
||||
|
||||
static void uv__inotify_read(uv_loop_t* loop,
|
||||
uv__io_t* dummy,
|
||||
unsigned int events) {
|
||||
const struct inotify_event* e;
|
||||
struct watcher_list* w;
|
||||
uv_fs_event_t* h;
|
||||
QUEUE queue;
|
||||
QUEUE* q;
|
||||
const char* path;
|
||||
ssize_t size;
|
||||
const char *p;
|
||||
/* needs to be large enough for sizeof(inotify_event) + strlen(path) */
|
||||
char buf[4096];
|
||||
|
||||
while (1) {
|
||||
do
|
||||
size = read(loop->inotify_fd, buf, sizeof(buf));
|
||||
while (size == -1 && errno == EINTR);
|
||||
|
||||
if (size == -1) {
|
||||
assert(errno == EAGAIN || errno == EWOULDBLOCK);
|
||||
break;
|
||||
}
|
||||
|
||||
assert(size > 0); /* pre-2.6.21 thing, size=0 == read buffer too small */
|
||||
|
||||
/* Now we have one or more inotify_event structs. */
|
||||
for (p = buf; p < buf + size; p += sizeof(*e) + e->len) {
|
||||
e = (const struct inotify_event*) p;
|
||||
|
||||
events = 0;
|
||||
if (e->mask & (IN_ATTRIB|IN_MODIFY))
|
||||
events |= UV_CHANGE;
|
||||
if (e->mask & ~(IN_ATTRIB|IN_MODIFY))
|
||||
events |= UV_RENAME;
|
||||
|
||||
w = find_watcher(loop, e->wd);
|
||||
if (w == NULL)
|
||||
continue; /* Stale event, no watchers left. */
|
||||
|
||||
/* inotify does not return the filename when monitoring a single file
|
||||
* for modifications. Repurpose the filename for API compatibility.
|
||||
* I'm not convinced this is a good thing, maybe it should go.
|
||||
*/
|
||||
path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path);
|
||||
|
||||
/* We're about to iterate over the queue and call user's callbacks.
|
||||
* What can go wrong?
|
||||
* A callback could call uv_fs_event_stop()
|
||||
* and the queue can change under our feet.
|
||||
* So, we use QUEUE_MOVE() trick to safely iterate over the queue.
|
||||
* And we don't free the watcher_list until we're done iterating.
|
||||
*
|
||||
* First,
|
||||
* tell uv_fs_event_stop() (that could be called from a user's callback)
|
||||
* not to free watcher_list.
|
||||
*/
|
||||
w->iterating = 1;
|
||||
QUEUE_MOVE(&w->watchers, &queue);
|
||||
while (!QUEUE_EMPTY(&queue)) {
|
||||
q = QUEUE_HEAD(&queue);
|
||||
h = QUEUE_DATA(q, uv_fs_event_t, watchers);
|
||||
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INSERT_TAIL(&w->watchers, q);
|
||||
|
||||
h->cb(h, path, events, 0);
|
||||
}
|
||||
/* done iterating, time to (maybe) free empty watcher_list */
|
||||
w->iterating = 0;
|
||||
maybe_free_watcher_list(w, loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
uv_fs_event_cb cb,
|
||||
const char* path,
|
||||
unsigned int flags) {
|
||||
struct watcher_list* w;
|
||||
size_t len;
|
||||
int events;
|
||||
int err;
|
||||
int wd;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
return UV_EINVAL;
|
||||
|
||||
err = init_inotify(handle->loop);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
events = IN_ATTRIB
|
||||
| IN_CREATE
|
||||
| IN_MODIFY
|
||||
| IN_DELETE
|
||||
| IN_DELETE_SELF
|
||||
| IN_MOVE_SELF
|
||||
| IN_MOVED_FROM
|
||||
| IN_MOVED_TO;
|
||||
|
||||
wd = inotify_add_watch(handle->loop->inotify_fd, path, events);
|
||||
if (wd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
w = find_watcher(handle->loop, wd);
|
||||
if (w)
|
||||
goto no_insert;
|
||||
|
||||
len = strlen(path) + 1;
|
||||
w = uv__malloc(sizeof(*w) + len);
|
||||
if (w == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
w->wd = wd;
|
||||
w->path = memcpy(w + 1, path, len);
|
||||
QUEUE_INIT(&w->watchers);
|
||||
w->iterating = 0;
|
||||
RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w);
|
||||
|
||||
no_insert:
|
||||
uv__handle_start(handle);
|
||||
QUEUE_INSERT_TAIL(&w->watchers, &handle->watchers);
|
||||
handle->path = w->path;
|
||||
handle->cb = cb;
|
||||
handle->wd = wd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
struct watcher_list* w;
|
||||
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
w = find_watcher(handle->loop, handle->wd);
|
||||
assert(w != NULL);
|
||||
|
||||
handle->wd = -1;
|
||||
handle->path = NULL;
|
||||
uv__handle_stop(handle);
|
||||
QUEUE_REMOVE(&handle->watchers);
|
||||
|
||||
maybe_free_watcher_list(w, handle->loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__fs_event_close(uv_fs_event_t* handle) {
|
||||
uv_fs_event_stop(handle);
|
||||
}
|
267
deps/libuv/src/unix/linux-syscalls.c
vendored
Normal file
267
deps/libuv/src/unix/linux-syscalls.c
vendored
Normal file
@ -0,0 +1,267 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "linux-syscalls.h"
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(__arm__)
|
||||
# if defined(__thumb__) || defined(__ARM_EABI__)
|
||||
# define UV_SYSCALL_BASE 0
|
||||
# else
|
||||
# define UV_SYSCALL_BASE 0x900000
|
||||
# endif
|
||||
#endif /* __arm__ */
|
||||
|
||||
#ifndef __NR_recvmmsg
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_recvmmsg 299
|
||||
# elif defined(__arm__)
|
||||
# define __NR_recvmmsg (UV_SYSCALL_BASE + 365)
|
||||
# endif
|
||||
#endif /* __NR_recvmsg */
|
||||
|
||||
#ifndef __NR_sendmmsg
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_sendmmsg 307
|
||||
# elif defined(__arm__)
|
||||
# define __NR_sendmmsg (UV_SYSCALL_BASE + 374)
|
||||
# endif
|
||||
#endif /* __NR_sendmmsg */
|
||||
|
||||
#ifndef __NR_utimensat
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_utimensat 280
|
||||
# elif defined(__i386__)
|
||||
# define __NR_utimensat 320
|
||||
# elif defined(__arm__)
|
||||
# define __NR_utimensat (UV_SYSCALL_BASE + 348)
|
||||
# endif
|
||||
#endif /* __NR_utimensat */
|
||||
|
||||
#ifndef __NR_preadv
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_preadv 295
|
||||
# elif defined(__i386__)
|
||||
# define __NR_preadv 333
|
||||
# elif defined(__arm__)
|
||||
# define __NR_preadv (UV_SYSCALL_BASE + 361)
|
||||
# endif
|
||||
#endif /* __NR_preadv */
|
||||
|
||||
#ifndef __NR_pwritev
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_pwritev 296
|
||||
# elif defined(__i386__)
|
||||
# define __NR_pwritev 334
|
||||
# elif defined(__arm__)
|
||||
# define __NR_pwritev (UV_SYSCALL_BASE + 362)
|
||||
# endif
|
||||
#endif /* __NR_pwritev */
|
||||
|
||||
#ifndef __NR_dup3
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_dup3 292
|
||||
# elif defined(__i386__)
|
||||
# define __NR_dup3 330
|
||||
# elif defined(__arm__)
|
||||
# define __NR_dup3 (UV_SYSCALL_BASE + 358)
|
||||
# endif
|
||||
#endif /* __NR_pwritev */
|
||||
|
||||
#ifndef __NR_copy_file_range
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_copy_file_range 326
|
||||
# elif defined(__i386__)
|
||||
# define __NR_copy_file_range 377
|
||||
# elif defined(__s390__)
|
||||
# define __NR_copy_file_range 375
|
||||
# elif defined(__arm__)
|
||||
# define __NR_copy_file_range (UV_SYSCALL_BASE + 391)
|
||||
# elif defined(__aarch64__)
|
||||
# define __NR_copy_file_range 285
|
||||
# elif defined(__powerpc__)
|
||||
# define __NR_copy_file_range 379
|
||||
# elif defined(__arc__)
|
||||
# define __NR_copy_file_range 285
|
||||
# endif
|
||||
#endif /* __NR_copy_file_range */
|
||||
|
||||
#ifndef __NR_statx
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_statx 332
|
||||
# elif defined(__i386__)
|
||||
# define __NR_statx 383
|
||||
# elif defined(__aarch64__)
|
||||
# define __NR_statx 397
|
||||
# elif defined(__arm__)
|
||||
# define __NR_statx (UV_SYSCALL_BASE + 397)
|
||||
# elif defined(__ppc__)
|
||||
# define __NR_statx 383
|
||||
# elif defined(__s390__)
|
||||
# define __NR_statx 379
|
||||
# endif
|
||||
#endif /* __NR_statx */
|
||||
|
||||
#ifndef __NR_getrandom
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_getrandom 318
|
||||
# elif defined(__i386__)
|
||||
# define __NR_getrandom 355
|
||||
# elif defined(__aarch64__)
|
||||
# define __NR_getrandom 384
|
||||
# elif defined(__arm__)
|
||||
# define __NR_getrandom (UV_SYSCALL_BASE + 384)
|
||||
# elif defined(__ppc__)
|
||||
# define __NR_getrandom 359
|
||||
# elif defined(__s390__)
|
||||
# define __NR_getrandom 349
|
||||
# endif
|
||||
#endif /* __NR_getrandom */
|
||||
|
||||
struct uv__mmsghdr;
|
||||
|
||||
int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
|
||||
#if defined(__i386__)
|
||||
unsigned long args[4];
|
||||
int rc;
|
||||
|
||||
args[0] = (unsigned long) fd;
|
||||
args[1] = (unsigned long) mmsg;
|
||||
args[2] = (unsigned long) vlen;
|
||||
args[3] = /* flags */ 0;
|
||||
|
||||
/* socketcall() raises EINVAL when SYS_SENDMMSG is not supported. */
|
||||
rc = syscall(/* __NR_socketcall */ 102, 20 /* SYS_SENDMMSG */, args);
|
||||
if (rc == -1)
|
||||
if (errno == EINVAL)
|
||||
errno = ENOSYS;
|
||||
|
||||
return rc;
|
||||
#elif defined(__NR_sendmmsg)
|
||||
return syscall(__NR_sendmmsg, fd, mmsg, vlen, /* flags */ 0);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
|
||||
#if defined(__i386__)
|
||||
unsigned long args[5];
|
||||
int rc;
|
||||
|
||||
args[0] = (unsigned long) fd;
|
||||
args[1] = (unsigned long) mmsg;
|
||||
args[2] = (unsigned long) vlen;
|
||||
args[3] = /* flags */ 0;
|
||||
args[4] = /* timeout */ 0;
|
||||
|
||||
/* socketcall() raises EINVAL when SYS_RECVMMSG is not supported. */
|
||||
rc = syscall(/* __NR_socketcall */ 102, 19 /* SYS_RECVMMSG */, args);
|
||||
if (rc == -1)
|
||||
if (errno == EINVAL)
|
||||
errno = ENOSYS;
|
||||
|
||||
return rc;
|
||||
#elif defined(__NR_recvmmsg)
|
||||
return syscall(__NR_recvmmsg, fd, mmsg, vlen, /* flags */ 0, /* timeout */ 0);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
|
||||
#if defined(__NR_preadv)
|
||||
return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
|
||||
#if defined(__NR_pwritev)
|
||||
return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__dup3(int oldfd, int newfd, int flags) {
|
||||
#if defined(__NR_dup3)
|
||||
return syscall(__NR_dup3, oldfd, newfd, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
uv__fs_copy_file_range(int fd_in,
|
||||
ssize_t* off_in,
|
||||
int fd_out,
|
||||
ssize_t* off_out,
|
||||
size_t len,
|
||||
unsigned int flags)
|
||||
{
|
||||
#ifdef __NR_copy_file_range
|
||||
return syscall(__NR_copy_file_range,
|
||||
fd_in,
|
||||
off_in,
|
||||
fd_out,
|
||||
off_out,
|
||||
len,
|
||||
flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__statx(int dirfd,
|
||||
const char* path,
|
||||
int flags,
|
||||
unsigned int mask,
|
||||
struct uv__statx* statxbuf) {
|
||||
/* __NR_statx make Android box killed by SIGSYS.
|
||||
* That looks like a seccomp2 sandbox filter rejecting the system call.
|
||||
*/
|
||||
#if defined(__NR_statx) && !defined(__ANDROID__)
|
||||
return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags) {
|
||||
#if defined(__NR_getrandom)
|
||||
return syscall(__NR_getrandom, buf, buflen, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
81
deps/libuv/src/unix/linux-syscalls.h
vendored
Normal file
81
deps/libuv/src/unix/linux-syscalls.h
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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_LINUX_SYSCALL_H_
|
||||
#define UV_LINUX_SYSCALL_H_
|
||||
|
||||
#undef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
struct uv__statx_timestamp {
|
||||
int64_t tv_sec;
|
||||
uint32_t tv_nsec;
|
||||
int32_t unused0;
|
||||
};
|
||||
|
||||
struct uv__statx {
|
||||
uint32_t stx_mask;
|
||||
uint32_t stx_blksize;
|
||||
uint64_t stx_attributes;
|
||||
uint32_t stx_nlink;
|
||||
uint32_t stx_uid;
|
||||
uint32_t stx_gid;
|
||||
uint16_t stx_mode;
|
||||
uint16_t unused0;
|
||||
uint64_t stx_ino;
|
||||
uint64_t stx_size;
|
||||
uint64_t stx_blocks;
|
||||
uint64_t stx_attributes_mask;
|
||||
struct uv__statx_timestamp stx_atime;
|
||||
struct uv__statx_timestamp stx_btime;
|
||||
struct uv__statx_timestamp stx_ctime;
|
||||
struct uv__statx_timestamp stx_mtime;
|
||||
uint32_t stx_rdev_major;
|
||||
uint32_t stx_rdev_minor;
|
||||
uint32_t stx_dev_major;
|
||||
uint32_t stx_dev_minor;
|
||||
uint64_t unused1[14];
|
||||
};
|
||||
|
||||
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
|
||||
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
|
||||
int uv__dup3(int oldfd, int newfd, int flags);
|
||||
ssize_t
|
||||
uv__fs_copy_file_range(int fd_in,
|
||||
ssize_t* off_in,
|
||||
int fd_out,
|
||||
ssize_t* off_out,
|
||||
size_t len,
|
||||
unsigned int flags);
|
||||
int uv__statx(int dirfd,
|
||||
const char* path,
|
||||
int flags,
|
||||
unsigned int mask,
|
||||
struct uv__statx* statxbuf);
|
||||
ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags);
|
||||
|
||||
#endif /* UV_LINUX_SYSCALL_H_ */
|
68
deps/libuv/src/unix/loop-watcher.c
vendored
Normal file
68
deps/libuv/src/unix/loop-watcher.c
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#define UV_LOOP_WATCHER_DEFINE(name, type) \
|
||||
int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_##type); \
|
||||
handle->name##_cb = NULL; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
|
||||
if (uv__is_active(handle)) return 0; \
|
||||
if (cb == NULL) return UV_EINVAL; \
|
||||
QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \
|
||||
handle->name##_cb = cb; \
|
||||
uv__handle_start(handle); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
int uv_##name##_stop(uv_##name##_t* handle) { \
|
||||
if (!uv__is_active(handle)) return 0; \
|
||||
QUEUE_REMOVE(&handle->queue); \
|
||||
uv__handle_stop(handle); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
void uv__run_##name(uv_loop_t* loop) { \
|
||||
uv_##name##_t* h; \
|
||||
QUEUE queue; \
|
||||
QUEUE* q; \
|
||||
QUEUE_MOVE(&loop->name##_handles, &queue); \
|
||||
while (!QUEUE_EMPTY(&queue)) { \
|
||||
q = QUEUE_HEAD(&queue); \
|
||||
h = QUEUE_DATA(q, uv_##name##_t, queue); \
|
||||
QUEUE_REMOVE(q); \
|
||||
QUEUE_INSERT_TAIL(&loop->name##_handles, q); \
|
||||
h->name##_cb(h); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
void uv__##name##_close(uv_##name##_t* handle) { \
|
||||
uv_##name##_stop(handle); \
|
||||
}
|
||||
|
||||
UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
|
||||
UV_LOOP_WATCHER_DEFINE(check, CHECK)
|
||||
UV_LOOP_WATCHER_DEFINE(idle, IDLE)
|
228
deps/libuv/src/unix/loop.c
vendored
Normal file
228
deps/libuv/src/unix/loop.c
vendored
Normal file
@ -0,0 +1,228 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "uv/tree.h"
|
||||
#include "internal.h"
|
||||
#include "heap-inl.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int uv_loop_init(uv_loop_t* loop) {
|
||||
uv__loop_internal_fields_t* lfields;
|
||||
void* saved_data;
|
||||
int err;
|
||||
|
||||
|
||||
saved_data = loop->data;
|
||||
memset(loop, 0, sizeof(*loop));
|
||||
loop->data = saved_data;
|
||||
|
||||
lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields));
|
||||
if (lfields == NULL)
|
||||
return UV_ENOMEM;
|
||||
loop->internal_fields = lfields;
|
||||
|
||||
err = uv_mutex_init(&lfields->loop_metrics.lock);
|
||||
if (err)
|
||||
goto fail_metrics_mutex_init;
|
||||
|
||||
heap_init((struct heap*) &loop->timer_heap);
|
||||
QUEUE_INIT(&loop->wq);
|
||||
QUEUE_INIT(&loop->idle_handles);
|
||||
QUEUE_INIT(&loop->async_handles);
|
||||
QUEUE_INIT(&loop->check_handles);
|
||||
QUEUE_INIT(&loop->prepare_handles);
|
||||
QUEUE_INIT(&loop->handle_queue);
|
||||
|
||||
loop->active_handles = 0;
|
||||
loop->active_reqs.count = 0;
|
||||
loop->nfds = 0;
|
||||
loop->watchers = NULL;
|
||||
loop->nwatchers = 0;
|
||||
QUEUE_INIT(&loop->pending_queue);
|
||||
QUEUE_INIT(&loop->watcher_queue);
|
||||
|
||||
loop->closing_handles = NULL;
|
||||
uv__update_time(loop);
|
||||
loop->async_io_watcher.fd = -1;
|
||||
loop->async_wfd = -1;
|
||||
loop->signal_pipefd[0] = -1;
|
||||
loop->signal_pipefd[1] = -1;
|
||||
loop->backend_fd = -1;
|
||||
loop->emfile_fd = -1;
|
||||
|
||||
loop->timer_counter = 0;
|
||||
loop->stop_flag = 0;
|
||||
|
||||
err = uv__platform_loop_init(loop);
|
||||
if (err)
|
||||
goto fail_platform_init;
|
||||
|
||||
uv__signal_global_once_init();
|
||||
err = uv_signal_init(loop, &loop->child_watcher);
|
||||
if (err)
|
||||
goto fail_signal_init;
|
||||
|
||||
uv__handle_unref(&loop->child_watcher);
|
||||
loop->child_watcher.flags |= UV_HANDLE_INTERNAL;
|
||||
QUEUE_INIT(&loop->process_handles);
|
||||
|
||||
err = uv_rwlock_init(&loop->cloexec_lock);
|
||||
if (err)
|
||||
goto fail_rwlock_init;
|
||||
|
||||
err = uv_mutex_init(&loop->wq_mutex);
|
||||
if (err)
|
||||
goto fail_mutex_init;
|
||||
|
||||
err = uv_async_init(loop, &loop->wq_async, uv__work_done);
|
||||
if (err)
|
||||
goto fail_async_init;
|
||||
|
||||
uv__handle_unref(&loop->wq_async);
|
||||
loop->wq_async.flags |= UV_HANDLE_INTERNAL;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_async_init:
|
||||
uv_mutex_destroy(&loop->wq_mutex);
|
||||
|
||||
fail_mutex_init:
|
||||
uv_rwlock_destroy(&loop->cloexec_lock);
|
||||
|
||||
fail_rwlock_init:
|
||||
uv__signal_loop_cleanup(loop);
|
||||
|
||||
fail_signal_init:
|
||||
uv__platform_loop_delete(loop);
|
||||
|
||||
fail_platform_init:
|
||||
uv_mutex_destroy(&lfields->loop_metrics.lock);
|
||||
|
||||
fail_metrics_mutex_init:
|
||||
uv__free(lfields);
|
||||
loop->internal_fields = NULL;
|
||||
|
||||
uv__free(loop->watchers);
|
||||
loop->nwatchers = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int uv_loop_fork(uv_loop_t* loop) {
|
||||
int err;
|
||||
unsigned int i;
|
||||
uv__io_t* w;
|
||||
|
||||
err = uv__io_fork(loop);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = uv__async_fork(loop);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = uv__signal_loop_fork(loop);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Rearm all the watchers that aren't re-queued by the above. */
|
||||
for (i = 0; i < loop->nwatchers; i++) {
|
||||
w = loop->watchers[i];
|
||||
if (w == NULL)
|
||||
continue;
|
||||
|
||||
if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) {
|
||||
w->events = 0; /* Force re-registration in uv__io_poll. */
|
||||
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__loop_close(uv_loop_t* loop) {
|
||||
uv__loop_internal_fields_t* lfields;
|
||||
|
||||
uv__signal_loop_cleanup(loop);
|
||||
uv__platform_loop_delete(loop);
|
||||
uv__async_stop(loop);
|
||||
|
||||
if (loop->emfile_fd != -1) {
|
||||
uv__close(loop->emfile_fd);
|
||||
loop->emfile_fd = -1;
|
||||
}
|
||||
|
||||
if (loop->backend_fd != -1) {
|
||||
uv__close(loop->backend_fd);
|
||||
loop->backend_fd = -1;
|
||||
}
|
||||
|
||||
uv_mutex_lock(&loop->wq_mutex);
|
||||
assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
|
||||
assert(!uv__has_active_reqs(loop));
|
||||
uv_mutex_unlock(&loop->wq_mutex);
|
||||
uv_mutex_destroy(&loop->wq_mutex);
|
||||
|
||||
/*
|
||||
* Note that all thread pool stuff is finished at this point and
|
||||
* it is safe to just destroy rw lock
|
||||
*/
|
||||
uv_rwlock_destroy(&loop->cloexec_lock);
|
||||
|
||||
#if 0
|
||||
assert(QUEUE_EMPTY(&loop->pending_queue));
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
assert(loop->nfds == 0);
|
||||
#endif
|
||||
|
||||
uv__free(loop->watchers);
|
||||
loop->watchers = NULL;
|
||||
loop->nwatchers = 0;
|
||||
|
||||
lfields = uv__get_internal_fields(loop);
|
||||
uv_mutex_destroy(&lfields->loop_metrics.lock);
|
||||
uv__free(lfields);
|
||||
loop->internal_fields = NULL;
|
||||
}
|
||||
|
||||
|
||||
int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
|
||||
uv__loop_internal_fields_t* lfields;
|
||||
|
||||
lfields = uv__get_internal_fields(loop);
|
||||
if (option == UV_METRICS_IDLE_TIME) {
|
||||
lfields->flags |= UV_METRICS_IDLE_TIME;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (option != UV_LOOP_BLOCK_SIGNAL)
|
||||
return UV_ENOSYS;
|
||||
|
||||
if (va_arg(ap, int) != SIGPROF)
|
||||
return UV_EINVAL;
|
||||
|
||||
loop->flags |= UV_LOOP_BLOCK_SIGPROF;
|
||||
return 0;
|
||||
}
|
259
deps/libuv/src/unix/netbsd.c
vendored
Normal file
259
deps/libuv/src/unix/netbsd.c
vendored
Normal file
@ -0,0 +1,259 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <kvm.h>
|
||||
#include <paths.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <uvm/uvm_extern.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
return uv__kqueue_init(loop);
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
struct loadavg info;
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_LOADAVG};
|
||||
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) == -1) return;
|
||||
|
||||
avg[0] = (double) info.ldavg[0] / info.fscale;
|
||||
avg[1] = (double) info.ldavg[1] / info.fscale;
|
||||
avg[2] = (double) info.ldavg[2] / info.fscale;
|
||||
}
|
||||
|
||||
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
/* Intermediate buffer, retrieving partial path name does not work
|
||||
* As of NetBSD-8(beta), vnode->path translator does not handle files
|
||||
* with longer names than 31 characters.
|
||||
*/
|
||||
char int_buf[PATH_MAX];
|
||||
size_t int_size;
|
||||
int mib[4];
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC_ARGS;
|
||||
mib[2] = -1;
|
||||
mib[3] = KERN_PROC_PATHNAME;
|
||||
int_size = ARRAY_SIZE(int_buf);
|
||||
|
||||
if (sysctl(mib, 4, int_buf, &int_size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* Copy string from the intermediate buffer to outer one with appropriate
|
||||
* length.
|
||||
*/
|
||||
/* TODO(bnoordhuis) Check uv__strscpy() return value. */
|
||||
uv__strscpy(buffer, int_buf, *size);
|
||||
|
||||
/* Set new size. */
|
||||
*size = strlen(buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
struct uvmexp info;
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_UVMEXP};
|
||||
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
#if defined(HW_PHYSMEM64)
|
||||
uint64_t info;
|
||||
int which[] = {CTL_HW, HW_PHYSMEM64};
|
||||
#else
|
||||
unsigned int info;
|
||||
int which[] = {CTL_HW, HW_PHYSMEM};
|
||||
#endif
|
||||
size_t size = sizeof(info);
|
||||
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
kvm_t *kd = NULL;
|
||||
struct kinfo_proc2 *kinfo = NULL;
|
||||
pid_t pid;
|
||||
int nprocs;
|
||||
int max_size = sizeof(struct kinfo_proc2);
|
||||
int page_size;
|
||||
|
||||
page_size = getpagesize();
|
||||
pid = getpid();
|
||||
|
||||
kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
|
||||
|
||||
if (kd == NULL) goto error;
|
||||
|
||||
kinfo = kvm_getproc2(kd, KERN_PROC_PID, pid, max_size, &nprocs);
|
||||
if (kinfo == NULL) goto error;
|
||||
|
||||
*rss = kinfo->p_vm_rssize * page_size;
|
||||
|
||||
kvm_close(kd);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (kd) kvm_close(kd);
|
||||
return UV_EPERM;
|
||||
}
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
time_t now;
|
||||
struct timeval info;
|
||||
size_t size = sizeof(info);
|
||||
static int which[] = {CTL_KERN, KERN_BOOTTIME};
|
||||
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
*uptime = (double)(now - info.tv_sec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK);
|
||||
unsigned int multiplier = ((uint64_t)1000L / ticks);
|
||||
unsigned int cur = 0;
|
||||
uv_cpu_info_t* cpu_info;
|
||||
u_int64_t* cp_times;
|
||||
char model[512];
|
||||
u_int64_t cpuspeed;
|
||||
int numcpus;
|
||||
size_t size;
|
||||
int i;
|
||||
|
||||
size = sizeof(model);
|
||||
if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) &&
|
||||
sysctlbyname("hw.model", &model, &size, NULL, 0)) {
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
size = sizeof(numcpus);
|
||||
if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
*count = numcpus;
|
||||
|
||||
/* Only i386 and amd64 have machdep.tsc_freq */
|
||||
size = sizeof(cpuspeed);
|
||||
if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &size, NULL, 0))
|
||||
cpuspeed = 0;
|
||||
|
||||
size = numcpus * CPUSTATES * sizeof(*cp_times);
|
||||
cp_times = uv__malloc(size);
|
||||
if (cp_times == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
*cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
|
||||
if (!(*cpu_infos)) {
|
||||
uv__free(cp_times);
|
||||
uv__free(*cpu_infos);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < numcpus; i++) {
|
||||
cpu_info = &(*cpu_infos)[i];
|
||||
cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
|
||||
cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
|
||||
cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
|
||||
cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
|
||||
cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
|
||||
cpu_info->model = uv__strdup(model);
|
||||
cpu_info->speed = (int)(cpuspeed/(uint64_t) 1e6);
|
||||
cur += CPUSTATES;
|
||||
}
|
||||
uv__free(cp_times);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv__random_sysctl(void* buf, size_t len) {
|
||||
static int name[] = {CTL_KERN, KERN_ARND};
|
||||
size_t count, req;
|
||||
unsigned char* p;
|
||||
|
||||
p = buf;
|
||||
while (len) {
|
||||
req = len < 32 ? len : 32;
|
||||
count = req;
|
||||
|
||||
if (sysctl(name, ARRAY_SIZE(name), p, &count, NULL, 0) == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (count != req)
|
||||
return UV_EIO; /* Can't happen. */
|
||||
|
||||
p += count;
|
||||
len -= count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
42
deps/libuv/src/unix/no-fsevents.c
vendored
Normal file
42
deps/libuv/src/unix/no-fsevents.c
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
/* 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
|
||||
const char* filename, unsigned int flags) {
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
void uv__fs_event_close(uv_fs_event_t* handle) {
|
||||
UNREACHABLE();
|
||||
}
|
45
deps/libuv/src/unix/no-proctitle.c
vendored
Normal file
45
deps/libuv/src/unix/no-proctitle.c
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
/* 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
return argv;
|
||||
}
|
||||
|
||||
void uv__process_title_cleanup(void) {
|
||||
}
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
if (buffer == NULL || size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
buffer[0] = '\0';
|
||||
return 0;
|
||||
}
|
240
deps/libuv/src/unix/openbsd.c
vendored
Normal file
240
deps/libuv/src/unix/openbsd.c
vendored
Normal file
@ -0,0 +1,240 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/sched.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
return uv__kqueue_init(loop);
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
struct loadavg info;
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_LOADAVG};
|
||||
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) < 0) return;
|
||||
|
||||
avg[0] = (double) info.ldavg[0] / info.fscale;
|
||||
avg[1] = (double) info.ldavg[1] / info.fscale;
|
||||
avg[2] = (double) info.ldavg[2] / info.fscale;
|
||||
}
|
||||
|
||||
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
int mib[4];
|
||||
char **argsbuf = NULL;
|
||||
size_t argsbuf_size = 100U;
|
||||
size_t exepath_size;
|
||||
pid_t mypid;
|
||||
int err;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
mypid = getpid();
|
||||
for (;;) {
|
||||
err = UV_ENOMEM;
|
||||
argsbuf = uv__reallocf(argsbuf, argsbuf_size);
|
||||
if (argsbuf == NULL)
|
||||
goto out;
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC_ARGS;
|
||||
mib[2] = mypid;
|
||||
mib[3] = KERN_PROC_ARGV;
|
||||
if (sysctl(mib, ARRAY_SIZE(mib), argsbuf, &argsbuf_size, NULL, 0) == 0) {
|
||||
break;
|
||||
}
|
||||
if (errno != ENOMEM) {
|
||||
err = UV__ERR(errno);
|
||||
goto out;
|
||||
}
|
||||
argsbuf_size *= 2U;
|
||||
}
|
||||
|
||||
if (argsbuf[0] == NULL) {
|
||||
err = UV_EINVAL; /* FIXME(bnoordhuis) More appropriate error. */
|
||||
goto out;
|
||||
}
|
||||
|
||||
*size -= 1;
|
||||
exepath_size = strlen(argsbuf[0]);
|
||||
if (*size > exepath_size)
|
||||
*size = exepath_size;
|
||||
|
||||
memcpy(buffer, argsbuf[0], *size);
|
||||
buffer[*size] = '\0';
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
uv__free(argsbuf);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
struct uvmexp info;
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_UVMEXP};
|
||||
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
uint64_t info;
|
||||
int which[] = {CTL_HW, HW_PHYSMEM64};
|
||||
size_t size = sizeof(info);
|
||||
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
struct kinfo_proc kinfo;
|
||||
size_t page_size = getpagesize();
|
||||
size_t size = sizeof(struct kinfo_proc);
|
||||
int mib[6];
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PID;
|
||||
mib[3] = getpid();
|
||||
mib[4] = sizeof(struct kinfo_proc);
|
||||
mib[5] = 1;
|
||||
|
||||
if (sysctl(mib, ARRAY_SIZE(mib), &kinfo, &size, NULL, 0) < 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
*rss = kinfo.p_vm_rssize * page_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
time_t now;
|
||||
struct timeval info;
|
||||
size_t size = sizeof(info);
|
||||
static int which[] = {CTL_KERN, KERN_BOOTTIME};
|
||||
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
*uptime = (double)(now - info.tv_sec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
|
||||
multiplier = ((uint64_t)1000L / ticks), cpuspeed;
|
||||
uint64_t info[CPUSTATES];
|
||||
char model[512];
|
||||
int numcpus = 1;
|
||||
int which[] = {CTL_HW,HW_MODEL};
|
||||
int percpu[] = {CTL_KERN,KERN_CPTIME2,0};
|
||||
size_t size;
|
||||
int i, j;
|
||||
uv_cpu_info_t* cpu_info;
|
||||
|
||||
size = sizeof(model);
|
||||
if (sysctl(which, ARRAY_SIZE(which), &model, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
which[1] = HW_NCPUONLINE;
|
||||
size = sizeof(numcpus);
|
||||
if (sysctl(which, ARRAY_SIZE(which), &numcpus, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
*cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
|
||||
if (!(*cpu_infos))
|
||||
return UV_ENOMEM;
|
||||
|
||||
i = 0;
|
||||
*count = numcpus;
|
||||
|
||||
which[1] = HW_CPUSPEED;
|
||||
size = sizeof(cpuspeed);
|
||||
if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0))
|
||||
goto error;
|
||||
|
||||
size = sizeof(info);
|
||||
for (i = 0; i < numcpus; i++) {
|
||||
percpu[2] = i;
|
||||
if (sysctl(percpu, ARRAY_SIZE(percpu), &info, &size, NULL, 0))
|
||||
goto error;
|
||||
|
||||
cpu_info = &(*cpu_infos)[i];
|
||||
|
||||
cpu_info->cpu_times.user = (uint64_t)(info[CP_USER]) * multiplier;
|
||||
cpu_info->cpu_times.nice = (uint64_t)(info[CP_NICE]) * multiplier;
|
||||
cpu_info->cpu_times.sys = (uint64_t)(info[CP_SYS]) * multiplier;
|
||||
cpu_info->cpu_times.idle = (uint64_t)(info[CP_IDLE]) * multiplier;
|
||||
cpu_info->cpu_times.irq = (uint64_t)(info[CP_INTR]) * multiplier;
|
||||
|
||||
cpu_info->model = uv__strdup(model);
|
||||
cpu_info->speed = cpuspeed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
*count = 0;
|
||||
for (j = 0; j < i; j++)
|
||||
uv__free((*cpu_infos)[j].model);
|
||||
|
||||
uv__free(*cpu_infos);
|
||||
*cpu_infos = NULL;
|
||||
return UV__ERR(errno);
|
||||
}
|
584
deps/libuv/src/unix/os390-syscalls.c
vendored
Normal file
584
deps/libuv/src/unix/os390-syscalls.c
vendored
Normal file
@ -0,0 +1,584 @@
|
||||
/* 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 <search.h>
|
||||
#include <termios.h>
|
||||
#include <sys/msg.h>
|
||||
|
||||
#define CW_INTRPT 1
|
||||
#define CW_CONDVAR 32
|
||||
|
||||
#pragma linkage(BPX4CTW, OS)
|
||||
#pragma linkage(BPX1CTW, OS)
|
||||
|
||||
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** nl_copy;
|
||||
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)
|
||||
goto error;
|
||||
memcpy(copy, dirent, sizeof(*copy));
|
||||
|
||||
nl_copy = uv__realloc(nl, sizeof(*copy) * (count + 1));
|
||||
if (nl_copy == NULL) {
|
||||
uv__free(copy);
|
||||
goto error;
|
||||
}
|
||||
|
||||
nl = nl_copy;
|
||||
nl[count++] = copy;
|
||||
}
|
||||
}
|
||||
|
||||
qsort(nl, count, sizeof(struct dirent *),
|
||||
(int (*)(const void *, const void *)) compar);
|
||||
|
||||
closedir(mdir);
|
||||
|
||||
*namelist = nl;
|
||||
return count;
|
||||
|
||||
error:
|
||||
while (count > 0) {
|
||||
dirent = nl[--count];
|
||||
uv__free(dirent);
|
||||
}
|
||||
uv__free(nl);
|
||||
closedir(mdir);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
struct pollfd event;
|
||||
|
||||
if (len <= lst->size)
|
||||
return;
|
||||
|
||||
if (lst->size == 0)
|
||||
event.fd = -1;
|
||||
else {
|
||||
/* Extract the message queue at the end. */
|
||||
event = lst->items[lst->size - 1];
|
||||
lst->items[lst->size - 1].fd = -1;
|
||||
}
|
||||
|
||||
newsize = next_power_of_two(len);
|
||||
newlst = uv__reallocf(lst->items, newsize * sizeof(lst->items[0]));
|
||||
|
||||
if (newlst == NULL)
|
||||
abort();
|
||||
for (i = lst->size; i < newsize; ++i)
|
||||
newlst[i].fd = -1;
|
||||
|
||||
/* Restore the message queue at the end */
|
||||
newlst[newsize - 1] = event;
|
||||
|
||||
lst->items = newlst;
|
||||
lst->size = newsize;
|
||||
}
|
||||
|
||||
|
||||
static void init_message_queue(uv__os390_epoll* lst) {
|
||||
struct {
|
||||
long int header;
|
||||
char body;
|
||||
} msg;
|
||||
|
||||
/* initialize message queue */
|
||||
lst->msg_queue = msgget(IPC_PRIVATE, 0600 | IPC_CREAT);
|
||||
if (lst->msg_queue == -1)
|
||||
abort();
|
||||
|
||||
/*
|
||||
On z/OS, the message queue will be affiliated with the process only
|
||||
when a send is performed on it. Once this is done, the system
|
||||
can be queried for all message queues belonging to our process id.
|
||||
*/
|
||||
msg.header = 1;
|
||||
if (msgsnd(lst->msg_queue, &msg, sizeof(msg.body), 0) != 0)
|
||||
abort();
|
||||
|
||||
/* Clean up the dummy message sent above */
|
||||
if (msgrcv(lst->msg_queue, &msg, sizeof(msg.body), 0, 0) != sizeof(msg.body))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
static void before_fork(void) {
|
||||
uv_mutex_lock(&global_epoll_lock);
|
||||
}
|
||||
|
||||
|
||||
static void after_fork(void) {
|
||||
uv_mutex_unlock(&global_epoll_lock);
|
||||
}
|
||||
|
||||
|
||||
static void child_fork(void) {
|
||||
QUEUE* q;
|
||||
uv_once_t child_once = UV_ONCE_INIT;
|
||||
|
||||
/* reset once */
|
||||
memcpy(&once, &child_once, sizeof(child_once));
|
||||
|
||||
/* reset epoll list */
|
||||
while (!QUEUE_EMPTY(&global_epoll_queue)) {
|
||||
uv__os390_epoll* lst;
|
||||
q = QUEUE_HEAD(&global_epoll_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
lst = QUEUE_DATA(q, uv__os390_epoll, member);
|
||||
uv__free(lst->items);
|
||||
lst->items = NULL;
|
||||
lst->size = 0;
|
||||
}
|
||||
|
||||
uv_mutex_unlock(&global_epoll_lock);
|
||||
uv_mutex_destroy(&global_epoll_lock);
|
||||
}
|
||||
|
||||
|
||||
static void epoll_init(void) {
|
||||
QUEUE_INIT(&global_epoll_queue);
|
||||
if (uv_mutex_init(&global_epoll_lock))
|
||||
abort();
|
||||
|
||||
if (pthread_atfork(&before_fork, &after_fork, &child_fork))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
uv__os390_epoll* epoll_create1(int flags) {
|
||||
uv__os390_epoll* lst;
|
||||
|
||||
lst = uv__malloc(sizeof(*lst));
|
||||
if (lst != NULL) {
|
||||
/* initialize list */
|
||||
lst->size = 0;
|
||||
lst->items = NULL;
|
||||
init_message_queue(lst);
|
||||
maybe_resize(lst, 1);
|
||||
lst->items[lst->size - 1].fd = lst->msg_queue;
|
||||
lst->items[lst->size - 1].events = POLLIN;
|
||||
lst->items[lst->size - 1].revents = 0;
|
||||
uv_once(&once, epoll_init);
|
||||
uv_mutex_lock(&global_epoll_lock);
|
||||
QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member);
|
||||
uv_mutex_unlock(&global_epoll_lock);
|
||||
}
|
||||
|
||||
return lst;
|
||||
}
|
||||
|
||||
|
||||
int epoll_ctl(uv__os390_epoll* lst,
|
||||
int op,
|
||||
int fd,
|
||||
struct epoll_event *event) {
|
||||
uv_mutex_lock(&global_epoll_lock);
|
||||
|
||||
if (op == EPOLL_CTL_DEL) {
|
||||
if (fd >= lst->size || lst->items[fd].fd == -1) {
|
||||
uv_mutex_unlock(&global_epoll_lock);
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
lst->items[fd].fd = -1;
|
||||
} else if (op == EPOLL_CTL_ADD) {
|
||||
|
||||
/* Resizing to 'fd + 1' would expand the list to contain at least
|
||||
* 'fd'. But we need to guarantee that the last index on the list
|
||||
* is reserved for the message queue. So specify 'fd + 2' instead.
|
||||
*/
|
||||
maybe_resize(lst, fd + 2);
|
||||
if (lst->items[fd].fd != -1) {
|
||||
uv_mutex_unlock(&global_epoll_lock);
|
||||
errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
lst->items[fd].fd = fd;
|
||||
lst->items[fd].events = event->events;
|
||||
lst->items[fd].revents = 0;
|
||||
} else if (op == EPOLL_CTL_MOD) {
|
||||
if (fd >= lst->size - 1 || lst->items[fd].fd == -1) {
|
||||
uv_mutex_unlock(&global_epoll_lock);
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
lst->items[fd].events = event->events;
|
||||
lst->items[fd].revents = 0;
|
||||
} else
|
||||
abort();
|
||||
|
||||
uv_mutex_unlock(&global_epoll_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define EP_MAX_PFDS (ULONG_MAX / sizeof(struct pollfd))
|
||||
#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
|
||||
|
||||
int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
|
||||
int maxevents, int timeout) {
|
||||
nmsgsfds_t size;
|
||||
struct pollfd* pfds;
|
||||
int pollret;
|
||||
int reventcount;
|
||||
int nevents;
|
||||
struct pollfd msg_fd;
|
||||
int i;
|
||||
|
||||
if (!lst || !lst->items || !events) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lst->size > EP_MAX_PFDS) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (maxevents <= 0 || maxevents > EP_MAX_EVENTS) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lst->size > 0)
|
||||
_SET_FDS_MSGS(size, 1, lst->size - 1);
|
||||
else
|
||||
_SET_FDS_MSGS(size, 0, 0);
|
||||
pfds = lst->items;
|
||||
pollret = poll(pfds, size, timeout);
|
||||
if (pollret <= 0)
|
||||
return pollret;
|
||||
|
||||
assert(lst->size > 0);
|
||||
|
||||
pollret = _NFDS(pollret) + _NMSGS(pollret);
|
||||
|
||||
reventcount = 0;
|
||||
nevents = 0;
|
||||
msg_fd = pfds[lst->size - 1];
|
||||
for (i = 0;
|
||||
i < lst->size && i < maxevents && reventcount < pollret; ++i) {
|
||||
struct epoll_event ev;
|
||||
struct pollfd* pfd;
|
||||
|
||||
pfd = &pfds[i];
|
||||
if (pfd->fd == -1 || pfd->revents == 0)
|
||||
continue;
|
||||
|
||||
ev.fd = pfd->fd;
|
||||
ev.events = pfd->revents;
|
||||
ev.is_msg = 0;
|
||||
if (pfd->revents & POLLIN && pfd->revents & POLLOUT)
|
||||
reventcount += 2;
|
||||
else if (pfd->revents & (POLLIN | POLLOUT))
|
||||
++reventcount;
|
||||
|
||||
pfd->revents = 0;
|
||||
events[nevents++] = ev;
|
||||
}
|
||||
|
||||
if (msg_fd.revents != 0 && msg_fd.fd != -1)
|
||||
if (i == lst->size)
|
||||
events[nevents - 1].is_msg = 1;
|
||||
|
||||
return nevents;
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
/* Remove epoll instance from global queue */
|
||||
uv_mutex_lock(&global_epoll_lock);
|
||||
QUEUE_REMOVE(&lst->member);
|
||||
uv_mutex_unlock(&global_epoll_lock);
|
||||
|
||||
/* Free resources */
|
||||
msgctl(lst->msg_queue, IPC_RMID, NULL);
|
||||
lst->msg_queue = -1;
|
||||
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 err;
|
||||
int rsn;
|
||||
|
||||
nano = (int)req->tv_nsec;
|
||||
seconds = req->tv_sec;
|
||||
events = CW_CONDVAR | CW_INTRPT;
|
||||
secrem = 0;
|
||||
nanorem = 0;
|
||||
|
||||
#if defined(_LP64)
|
||||
BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &err, &rsn);
|
||||
#else
|
||||
BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &err, &rsn);
|
||||
#endif
|
||||
|
||||
/* Don't clobber errno unless BPX1CTW/BPX4CTW errored.
|
||||
* Don't leak EAGAIN, that just means the timeout expired.
|
||||
*/
|
||||
if (rv == -1)
|
||||
if (err == EAGAIN)
|
||||
rv = 0;
|
||||
else
|
||||
errno = err;
|
||||
|
||||
if (rem != NULL && (rv == 0 || err == EINTR)) {
|
||||
rem->tv_nsec = nanorem;
|
||||
rem->tv_sec = secrem;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
ssize_t os390_readlink(const char* path, char* buf, size_t len) {
|
||||
ssize_t rlen;
|
||||
ssize_t vlen;
|
||||
ssize_t plen;
|
||||
char* delimiter;
|
||||
char old_delim;
|
||||
char* tmpbuf;
|
||||
char realpathstr[PATH_MAX + 1];
|
||||
|
||||
tmpbuf = uv__malloc(len + 1);
|
||||
if (tmpbuf == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rlen = readlink(path, tmpbuf, len);
|
||||
if (rlen < 0) {
|
||||
uv__free(tmpbuf);
|
||||
return rlen;
|
||||
}
|
||||
|
||||
if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) {
|
||||
/* Straightforward readlink. */
|
||||
memcpy(buf, tmpbuf, rlen);
|
||||
uv__free(tmpbuf);
|
||||
return rlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* There is a parmlib variable at the beginning
|
||||
* which needs interpretation.
|
||||
*/
|
||||
tmpbuf[rlen] = '\0';
|
||||
delimiter = strchr(tmpbuf + 2, '/');
|
||||
if (delimiter == NULL)
|
||||
/* No slash at the end */
|
||||
delimiter = strchr(tmpbuf + 2, '\0');
|
||||
|
||||
/* Read real path of the variable. */
|
||||
old_delim = *delimiter;
|
||||
*delimiter = '\0';
|
||||
if (realpath(tmpbuf, realpathstr) == NULL) {
|
||||
uv__free(tmpbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* realpathstr is not guaranteed to end with null byte.*/
|
||||
realpathstr[PATH_MAX] = '\0';
|
||||
|
||||
/* Reset the delimiter and fill up the buffer. */
|
||||
*delimiter = old_delim;
|
||||
plen = strlen(delimiter);
|
||||
vlen = strlen(realpathstr);
|
||||
rlen = plen + vlen;
|
||||
if (rlen > len) {
|
||||
uv__free(tmpbuf);
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
memcpy(buf, realpathstr, vlen);
|
||||
memcpy(buf + vlen, delimiter, plen);
|
||||
|
||||
/* Done using temporary buffer. */
|
||||
uv__free(tmpbuf);
|
||||
|
||||
return rlen;
|
||||
}
|
||||
|
||||
|
||||
size_t strnlen(const char* str, size_t maxlen) {
|
||||
char* p = memchr(str, 0, maxlen);
|
||||
if (p == NULL)
|
||||
return maxlen;
|
||||
else
|
||||
return p - str;
|
||||
}
|
||||
|
||||
|
||||
int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
int sem_destroy(UV_PLATFORM_SEM_T* semid) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
int sem_post(UV_PLATFORM_SEM_T* semid) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
int sem_trywait(UV_PLATFORM_SEM_T* semid) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
int sem_wait(UV_PLATFORM_SEM_T* semid) {
|
||||
UNREACHABLE();
|
||||
}
|
74
deps/libuv/src/unix/os390-syscalls.h
vendored
Normal file
74
deps/libuv/src/unix/os390-syscalls.h
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
/* 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
|
||||
|
||||
struct epoll_event {
|
||||
int events;
|
||||
int fd;
|
||||
int is_msg;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
QUEUE member;
|
||||
struct pollfd* items;
|
||||
unsigned long size;
|
||||
int msg_queue;
|
||||
} 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);
|
||||
ssize_t os390_readlink(const char* path, char* buf, size_t len);
|
||||
size_t strnlen(const char* str, size_t maxlen);
|
||||
int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value);
|
||||
int sem_destroy(UV_PLATFORM_SEM_T* semid);
|
||||
int sem_post(UV_PLATFORM_SEM_T* semid);
|
||||
int sem_trywait(UV_PLATFORM_SEM_T* semid);
|
||||
int sem_wait(UV_PLATFORM_SEM_T* semid);
|
||||
|
||||
#endif /* UV_OS390_SYSCALL_H_ */
|
975
deps/libuv/src/unix/os390.c
vendored
Normal file
975
deps/libuv/src/unix/os390.c
vendored
Normal file
@ -0,0 +1,975 @@
|
||||
/* 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 "internal.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <utmpx.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ps.h>
|
||||
#include <builtins.h>
|
||||
#include <termios.h>
|
||||
#include <sys/msg.h>
|
||||
#if defined(__clang__)
|
||||
#include "csrsic.h"
|
||||
#else
|
||||
#include "//'SYS1.SAMPLIB(CSRSIC)'"
|
||||
#endif
|
||||
|
||||
#define CVT_PTR 0x10
|
||||
#define PSA_PTR 0x00
|
||||
#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
|
||||
|
||||
/* Pointer to the home (current) ASCB. */
|
||||
#define PSAAOLD 0x224
|
||||
|
||||
/* Pointer to rsm address space block extension. */
|
||||
#define ASCBRSME 0x16C
|
||||
|
||||
/*
|
||||
NUMBER OF FRAMES CURRENTLY IN USE BY THIS ADDRESS SPACE.
|
||||
It does not include 2G frames.
|
||||
*/
|
||||
#define RAXFMCT 0x2C
|
||||
|
||||
/* Thread Entry constants */
|
||||
#define PGTH_CURRENT 1
|
||||
#define PGTH_LEN 26
|
||||
#define PGTHAPATH 0x20
|
||||
#pragma linkage(BPX4GTH, OS)
|
||||
#pragma linkage(BPX1GTH, OS)
|
||||
|
||||
/* TOD Clock resolution in nanoseconds */
|
||||
#define TOD_RES 4.096
|
||||
|
||||
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(0);
|
||||
loop->ep = ep;
|
||||
if (ep == NULL)
|
||||
return UV__ERR(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) {
|
||||
unsigned long long timestamp;
|
||||
__stckf(×tamp);
|
||||
/* Convert to nanoseconds */
|
||||
return timestamp / TOD_RES;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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 = (struct Output_path_type*) ((char*) (&Output_buf) +
|
||||
(Output_buf.Output_data.offsetPath & 0x00FFFFFF));
|
||||
|
||||
if (Output_path->len >= len) {
|
||||
errno = ENOBUFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uv__strscpy(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];
|
||||
int pid;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
pid = getpid();
|
||||
res = getexe(pid, args, sizeof(args));
|
||||
if (res < 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
return uv__search_path(args, buffer, size);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
char* ascb;
|
||||
char* rax;
|
||||
size_t nframes;
|
||||
|
||||
ascb = *(char* __ptr32 *)(PSA_PTR + PSAAOLD);
|
||||
rax = *(char* __ptr32 *)(ascb + ASCBRSME);
|
||||
nframes = *(unsigned int*)(rax + RAXFMCT);
|
||||
|
||||
*rss = nframes * sysconf(_SC_PAGESIZE);
|
||||
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 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 UV_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;
|
||||
}
|
||||
|
||||
|
||||
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 UV__ERR(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 UV__ERR(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 UV_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;
|
||||
memset(address->phys_addr, 0, sizeof(address->phys_addr));
|
||||
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;
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
/* get the ipv6 addresses first */
|
||||
uv_interface_address_t* addresses_v6;
|
||||
uv__interface_addresses_v6(&addresses_v6, &count_v6);
|
||||
|
||||
/* now get the ipv4 addresses */
|
||||
|
||||
/* Assume maximum buffer size allowable */
|
||||
maxsize = 16384;
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||
if (0 > sockfd)
|
||||
return UV__ERR(errno);
|
||||
|
||||
ifc.ifc_req = uv__calloc(1, maxsize);
|
||||
ifc.ifc_len = maxsize;
|
||||
if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
|
||||
uv__close(sockfd);
|
||||
return UV__ERR(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 UV__ERR(errno);
|
||||
}
|
||||
|
||||
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
|
||||
continue;
|
||||
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
if (*count == 0) {
|
||||
uv__close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Alloc the return interface structs */
|
||||
*addresses = uv__malloc((*count + count_v6) *
|
||||
sizeof(uv_interface_address_t));
|
||||
|
||||
if (!(*addresses)) {
|
||||
uv__close(sockfd);
|
||||
return UV_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 UV_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;
|
||||
memset(address->phys_addr, 0, sizeof(address->phys_addr));
|
||||
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);
|
||||
assert(fd >= 0);
|
||||
|
||||
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, EPOLL_CTL_DEL, fd, &dummy);
|
||||
}
|
||||
|
||||
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
struct pollfd p[1];
|
||||
int rv;
|
||||
|
||||
p[0].fd = fd;
|
||||
p[0].events = POLLIN;
|
||||
|
||||
do
|
||||
rv = poll(p, 1, 0);
|
||||
while (rv == -1 && errno == EINTR);
|
||||
|
||||
if (rv == -1)
|
||||
abort();
|
||||
|
||||
if (p[0].revents & POLLNVAL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__fs_event_close(uv_fs_event_t* handle) {
|
||||
uv_fs_event_stop(handle);
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
|
||||
const char* filename, unsigned int flags) {
|
||||
uv__os390_epoll* ep;
|
||||
_RFIS reg_struct;
|
||||
char* path;
|
||||
int rc;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
return UV_EINVAL;
|
||||
|
||||
ep = handle->loop->ep;
|
||||
assert(ep->msg_queue != -1);
|
||||
|
||||
reg_struct.__rfis_cmd = _RFIS_REG;
|
||||
reg_struct.__rfis_qid = ep->msg_queue;
|
||||
reg_struct.__rfis_type = 1;
|
||||
memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle));
|
||||
|
||||
path = uv__strdup(filename);
|
||||
if (path == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct);
|
||||
if (rc != 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
uv__handle_start(handle);
|
||||
handle->path = path;
|
||||
handle->cb = cb;
|
||||
memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok,
|
||||
sizeof(handle->rfis_rftok));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
uv__os390_epoll* ep;
|
||||
_RFIS reg_struct;
|
||||
int rc;
|
||||
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
ep = handle->loop->ep;
|
||||
assert(ep->msg_queue != -1);
|
||||
|
||||
reg_struct.__rfis_cmd = _RFIS_UNREG;
|
||||
reg_struct.__rfis_qid = ep->msg_queue;
|
||||
reg_struct.__rfis_type = 1;
|
||||
memcpy(reg_struct.__rfis_rftok, handle->rfis_rftok,
|
||||
sizeof(handle->rfis_rftok));
|
||||
|
||||
/*
|
||||
* This call will take "/" as the path argument in case we
|
||||
* don't care to supply the correct path. The system will simply
|
||||
* ignore it.
|
||||
*/
|
||||
rc = __w_pioctl("/", _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct);
|
||||
if (rc != 0 && errno != EALREADY && errno != ENOENT)
|
||||
abort();
|
||||
|
||||
uv__handle_stop(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int os390_message_queue_handler(uv__os390_epoll* ep) {
|
||||
uv_fs_event_t* handle;
|
||||
int msglen;
|
||||
int events;
|
||||
_RFIM msg;
|
||||
|
||||
if (ep->msg_queue == -1)
|
||||
return 0;
|
||||
|
||||
msglen = msgrcv(ep->msg_queue, &msg, sizeof(msg), 0, IPC_NOWAIT);
|
||||
|
||||
if (msglen == -1 && errno == ENOMSG)
|
||||
return 0;
|
||||
|
||||
if (msglen == -1)
|
||||
abort();
|
||||
|
||||
events = 0;
|
||||
if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE)
|
||||
events = UV_CHANGE;
|
||||
else if (msg.__rfim_event == _RFIM_RENAME)
|
||||
events = UV_RENAME;
|
||||
else
|
||||
/* Some event that we are not interested in. */
|
||||
return 0;
|
||||
|
||||
handle = *(uv_fs_event_t**)(msg.__rfim_utok);
|
||||
handle->cb(handle, uv__basename_r(handle->path), events, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
uv__os390_epoll* ep;
|
||||
int real_timeout;
|
||||
QUEUE* q;
|
||||
uv__io_t* w;
|
||||
uint64_t base;
|
||||
int count;
|
||||
int nfds;
|
||||
int fd;
|
||||
int op;
|
||||
int i;
|
||||
int user_timeout;
|
||||
int reset_timeout;
|
||||
|
||||
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 = EPOLL_CTL_ADD;
|
||||
else
|
||||
op = 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 == EPOLL_CTL_ADD);
|
||||
|
||||
/* We've reactivated a file descriptor that's been watched before. */
|
||||
if (epoll_ctl(loop->ep, 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;
|
||||
|
||||
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
|
||||
reset_timeout = 1;
|
||||
user_timeout = timeout;
|
||||
timeout = 0;
|
||||
} else {
|
||||
reset_timeout = 0;
|
||||
}
|
||||
|
||||
nfds = 0;
|
||||
for (;;) {
|
||||
/* Only need to set the provider_entry_time if timeout != 0. The function
|
||||
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
|
||||
*/
|
||||
if (timeout != 0)
|
||||
uv__metrics_set_provider_entry_time(loop);
|
||||
|
||||
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);
|
||||
|
||||
if (reset_timeout != 0) {
|
||||
timeout = user_timeout;
|
||||
reset_timeout = 0;
|
||||
}
|
||||
|
||||
if (timeout == -1)
|
||||
continue;
|
||||
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
/* We may have been inside the system call for longer than |timeout|
|
||||
* milliseconds so we need to update the timestamp to avoid drift.
|
||||
*/
|
||||
goto update_timeout;
|
||||
}
|
||||
|
||||
if (nfds == -1) {
|
||||
|
||||
if (errno != EINTR)
|
||||
abort();
|
||||
|
||||
if (reset_timeout != 0) {
|
||||
timeout = user_timeout;
|
||||
reset_timeout = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
ep = loop->ep;
|
||||
if (pe->is_msg) {
|
||||
os390_message_queue_handler(ep);
|
||||
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, 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) {
|
||||
uv__metrics_update_idle_time(loop);
|
||||
w->cb(loop, w, pe->events);
|
||||
nevents++;
|
||||
}
|
||||
}
|
||||
loop->watchers[loop->nwatchers] = NULL;
|
||||
loop->watchers[loop->nwatchers + 1] = NULL;
|
||||
|
||||
if (reset_timeout != 0) {
|
||||
timeout = user_timeout;
|
||||
reset_timeout = 0;
|
||||
}
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
int uv__io_fork(uv_loop_t* loop) {
|
||||
/*
|
||||
Nullify the msg queue but don't close it because
|
||||
it is still being used by the parent.
|
||||
*/
|
||||
loop->ep = NULL;
|
||||
|
||||
uv__platform_loop_delete(loop);
|
||||
return uv__platform_loop_init(loop);
|
||||
}
|
381
deps/libuv/src/unix/pipe.c
vendored
Normal file
381
deps/libuv/src/unix/pipe.c
vendored
Normal file
@ -0,0 +1,381 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
|
||||
uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
|
||||
handle->shutdown_req = NULL;
|
||||
handle->connect_req = NULL;
|
||||
handle->pipe_fname = NULL;
|
||||
handle->ipc = ipc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
struct sockaddr_un saddr;
|
||||
const char* pipe_fname;
|
||||
int sockfd;
|
||||
int err;
|
||||
|
||||
pipe_fname = NULL;
|
||||
|
||||
/* Already bound? */
|
||||
if (uv__stream_fd(handle) >= 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Make a copy of the file name, it outlives this function's scope. */
|
||||
pipe_fname = uv__strdup(name);
|
||||
if (pipe_fname == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
/* We've got a copy, don't touch the original any more. */
|
||||
name = NULL;
|
||||
|
||||
err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (err < 0)
|
||||
goto err_socket;
|
||||
sockfd = err;
|
||||
|
||||
memset(&saddr, 0, sizeof saddr);
|
||||
uv__strscpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path));
|
||||
saddr.sun_family = AF_UNIX;
|
||||
|
||||
if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
|
||||
err = UV__ERR(errno);
|
||||
/* Convert ENOENT to EACCES for compatibility with Windows. */
|
||||
if (err == UV_ENOENT)
|
||||
err = UV_EACCES;
|
||||
|
||||
uv__close(sockfd);
|
||||
goto err_socket;
|
||||
}
|
||||
|
||||
/* Success. */
|
||||
handle->flags |= UV_HANDLE_BOUND;
|
||||
handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */
|
||||
handle->io_watcher.fd = sockfd;
|
||||
return 0;
|
||||
|
||||
err_socket:
|
||||
uv__free((void*)pipe_fname);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
||||
if (uv__stream_fd(handle) == -1)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (handle->ipc)
|
||||
return UV_EINVAL;
|
||||
|
||||
#if defined(__MVS__) || defined(__PASE__)
|
||||
/* On zOS, backlog=0 has undefined behaviour */
|
||||
/* On IBMi PASE, backlog=0 leads to "Connection refused" error */
|
||||
if (backlog == 0)
|
||||
backlog = 1;
|
||||
else if (backlog < 0)
|
||||
backlog = SOMAXCONN;
|
||||
#endif
|
||||
|
||||
if (listen(uv__stream_fd(handle), backlog))
|
||||
return UV__ERR(errno);
|
||||
|
||||
handle->connection_cb = cb;
|
||||
handle->io_watcher.cb = uv__server_io;
|
||||
uv__io_start(handle->loop, &handle->io_watcher, POLLIN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__pipe_close(uv_pipe_t* handle) {
|
||||
if (handle->pipe_fname) {
|
||||
/*
|
||||
* Unlink the file system entity before closing the file descriptor.
|
||||
* Doing it the other way around introduces a race where our process
|
||||
* unlinks a socket with the same name that's just been created by
|
||||
* another thread or process.
|
||||
*/
|
||||
unlink(handle->pipe_fname);
|
||||
uv__free((void*)handle->pipe_fname);
|
||||
handle->pipe_fname = NULL;
|
||||
}
|
||||
|
||||
uv__stream_close((uv_stream_t*)handle);
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
|
||||
int flags;
|
||||
int mode;
|
||||
int err;
|
||||
flags = 0;
|
||||
|
||||
if (uv__fd_exists(handle->loop, fd))
|
||||
return UV_EEXIST;
|
||||
|
||||
do
|
||||
mode = fcntl(fd, F_GETFL);
|
||||
while (mode == -1 && errno == EINTR);
|
||||
|
||||
if (mode == -1)
|
||||
return UV__ERR(errno); /* according to docs, must be EBADF */
|
||||
|
||||
err = uv__nonblock(fd, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
err = uv__stream_try_select((uv_stream_t*) handle, &fd);
|
||||
if (err)
|
||||
return err;
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
mode &= O_ACCMODE;
|
||||
if (mode != O_WRONLY)
|
||||
flags |= UV_HANDLE_READABLE;
|
||||
if (mode != O_RDONLY)
|
||||
flags |= UV_HANDLE_WRITABLE;
|
||||
|
||||
return uv__stream_open((uv_stream_t*)handle, fd, flags);
|
||||
}
|
||||
|
||||
|
||||
void uv_pipe_connect(uv_connect_t* req,
|
||||
uv_pipe_t* handle,
|
||||
const char* name,
|
||||
uv_connect_cb cb) {
|
||||
struct sockaddr_un saddr;
|
||||
int new_sock;
|
||||
int err;
|
||||
int r;
|
||||
|
||||
new_sock = (uv__stream_fd(handle) == -1);
|
||||
|
||||
if (new_sock) {
|
||||
err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
handle->io_watcher.fd = err;
|
||||
}
|
||||
|
||||
memset(&saddr, 0, sizeof saddr);
|
||||
uv__strscpy(saddr.sun_path, name, sizeof(saddr.sun_path));
|
||||
saddr.sun_family = AF_UNIX;
|
||||
|
||||
do {
|
||||
r = connect(uv__stream_fd(handle),
|
||||
(struct sockaddr*)&saddr, sizeof saddr);
|
||||
}
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r == -1 && errno != EINPROGRESS) {
|
||||
err = UV__ERR(errno);
|
||||
#if defined(__CYGWIN__) || defined(__MSYS__)
|
||||
/* EBADF is supposed to mean that the socket fd is bad, but
|
||||
Cygwin reports EBADF instead of ENOTSOCK when the file is
|
||||
not a socket. We do not expect to see a bad fd here
|
||||
(e.g. due to new_sock), so translate the error. */
|
||||
if (err == UV_EBADF)
|
||||
err = UV_ENOTSOCK;
|
||||
#endif
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
if (new_sock) {
|
||||
err = uv__stream_open((uv_stream_t*)handle,
|
||||
uv__stream_fd(handle),
|
||||
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
}
|
||||
|
||||
if (err == 0)
|
||||
uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
|
||||
|
||||
out:
|
||||
handle->delayed_error = err;
|
||||
handle->connect_req = req;
|
||||
|
||||
uv__req_init(handle->loop, req, UV_CONNECT);
|
||||
req->handle = (uv_stream_t*)handle;
|
||||
req->cb = cb;
|
||||
QUEUE_INIT(&req->queue);
|
||||
|
||||
/* Force callback to run on next tick in case of error. */
|
||||
if (err)
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
||||
uv__peersockfunc func,
|
||||
char* buffer,
|
||||
size_t* size) {
|
||||
struct sockaddr_un sa;
|
||||
socklen_t addrlen;
|
||||
int err;
|
||||
|
||||
addrlen = sizeof(sa);
|
||||
memset(&sa, 0, addrlen);
|
||||
err = uv__getsockpeername((const uv_handle_t*) handle,
|
||||
func,
|
||||
(struct sockaddr*) &sa,
|
||||
(int*) &addrlen);
|
||||
if (err < 0) {
|
||||
*size = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
if (sa.sun_path[0] == 0)
|
||||
/* Linux abstract namespace */
|
||||
addrlen -= offsetof(struct sockaddr_un, sun_path);
|
||||
else
|
||||
#endif
|
||||
addrlen = strlen(sa.sun_path);
|
||||
|
||||
|
||||
if ((size_t)addrlen >= *size) {
|
||||
*size = addrlen + 1;
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, sa.sun_path, addrlen);
|
||||
*size = addrlen;
|
||||
|
||||
/* only null-terminate if it's not an abstract socket */
|
||||
if (buffer[0] != '\0')
|
||||
buffer[addrlen] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
|
||||
return uv__pipe_getsockpeername(handle, getsockname, buffer, size);
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
|
||||
return uv__pipe_getsockpeername(handle, getpeername, buffer, size);
|
||||
}
|
||||
|
||||
|
||||
void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_pending_count(uv_pipe_t* handle) {
|
||||
uv__stream_queued_fds_t* queued_fds;
|
||||
|
||||
if (!handle->ipc)
|
||||
return 0;
|
||||
|
||||
if (handle->accepted_fd == -1)
|
||||
return 0;
|
||||
|
||||
if (handle->queued_fds == NULL)
|
||||
return 1;
|
||||
|
||||
queued_fds = handle->queued_fds;
|
||||
return queued_fds->offset + 1;
|
||||
}
|
||||
|
||||
|
||||
uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
|
||||
if (!handle->ipc)
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
if (handle->accepted_fd == -1)
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
else
|
||||
return uv__handle_type(handle->accepted_fd);
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
|
||||
unsigned desired_mode;
|
||||
struct stat pipe_stat;
|
||||
char* name_buffer;
|
||||
size_t name_len;
|
||||
int r;
|
||||
|
||||
if (handle == NULL || uv__stream_fd(handle) == -1)
|
||||
return UV_EBADF;
|
||||
|
||||
if (mode != UV_READABLE &&
|
||||
mode != UV_WRITABLE &&
|
||||
mode != (UV_WRITABLE | UV_READABLE))
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Unfortunately fchmod does not work on all platforms, we will use chmod. */
|
||||
name_len = 0;
|
||||
r = uv_pipe_getsockname(handle, NULL, &name_len);
|
||||
if (r != UV_ENOBUFS)
|
||||
return r;
|
||||
|
||||
name_buffer = uv__malloc(name_len);
|
||||
if (name_buffer == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
r = uv_pipe_getsockname(handle, name_buffer, &name_len);
|
||||
if (r != 0) {
|
||||
uv__free(name_buffer);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* stat must be used as fstat has a bug on Darwin */
|
||||
if (stat(name_buffer, &pipe_stat) == -1) {
|
||||
uv__free(name_buffer);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
desired_mode = 0;
|
||||
if (mode & UV_READABLE)
|
||||
desired_mode |= S_IRUSR | S_IRGRP | S_IROTH;
|
||||
if (mode & UV_WRITABLE)
|
||||
desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
|
||||
|
||||
/* Exit early if pipe already has desired mode. */
|
||||
if ((pipe_stat.st_mode & desired_mode) == desired_mode) {
|
||||
uv__free(name_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pipe_stat.st_mode |= desired_mode;
|
||||
|
||||
r = chmod(name_buffer, pipe_stat.st_mode);
|
||||
uv__free(name_buffer);
|
||||
|
||||
return r != -1 ? 0 : UV__ERR(errno);
|
||||
}
|
150
deps/libuv/src/unix/poll.c
vendored
Normal file
150
deps/libuv/src/unix/poll.c
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
uv_poll_t* handle;
|
||||
int pevents;
|
||||
|
||||
handle = container_of(w, uv_poll_t, io_watcher);
|
||||
|
||||
/*
|
||||
* As documented in the kernel source fs/kernfs/file.c #780
|
||||
* poll will return POLLERR|POLLPRI in case of sysfs
|
||||
* polling. This does not happen in case of out-of-band
|
||||
* TCP messages.
|
||||
*
|
||||
* The above is the case on (at least) FreeBSD and Linux.
|
||||
*
|
||||
* So to properly determine a POLLPRI or a POLLERR we need
|
||||
* to check for both.
|
||||
*/
|
||||
if ((events & POLLERR) && !(events & UV__POLLPRI)) {
|
||||
uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
|
||||
uv__handle_stop(handle);
|
||||
handle->poll_cb(handle, UV_EBADF, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
pevents = 0;
|
||||
if (events & POLLIN)
|
||||
pevents |= UV_READABLE;
|
||||
if (events & UV__POLLPRI)
|
||||
pevents |= UV_PRIORITIZED;
|
||||
if (events & POLLOUT)
|
||||
pevents |= UV_WRITABLE;
|
||||
if (events & UV__POLLRDHUP)
|
||||
pevents |= UV_DISCONNECT;
|
||||
|
||||
handle->poll_cb(handle, 0, pevents);
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
|
||||
int err;
|
||||
|
||||
if (uv__fd_exists(loop, fd))
|
||||
return UV_EEXIST;
|
||||
|
||||
err = uv__io_check_fd(loop, fd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* If ioctl(FIONBIO) reports ENOTTY, try fcntl(F_GETFL) + fcntl(F_SETFL).
|
||||
* Workaround for e.g. kqueue fds not supporting ioctls.
|
||||
*/
|
||||
err = uv__nonblock(fd, 1);
|
||||
if (err == UV_ENOTTY)
|
||||
if (uv__nonblock == uv__nonblock_ioctl)
|
||||
err = uv__nonblock_fcntl(fd, 1);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
|
||||
uv__io_init(&handle->io_watcher, uv__poll_io, fd);
|
||||
handle->poll_cb = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
|
||||
uv_os_sock_t socket) {
|
||||
return uv_poll_init(loop, handle, socket);
|
||||
}
|
||||
|
||||
|
||||
static void uv__poll_stop(uv_poll_t* handle) {
|
||||
uv__io_stop(handle->loop,
|
||||
&handle->io_watcher,
|
||||
POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
|
||||
uv__handle_stop(handle);
|
||||
uv__platform_invalidate_fd(handle->loop, handle->io_watcher.fd);
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_stop(uv_poll_t* handle) {
|
||||
assert(!uv__is_closing(handle));
|
||||
uv__poll_stop(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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 |
|
||||
UV_PRIORITIZED)) == 0);
|
||||
assert(!uv__is_closing(handle));
|
||||
|
||||
uv__poll_stop(handle);
|
||||
|
||||
if (pevents == 0)
|
||||
return 0;
|
||||
|
||||
events = 0;
|
||||
if (pevents & UV_READABLE)
|
||||
events |= POLLIN;
|
||||
if (pevents & UV_PRIORITIZED)
|
||||
events |= UV__POLLPRI;
|
||||
if (pevents & UV_WRITABLE)
|
||||
events |= POLLOUT;
|
||||
if (pevents & UV_DISCONNECT)
|
||||
events |= UV__POLLRDHUP;
|
||||
|
||||
uv__io_start(handle->loop, &handle->io_watcher, events);
|
||||
uv__handle_start(handle);
|
||||
handle->poll_cb = poll_cb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__poll_close(uv_poll_t* handle) {
|
||||
uv__poll_stop(handle);
|
||||
}
|
35
deps/libuv/src/unix/posix-hrtime.c
vendored
Normal file
35
deps/libuv/src/unix/posix-hrtime.c
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
/* 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#undef NANOSEC
|
||||
#define NANOSEC ((uint64_t) 1e9)
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
|
||||
}
|
374
deps/libuv/src/unix/posix-poll.c
vendored
Normal file
374
deps/libuv/src/unix/posix-poll.c
vendored
Normal file
@ -0,0 +1,374 @@
|
||||
/* 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* POSIX defines poll() as a portable way to wait on file descriptors.
|
||||
* Here we maintain a dynamically sized array of file descriptors and
|
||||
* events to pass as the first argument to poll().
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
loop->poll_fds = NULL;
|
||||
loop->poll_fds_used = 0;
|
||||
loop->poll_fds_size = 0;
|
||||
loop->poll_fds_iterating = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
uv__free(loop->poll_fds);
|
||||
loop->poll_fds = NULL;
|
||||
}
|
||||
|
||||
int uv__io_fork(uv_loop_t* loop) {
|
||||
uv__platform_loop_delete(loop);
|
||||
return uv__platform_loop_init(loop);
|
||||
}
|
||||
|
||||
/* Allocate or dynamically resize our poll fds array. */
|
||||
static void uv__pollfds_maybe_resize(uv_loop_t* loop) {
|
||||
size_t i;
|
||||
size_t n;
|
||||
struct pollfd* p;
|
||||
|
||||
if (loop->poll_fds_used < loop->poll_fds_size)
|
||||
return;
|
||||
|
||||
n = loop->poll_fds_size ? loop->poll_fds_size * 2 : 64;
|
||||
p = uv__reallocf(loop->poll_fds, n * sizeof(*loop->poll_fds));
|
||||
if (p == NULL)
|
||||
abort();
|
||||
|
||||
loop->poll_fds = p;
|
||||
for (i = loop->poll_fds_size; i < n; i++) {
|
||||
loop->poll_fds[i].fd = -1;
|
||||
loop->poll_fds[i].events = 0;
|
||||
loop->poll_fds[i].revents = 0;
|
||||
}
|
||||
loop->poll_fds_size = n;
|
||||
}
|
||||
|
||||
/* Primitive swap operation on poll fds array elements. */
|
||||
static void uv__pollfds_swap(uv_loop_t* loop, size_t l, size_t r) {
|
||||
struct pollfd pfd;
|
||||
pfd = loop->poll_fds[l];
|
||||
loop->poll_fds[l] = loop->poll_fds[r];
|
||||
loop->poll_fds[r] = pfd;
|
||||
}
|
||||
|
||||
/* Add a watcher's fd to our poll fds array with its pending events. */
|
||||
static void uv__pollfds_add(uv_loop_t* loop, uv__io_t* w) {
|
||||
size_t i;
|
||||
struct pollfd* pe;
|
||||
|
||||
/* If the fd is already in the set just update its events. */
|
||||
assert(!loop->poll_fds_iterating);
|
||||
for (i = 0; i < loop->poll_fds_used; ++i) {
|
||||
if (loop->poll_fds[i].fd == w->fd) {
|
||||
loop->poll_fds[i].events = w->pevents;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, allocate a new slot in the set for the fd. */
|
||||
uv__pollfds_maybe_resize(loop);
|
||||
pe = &loop->poll_fds[loop->poll_fds_used++];
|
||||
pe->fd = w->fd;
|
||||
pe->events = w->pevents;
|
||||
}
|
||||
|
||||
/* Remove a watcher's fd from our poll fds array. */
|
||||
static void uv__pollfds_del(uv_loop_t* loop, int fd) {
|
||||
size_t i;
|
||||
assert(!loop->poll_fds_iterating);
|
||||
for (i = 0; i < loop->poll_fds_used;) {
|
||||
if (loop->poll_fds[i].fd == fd) {
|
||||
/* swap to last position and remove */
|
||||
--loop->poll_fds_used;
|
||||
uv__pollfds_swap(loop, i, loop->poll_fds_used);
|
||||
loop->poll_fds[loop->poll_fds_used].fd = -1;
|
||||
loop->poll_fds[loop->poll_fds_used].events = 0;
|
||||
loop->poll_fds[loop->poll_fds_used].revents = 0;
|
||||
/* This method is called with an fd of -1 to purge the invalidated fds,
|
||||
* so we may possibly have multiples to remove.
|
||||
*/
|
||||
if (-1 != fd)
|
||||
return;
|
||||
} else {
|
||||
/* We must only increment the loop counter when the fds do not match.
|
||||
* Otherwise, when we are purging an invalidated fd, the value just
|
||||
* swapped here from the previous end of the array will be skipped.
|
||||
*/
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
sigset_t* pset;
|
||||
sigset_t set;
|
||||
uint64_t time_base;
|
||||
uint64_t time_diff;
|
||||
QUEUE* q;
|
||||
uv__io_t* w;
|
||||
size_t i;
|
||||
unsigned int nevents;
|
||||
int nfds;
|
||||
int have_signals;
|
||||
struct pollfd* pe;
|
||||
int fd;
|
||||
int user_timeout;
|
||||
int reset_timeout;
|
||||
|
||||
if (loop->nfds == 0) {
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Take queued watchers and add their fds to our poll fds array. */
|
||||
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
|
||||
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);
|
||||
assert(w->fd < (int) loop->nwatchers);
|
||||
|
||||
uv__pollfds_add(loop, w);
|
||||
|
||||
w->events = w->pevents;
|
||||
}
|
||||
|
||||
/* Prepare a set of signals to block around poll(), if any. */
|
||||
pset = NULL;
|
||||
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
|
||||
pset = &set;
|
||||
sigemptyset(pset);
|
||||
sigaddset(pset, SIGPROF);
|
||||
}
|
||||
|
||||
assert(timeout >= -1);
|
||||
time_base = loop->time;
|
||||
|
||||
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
|
||||
reset_timeout = 1;
|
||||
user_timeout = timeout;
|
||||
timeout = 0;
|
||||
} else {
|
||||
reset_timeout = 0;
|
||||
}
|
||||
|
||||
/* Loop calls to poll() and processing of results. If we get some
|
||||
* results from poll() but they turn out not to be interesting to
|
||||
* our caller then we need to loop around and poll() again.
|
||||
*/
|
||||
for (;;) {
|
||||
/* Only need to set the provider_entry_time if timeout != 0. The function
|
||||
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
|
||||
*/
|
||||
if (timeout != 0)
|
||||
uv__metrics_set_provider_entry_time(loop);
|
||||
|
||||
if (pset != NULL)
|
||||
if (pthread_sigmask(SIG_BLOCK, pset, NULL))
|
||||
abort();
|
||||
nfds = poll(loop->poll_fds, (nfds_t)loop->poll_fds_used, timeout);
|
||||
if (pset != NULL)
|
||||
if (pthread_sigmask(SIG_UNBLOCK, pset, NULL))
|
||||
abort();
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
SAVE_ERRNO(uv__update_time(loop));
|
||||
|
||||
if (nfds == 0) {
|
||||
if (reset_timeout != 0) {
|
||||
timeout = user_timeout;
|
||||
reset_timeout = 0;
|
||||
if (timeout == -1)
|
||||
continue;
|
||||
if (timeout > 0)
|
||||
goto update_timeout;
|
||||
}
|
||||
|
||||
assert(timeout != -1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nfds == -1) {
|
||||
if (errno != EINTR)
|
||||
abort();
|
||||
|
||||
if (reset_timeout != 0) {
|
||||
timeout = user_timeout;
|
||||
reset_timeout = 0;
|
||||
}
|
||||
|
||||
if (timeout == -1)
|
||||
continue;
|
||||
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
/* Interrupted by a signal. Update timeout and poll again. */
|
||||
goto update_timeout;
|
||||
}
|
||||
|
||||
/* Tell uv__platform_invalidate_fd not to manipulate our array
|
||||
* while we are iterating over it.
|
||||
*/
|
||||
loop->poll_fds_iterating = 1;
|
||||
|
||||
/* Initialize a count of events that we care about. */
|
||||
nevents = 0;
|
||||
have_signals = 0;
|
||||
|
||||
/* Loop over the entire poll fds array looking for returned events. */
|
||||
for (i = 0; i < loop->poll_fds_used; i++) {
|
||||
pe = loop->poll_fds + 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, ignore. */
|
||||
uv__platform_invalidate_fd(loop, fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Filter out events that user has not requested us to watch
|
||||
* (e.g. POLLNVAL).
|
||||
*/
|
||||
pe->revents &= w->pevents | POLLERR | POLLHUP;
|
||||
|
||||
if (pe->revents != 0) {
|
||||
/* Run signal watchers last. */
|
||||
if (w == &loop->signal_io_watcher) {
|
||||
have_signals = 1;
|
||||
} else {
|
||||
uv__metrics_update_idle_time(loop);
|
||||
w->cb(loop, w, pe->revents);
|
||||
}
|
||||
|
||||
nevents++;
|
||||
}
|
||||
}
|
||||
|
||||
if (reset_timeout != 0) {
|
||||
timeout = user_timeout;
|
||||
reset_timeout = 0;
|
||||
}
|
||||
|
||||
if (have_signals != 0) {
|
||||
uv__metrics_update_idle_time(loop);
|
||||
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
|
||||
}
|
||||
|
||||
loop->poll_fds_iterating = 0;
|
||||
|
||||
/* Purge invalidated fds from our poll fds array. */
|
||||
uv__pollfds_del(loop, -1);
|
||||
|
||||
if (have_signals != 0)
|
||||
return; /* Event loop should cycle now so don't poll again. */
|
||||
|
||||
if (nevents != 0)
|
||||
return;
|
||||
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
if (timeout == -1)
|
||||
continue;
|
||||
|
||||
update_timeout:
|
||||
assert(timeout > 0);
|
||||
|
||||
time_diff = loop->time - time_base;
|
||||
if (time_diff >= (uint64_t) timeout)
|
||||
return;
|
||||
|
||||
timeout -= time_diff;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove the given fd from our poll fds array because no one
|
||||
* is interested in its events anymore.
|
||||
*/
|
||||
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
size_t i;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
if (loop->poll_fds_iterating) {
|
||||
/* uv__io_poll is currently iterating. Just invalidate fd. */
|
||||
for (i = 0; i < loop->poll_fds_used; i++)
|
||||
if (loop->poll_fds[i].fd == fd) {
|
||||
loop->poll_fds[i].fd = -1;
|
||||
loop->poll_fds[i].events = 0;
|
||||
loop->poll_fds[i].revents = 0;
|
||||
}
|
||||
} else {
|
||||
/* uv__io_poll is not iterating. Delete fd from the set. */
|
||||
uv__pollfds_del(loop, fd);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether the given fd is supported by poll(). */
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
struct pollfd p[1];
|
||||
int rv;
|
||||
|
||||
p[0].fd = fd;
|
||||
p[0].events = POLLIN;
|
||||
|
||||
do
|
||||
rv = poll(p, 1, 0);
|
||||
while (rv == -1 && (errno == EINTR || errno == EAGAIN));
|
||||
|
||||
if (rv == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (p[0].revents & POLLNVAL)
|
||||
return UV_EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
595
deps/libuv/src/unix/process.c
vendored
Normal file
595
deps/libuv/src/unix/process.c
vendored
Normal file
@ -0,0 +1,595 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
|
||||
#if defined(__APPLE__) && !TARGET_OS_IPHONE
|
||||
# include <crt_externs.h>
|
||||
# define environ (*_NSGetEnviron())
|
||||
#else
|
||||
extern char **environ;
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__GLIBC__)
|
||||
# include <grp.h>
|
||||
#endif
|
||||
|
||||
|
||||
static void uv__chld(uv_signal_t* handle, int signum) {
|
||||
uv_process_t* process;
|
||||
uv_loop_t* loop;
|
||||
int exit_status;
|
||||
int term_signal;
|
||||
int status;
|
||||
pid_t pid;
|
||||
QUEUE pending;
|
||||
QUEUE* q;
|
||||
QUEUE* h;
|
||||
|
||||
assert(signum == SIGCHLD);
|
||||
|
||||
QUEUE_INIT(&pending);
|
||||
loop = handle->loop;
|
||||
|
||||
h = &loop->process_handles;
|
||||
q = QUEUE_HEAD(h);
|
||||
while (q != h) {
|
||||
process = QUEUE_DATA(q, uv_process_t, queue);
|
||||
q = QUEUE_NEXT(q);
|
||||
|
||||
do
|
||||
pid = waitpid(process->pid, &status, WNOHANG);
|
||||
while (pid == -1 && errno == EINTR);
|
||||
|
||||
if (pid == 0)
|
||||
continue;
|
||||
|
||||
if (pid == -1) {
|
||||
if (errno != ECHILD)
|
||||
abort();
|
||||
continue;
|
||||
}
|
||||
|
||||
process->status = status;
|
||||
QUEUE_REMOVE(&process->queue);
|
||||
QUEUE_INSERT_TAIL(&pending, &process->queue);
|
||||
}
|
||||
|
||||
h = &pending;
|
||||
q = QUEUE_HEAD(h);
|
||||
while (q != h) {
|
||||
process = QUEUE_DATA(q, uv_process_t, queue);
|
||||
q = QUEUE_NEXT(q);
|
||||
|
||||
QUEUE_REMOVE(&process->queue);
|
||||
QUEUE_INIT(&process->queue);
|
||||
uv__handle_stop(process);
|
||||
|
||||
if (process->exit_cb == NULL)
|
||||
continue;
|
||||
|
||||
exit_status = 0;
|
||||
if (WIFEXITED(process->status))
|
||||
exit_status = WEXITSTATUS(process->status);
|
||||
|
||||
term_signal = 0;
|
||||
if (WIFSIGNALED(process->status))
|
||||
term_signal = WTERMSIG(process->status);
|
||||
|
||||
process->exit_cb(process, exit_status, term_signal);
|
||||
}
|
||||
assert(QUEUE_EMPTY(&pending));
|
||||
}
|
||||
|
||||
|
||||
static int uv__make_socketpair(int fds[2]) {
|
||||
#if defined(__FreeBSD__) || defined(__linux__)
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
int err;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
|
||||
return UV__ERR(errno);
|
||||
|
||||
err = uv__cloexec(fds[0], 1);
|
||||
if (err == 0)
|
||||
err = uv__cloexec(fds[1], 1);
|
||||
|
||||
if (err != 0) {
|
||||
uv__close(fds[0]);
|
||||
uv__close(fds[1]);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__make_pipe(int fds[2], int flags) {
|
||||
#if defined(__FreeBSD__) || defined(__linux__)
|
||||
if (pipe2(fds, flags | O_CLOEXEC))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
if (pipe(fds))
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (uv__cloexec(fds[0], 1))
|
||||
goto fail;
|
||||
|
||||
if (uv__cloexec(fds[1], 1))
|
||||
goto fail;
|
||||
|
||||
if (flags & UV__F_NONBLOCK) {
|
||||
if (uv__nonblock(fds[0], 1))
|
||||
goto fail;
|
||||
|
||||
if (uv__nonblock(fds[1], 1))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
uv__close(fds[0]);
|
||||
uv__close(fds[1]);
|
||||
return UV__ERR(errno);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Used for initializing stdio streams like options.stdin_stream. Returns
|
||||
* zero on success. See also the cleanup section in uv_spawn().
|
||||
*/
|
||||
static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
|
||||
int mask;
|
||||
int fd;
|
||||
|
||||
mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM;
|
||||
|
||||
switch (container->flags & mask) {
|
||||
case UV_IGNORE:
|
||||
return 0;
|
||||
|
||||
case UV_CREATE_PIPE:
|
||||
assert(container->data.stream != NULL);
|
||||
if (container->data.stream->type != UV_NAMED_PIPE)
|
||||
return UV_EINVAL;
|
||||
else
|
||||
return uv__make_socketpair(fds);
|
||||
|
||||
case UV_INHERIT_FD:
|
||||
case UV_INHERIT_STREAM:
|
||||
if (container->flags & UV_INHERIT_FD)
|
||||
fd = container->data.fd;
|
||||
else
|
||||
fd = uv__stream_fd(container->data.stream);
|
||||
|
||||
if (fd == -1)
|
||||
return UV_EINVAL;
|
||||
|
||||
fds[1] = fd;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
assert(0 && "Unexpected flags");
|
||||
return UV_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int uv__process_open_stream(uv_stdio_container_t* container,
|
||||
int pipefds[2]) {
|
||||
int flags;
|
||||
int err;
|
||||
|
||||
if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0)
|
||||
return 0;
|
||||
|
||||
err = uv__close(pipefds[1]);
|
||||
if (err != 0)
|
||||
abort();
|
||||
|
||||
pipefds[1] = -1;
|
||||
uv__nonblock(pipefds[0], 1);
|
||||
|
||||
flags = 0;
|
||||
if (container->flags & UV_WRITABLE_PIPE)
|
||||
flags |= UV_HANDLE_READABLE;
|
||||
if (container->flags & UV_READABLE_PIPE)
|
||||
flags |= UV_HANDLE_WRITABLE;
|
||||
|
||||
return uv__stream_open(container->data.stream, pipefds[0], flags);
|
||||
}
|
||||
|
||||
|
||||
static void uv__process_close_stream(uv_stdio_container_t* container) {
|
||||
if (!(container->flags & UV_CREATE_PIPE)) return;
|
||||
uv__stream_close(container->data.stream);
|
||||
}
|
||||
|
||||
|
||||
static void uv__write_int(int fd, int val) {
|
||||
ssize_t n;
|
||||
|
||||
do
|
||||
n = write(fd, &val, sizeof(val));
|
||||
while (n == -1 && errno == EINTR);
|
||||
|
||||
if (n == -1 && errno == EPIPE)
|
||||
return; /* parent process has quit */
|
||||
|
||||
assert(n == sizeof(val));
|
||||
}
|
||||
|
||||
|
||||
#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
|
||||
/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be
|
||||
* avoided. Since this isn't called on those targets, the function
|
||||
* doesn't even need to be defined for them.
|
||||
*/
|
||||
static void uv__process_child_init(const uv_process_options_t* options,
|
||||
int stdio_count,
|
||||
int (*pipes)[2],
|
||||
int error_fd) {
|
||||
sigset_t set;
|
||||
int close_fd;
|
||||
int use_fd;
|
||||
int err;
|
||||
int fd;
|
||||
int n;
|
||||
|
||||
if (options->flags & UV_PROCESS_DETACHED)
|
||||
setsid();
|
||||
|
||||
/* First duplicate low numbered fds, since it's not safe to duplicate them,
|
||||
* they could get replaced. Example: swapping stdout and stderr; without
|
||||
* this fd 2 (stderr) would be duplicated into fd 1, thus making both
|
||||
* stdout and stderr go to the same fd, which was not the intention. */
|
||||
for (fd = 0; fd < stdio_count; fd++) {
|
||||
use_fd = pipes[fd][1];
|
||||
if (use_fd < 0 || use_fd >= fd)
|
||||
continue;
|
||||
pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count);
|
||||
if (pipes[fd][1] == -1) {
|
||||
uv__write_int(error_fd, UV__ERR(errno));
|
||||
_exit(127);
|
||||
}
|
||||
}
|
||||
|
||||
for (fd = 0; fd < stdio_count; fd++) {
|
||||
close_fd = pipes[fd][0];
|
||||
use_fd = pipes[fd][1];
|
||||
|
||||
if (use_fd < 0) {
|
||||
if (fd >= 3)
|
||||
continue;
|
||||
else {
|
||||
/* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
|
||||
* set
|
||||
*/
|
||||
use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
|
||||
close_fd = use_fd;
|
||||
|
||||
if (use_fd < 0) {
|
||||
uv__write_int(error_fd, UV__ERR(errno));
|
||||
_exit(127);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fd == use_fd)
|
||||
uv__cloexec_fcntl(use_fd, 0);
|
||||
else
|
||||
fd = dup2(use_fd, fd);
|
||||
|
||||
if (fd == -1) {
|
||||
uv__write_int(error_fd, UV__ERR(errno));
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
if (fd <= 2)
|
||||
uv__nonblock_fcntl(fd, 0);
|
||||
|
||||
if (close_fd >= stdio_count)
|
||||
uv__close(close_fd);
|
||||
}
|
||||
|
||||
for (fd = 0; fd < stdio_count; fd++) {
|
||||
use_fd = pipes[fd][1];
|
||||
|
||||
if (use_fd >= stdio_count)
|
||||
uv__close(use_fd);
|
||||
}
|
||||
|
||||
if (options->cwd != NULL && chdir(options->cwd)) {
|
||||
uv__write_int(error_fd, UV__ERR(errno));
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
|
||||
/* When dropping privileges from root, the `setgroups` call will
|
||||
* remove any extraneous groups. If we don't call this, then
|
||||
* even though our uid has dropped, we may still have groups
|
||||
* that enable us to do super-user things. This will fail if we
|
||||
* aren't root, so don't bother checking the return value, this
|
||||
* is just done as an optimistic privilege dropping function.
|
||||
*/
|
||||
SAVE_ERRNO(setgroups(0, NULL));
|
||||
}
|
||||
|
||||
if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) {
|
||||
uv__write_int(error_fd, UV__ERR(errno));
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) {
|
||||
uv__write_int(error_fd, UV__ERR(errno));
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
if (options->env != NULL) {
|
||||
environ = options->env;
|
||||
}
|
||||
|
||||
/* Reset signal disposition. Use a hard-coded limit because NSIG
|
||||
* is not fixed on Linux: it's either 32, 34 or 64, depending on
|
||||
* whether RT signals are enabled. We are not allowed to touch
|
||||
* RT signal handlers, glibc uses them internally.
|
||||
*/
|
||||
for (n = 1; n < 32; n += 1) {
|
||||
if (n == SIGKILL || n == SIGSTOP)
|
||||
continue; /* Can't be changed. */
|
||||
|
||||
#if defined(__HAIKU__)
|
||||
if (n == SIGKILLTHR)
|
||||
continue; /* Can't be changed. */
|
||||
#endif
|
||||
|
||||
if (SIG_ERR != signal(n, SIG_DFL))
|
||||
continue;
|
||||
|
||||
uv__write_int(error_fd, UV__ERR(errno));
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
/* Reset signal mask. */
|
||||
sigemptyset(&set);
|
||||
err = pthread_sigmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
if (err != 0) {
|
||||
uv__write_int(error_fd, UV__ERR(err));
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
execvp(options->file, options->args);
|
||||
uv__write_int(error_fd, UV__ERR(errno));
|
||||
_exit(127);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int uv_spawn(uv_loop_t* loop,
|
||||
uv_process_t* process,
|
||||
const uv_process_options_t* options) {
|
||||
#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
|
||||
/* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */
|
||||
return UV_ENOSYS;
|
||||
#else
|
||||
int signal_pipe[2] = { -1, -1 };
|
||||
int pipes_storage[8][2];
|
||||
int (*pipes)[2];
|
||||
int stdio_count;
|
||||
ssize_t r;
|
||||
pid_t pid;
|
||||
int err;
|
||||
int exec_errorno;
|
||||
int i;
|
||||
int status;
|
||||
|
||||
assert(options->file != NULL);
|
||||
assert(!(options->flags & ~(UV_PROCESS_DETACHED |
|
||||
UV_PROCESS_SETGID |
|
||||
UV_PROCESS_SETUID |
|
||||
UV_PROCESS_WINDOWS_HIDE |
|
||||
UV_PROCESS_WINDOWS_HIDE_CONSOLE |
|
||||
UV_PROCESS_WINDOWS_HIDE_GUI |
|
||||
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
|
||||
|
||||
uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
|
||||
QUEUE_INIT(&process->queue);
|
||||
|
||||
stdio_count = options->stdio_count;
|
||||
if (stdio_count < 3)
|
||||
stdio_count = 3;
|
||||
|
||||
err = UV_ENOMEM;
|
||||
pipes = pipes_storage;
|
||||
if (stdio_count > (int) ARRAY_SIZE(pipes_storage))
|
||||
pipes = uv__malloc(stdio_count * sizeof(*pipes));
|
||||
|
||||
if (pipes == NULL)
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < stdio_count; i++) {
|
||||
pipes[i][0] = -1;
|
||||
pipes[i][1] = -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < options->stdio_count; i++) {
|
||||
err = uv__process_init_stdio(options->stdio + i, pipes[i]);
|
||||
if (err)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* This pipe is used by the parent to wait until
|
||||
* the child has called `execve()`. We need this
|
||||
* to avoid the following race condition:
|
||||
*
|
||||
* if ((pid = fork()) > 0) {
|
||||
* kill(pid, SIGTERM);
|
||||
* }
|
||||
* else if (pid == 0) {
|
||||
* execve("/bin/cat", argp, envp);
|
||||
* }
|
||||
*
|
||||
* The parent sends a signal immediately after forking.
|
||||
* Since the child may not have called `execve()` yet,
|
||||
* there is no telling what process receives the signal,
|
||||
* our fork or /bin/cat.
|
||||
*
|
||||
* To avoid ambiguity, we create a pipe with both ends
|
||||
* marked close-on-exec. Then, after the call to `fork()`,
|
||||
* the parent polls the read end until it EOFs or errors with EPIPE.
|
||||
*/
|
||||
err = uv__make_pipe(signal_pipe, 0);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
|
||||
|
||||
/* Acquire write lock to prevent opening new fds in worker threads */
|
||||
uv_rwlock_wrlock(&loop->cloexec_lock);
|
||||
pid = fork();
|
||||
|
||||
if (pid == -1) {
|
||||
err = UV__ERR(errno);
|
||||
uv_rwlock_wrunlock(&loop->cloexec_lock);
|
||||
uv__close(signal_pipe[0]);
|
||||
uv__close(signal_pipe[1]);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Release lock in parent process */
|
||||
uv_rwlock_wrunlock(&loop->cloexec_lock);
|
||||
uv__close(signal_pipe[1]);
|
||||
|
||||
process->status = 0;
|
||||
exec_errorno = 0;
|
||||
do
|
||||
r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno));
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r == 0)
|
||||
; /* okay, EOF */
|
||||
else if (r == sizeof(exec_errorno)) {
|
||||
do
|
||||
err = waitpid(pid, &status, 0); /* okay, read errorno */
|
||||
while (err == -1 && errno == EINTR);
|
||||
assert(err == pid);
|
||||
} else if (r == -1 && errno == EPIPE) {
|
||||
do
|
||||
err = waitpid(pid, &status, 0); /* okay, got EPIPE */
|
||||
while (err == -1 && errno == EINTR);
|
||||
assert(err == pid);
|
||||
} else
|
||||
abort();
|
||||
|
||||
uv__close_nocheckstdio(signal_pipe[0]);
|
||||
|
||||
for (i = 0; i < options->stdio_count; i++) {
|
||||
err = uv__process_open_stream(options->stdio + i, pipes[i]);
|
||||
if (err == 0)
|
||||
continue;
|
||||
|
||||
while (i--)
|
||||
uv__process_close_stream(options->stdio + i);
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Only activate this handle if exec() happened successfully */
|
||||
if (exec_errorno == 0) {
|
||||
QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue);
|
||||
uv__handle_start(process);
|
||||
}
|
||||
|
||||
process->pid = pid;
|
||||
process->exit_cb = options->exit_cb;
|
||||
|
||||
if (pipes != pipes_storage)
|
||||
uv__free(pipes);
|
||||
|
||||
return exec_errorno;
|
||||
|
||||
error:
|
||||
if (pipes != NULL) {
|
||||
for (i = 0; i < stdio_count; i++) {
|
||||
if (i < options->stdio_count)
|
||||
if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM))
|
||||
continue;
|
||||
if (pipes[i][0] != -1)
|
||||
uv__close_nocheckstdio(pipes[i][0]);
|
||||
if (pipes[i][1] != -1)
|
||||
uv__close_nocheckstdio(pipes[i][1]);
|
||||
}
|
||||
|
||||
if (pipes != pipes_storage)
|
||||
uv__free(pipes);
|
||||
}
|
||||
|
||||
return err;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv_process_kill(uv_process_t* process, int signum) {
|
||||
return uv_kill(process->pid, signum);
|
||||
}
|
||||
|
||||
|
||||
int uv_kill(int pid, int signum) {
|
||||
if (kill(pid, signum))
|
||||
return UV__ERR(errno);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__process_close(uv_process_t* handle) {
|
||||
QUEUE_REMOVE(&handle->queue);
|
||||
uv__handle_stop(handle);
|
||||
if (QUEUE_EMPTY(&handle->loop->process_handles))
|
||||
uv_signal_stop(&handle->loop->child_watcher);
|
||||
}
|
45
deps/libuv/src/unix/procfs-exepath.c
vendored
Normal file
45
deps/libuv/src/unix/procfs-exepath.c
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
/* 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
ssize_t n;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
n = *size - 1;
|
||||
if (n > 0)
|
||||
n = readlink("/proc/self/exe", buffer, n);
|
||||
|
||||
if (n == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
buffer[n] = '\0';
|
||||
*size = n;
|
||||
|
||||
return 0;
|
||||
}
|
159
deps/libuv/src/unix/proctitle.c
vendored
Normal file
159
deps/libuv/src/unix/proctitle.c
vendored
Normal file
@ -0,0 +1,159 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct uv__process_title {
|
||||
char* str;
|
||||
size_t len; /* Length of the current process title. */
|
||||
size_t cap; /* Maximum capacity. Computed once in uv_setup_args(). */
|
||||
};
|
||||
|
||||
extern void uv__set_process_title(const char* title);
|
||||
|
||||
static uv_mutex_t process_title_mutex;
|
||||
static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
|
||||
static struct uv__process_title process_title;
|
||||
static void* args_mem;
|
||||
|
||||
|
||||
static void init_process_title_mutex_once(void) {
|
||||
uv_mutex_init(&process_title_mutex);
|
||||
}
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
struct uv__process_title pt;
|
||||
char** new_argv;
|
||||
size_t size;
|
||||
char* s;
|
||||
int i;
|
||||
|
||||
if (argc <= 0)
|
||||
return argv;
|
||||
|
||||
pt.str = argv[0];
|
||||
pt.len = strlen(argv[0]);
|
||||
pt.cap = pt.len + 1;
|
||||
|
||||
/* Calculate how much memory we need for the argv strings. */
|
||||
size = pt.cap;
|
||||
for (i = 1; 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;
|
||||
|
||||
/* Copy over the strings and set up the pointer table. */
|
||||
i = 0;
|
||||
s = (char*) &new_argv[argc + 1];
|
||||
size = pt.cap;
|
||||
goto loop;
|
||||
|
||||
for (/* empty */; i < argc; i++) {
|
||||
size = strlen(argv[i]) + 1;
|
||||
loop:
|
||||
memcpy(s, argv[i], size);
|
||||
new_argv[i] = s;
|
||||
s += size;
|
||||
}
|
||||
new_argv[i] = NULL;
|
||||
|
||||
/* argv is not adjacent on z/os, we use just argv[0] on that platform. */
|
||||
#ifndef __MVS__
|
||||
pt.cap = argv[i - 1] + size - argv[0];
|
||||
#endif
|
||||
|
||||
args_mem = new_argv;
|
||||
process_title = pt;
|
||||
|
||||
return new_argv;
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
struct uv__process_title* pt;
|
||||
size_t len;
|
||||
|
||||
/* If uv_setup_args wasn't called or failed, we can't continue. */
|
||||
if (args_mem == NULL)
|
||||
return UV_ENOBUFS;
|
||||
|
||||
pt = &process_title;
|
||||
len = strlen(title);
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (len >= pt->cap) {
|
||||
len = 0;
|
||||
if (pt->cap > 0)
|
||||
len = pt->cap - 1;
|
||||
}
|
||||
|
||||
memcpy(pt->str, title, len);
|
||||
memset(pt->str + len, '\0', pt->cap - len);
|
||||
pt->len = len;
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
if (buffer == NULL || size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* If uv_setup_args wasn't called or failed, we can't continue. */
|
||||
if (args_mem == NULL)
|
||||
return UV_ENOBUFS;
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (size <= process_title.len) {
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
if (process_title.len != 0)
|
||||
memcpy(buffer, process_title.str, process_title.len + 1);
|
||||
|
||||
buffer[process_title.len] = '\0';
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__process_title_cleanup(void) {
|
||||
uv__free(args_mem); /* Keep valgrind happy. */
|
||||
args_mem = NULL;
|
||||
}
|
58
deps/libuv/src/unix/pthread-fixes.c
vendored
Normal file
58
deps/libuv/src/unix/pthread-fixes.c
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
/* Copyright (c) 2013, Sony Mobile Communications AB
|
||||
* Copyright (c) 2012, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Android versions < 4.1 have a broken pthread_sigmask. */
|
||||
#include "uv-common.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) {
|
||||
static int workaround;
|
||||
int err;
|
||||
|
||||
if (uv__load_relaxed(&workaround)) {
|
||||
return sigprocmask(how, set, oset);
|
||||
} else {
|
||||
err = pthread_sigmask(how, set, oset);
|
||||
if (err) {
|
||||
if (err == EINVAL && sigprocmask(how, set, oset) == 0) {
|
||||
uv__store_relaxed(&workaround, 1);
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
137
deps/libuv/src/unix/qnx.c
vendored
Normal file
137
deps/libuv/src/unix/qnx.c
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
/* Copyright libuv 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/process.h>
|
||||
#include <sys/neutrino.h>
|
||||
#include <sys/memmsg.h>
|
||||
#include <sys/syspage.h>
|
||||
#include <sys/procfs.h>
|
||||
|
||||
static void
|
||||
get_mem_info(uint64_t* totalmem, uint64_t* freemem) {
|
||||
mem_info_t msg;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.i.type = _MEM_INFO;
|
||||
msg.i.fd = -1;
|
||||
|
||||
if (MsgSend(MEMMGR_COID, &msg.i, sizeof(msg.i), &msg.o, sizeof(msg.o))
|
||||
!= -1) {
|
||||
*totalmem = msg.o.info.__posix_tmi_total;
|
||||
*freemem = msg.o.info.posix_tmi_length;
|
||||
} else {
|
||||
*totalmem = 0;
|
||||
*freemem = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
avg[0] = 0.0;
|
||||
avg[1] = 0.0;
|
||||
avg[2] = 0.0;
|
||||
}
|
||||
|
||||
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
char path[PATH_MAX];
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
realpath(_cmdname(NULL), path);
|
||||
strlcpy(buffer, path, *size);
|
||||
*size = strlen(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
uint64_t totalmem;
|
||||
uint64_t freemem;
|
||||
get_mem_info(&totalmem, &freemem);
|
||||
return freemem;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
uint64_t totalmem;
|
||||
uint64_t freemem;
|
||||
get_mem_info(&totalmem, &freemem);
|
||||
return totalmem;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
int fd;
|
||||
procfs_asinfo asinfo;
|
||||
|
||||
fd = uv__open_cloexec("/proc/self/ctl", O_RDONLY);
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (devctl(fd, DCMD_PROC_ASINFO, &asinfo, sizeof(asinfo), 0) == -1) {
|
||||
uv__close(fd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
uv__close(fd);
|
||||
*rss = asinfo.rss;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
struct qtime_entry* qtime = _SYSPAGE_ENTRY(_syspage_ptr, qtime);
|
||||
*uptime = (qtime->nsec / 1000000000.0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
struct cpuinfo_entry* cpuinfo =
|
||||
(struct cpuinfo_entry*)_SYSPAGE_ENTRY(_syspage_ptr, new_cpuinfo);
|
||||
size_t cpuinfo_size = _SYSPAGE_ELEMENT_SIZE(_syspage_ptr, cpuinfo);
|
||||
struct strings_entry* strings = _SYSPAGE_ENTRY(_syspage_ptr, strings);
|
||||
int num_cpus = _syspage_ptr->num_cpu;
|
||||
int i;
|
||||
|
||||
*count = num_cpus;
|
||||
*cpu_infos = uv__malloc(num_cpus * sizeof(**cpu_infos));
|
||||
if (*cpu_infos == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
for (i = 0; i < num_cpus; i++) {
|
||||
(*cpu_infos)[i].model = strdup(&strings->data[cpuinfo->name]);
|
||||
(*cpu_infos)[i].speed = cpuinfo->speed;
|
||||
SYSPAGE_ARRAY_ADJ_OFFSET(cpuinfo, cpuinfo, cpuinfo_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
93
deps/libuv/src/unix/random-devurandom.c
vendored
Normal file
93
deps/libuv/src/unix/random-devurandom.c
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
/* Copyright libuv 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
static int status;
|
||||
|
||||
|
||||
int uv__random_readpath(const char* path, void* buf, size_t buflen) {
|
||||
struct stat s;
|
||||
size_t pos;
|
||||
ssize_t n;
|
||||
int fd;
|
||||
|
||||
fd = uv__open_cloexec(path, O_RDONLY);
|
||||
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
if (fstat(fd, &s)) {
|
||||
uv__close(fd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
if (!S_ISCHR(s.st_mode)) {
|
||||
uv__close(fd);
|
||||
return UV_EIO;
|
||||
}
|
||||
|
||||
for (pos = 0; pos != buflen; pos += n) {
|
||||
do
|
||||
n = read(fd, (char*) buf + pos, buflen - pos);
|
||||
while (n == -1 && errno == EINTR);
|
||||
|
||||
if (n == -1) {
|
||||
uv__close(fd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
uv__close(fd);
|
||||
return UV_EIO;
|
||||
}
|
||||
}
|
||||
|
||||
uv__close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__random_devurandom_init(void) {
|
||||
char c;
|
||||
|
||||
/* Linux's random(4) man page suggests applications should read at least
|
||||
* once from /dev/random before switching to /dev/urandom in order to seed
|
||||
* the system RNG. Reads from /dev/random can of course block indefinitely
|
||||
* until entropy is available but that's the point.
|
||||
*/
|
||||
status = uv__random_readpath("/dev/random", &c, 1);
|
||||
}
|
||||
|
||||
|
||||
int uv__random_devurandom(void* buf, size_t buflen) {
|
||||
uv_once(&once, uv__random_devurandom_init);
|
||||
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
return uv__random_readpath("/dev/urandom", buf, buflen);
|
||||
}
|
57
deps/libuv/src/unix/random-getentropy.c
vendored
Normal file
57
deps/libuv/src/unix/random-getentropy.c
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/* Copyright libuv 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
typedef int (*uv__getentropy_cb)(void *, size_t);
|
||||
|
||||
static uv__getentropy_cb uv__getentropy;
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
|
||||
|
||||
static void uv__random_getentropy_init(void) {
|
||||
uv__getentropy = (uv__getentropy_cb) dlsym(RTLD_DEFAULT, "getentropy");
|
||||
}
|
||||
|
||||
|
||||
int uv__random_getentropy(void* buf, size_t buflen) {
|
||||
size_t pos;
|
||||
size_t stride;
|
||||
|
||||
uv_once(&once, uv__random_getentropy_init);
|
||||
|
||||
if (uv__getentropy == NULL)
|
||||
return UV_ENOSYS;
|
||||
|
||||
/* getentropy() returns an error for requests > 256 bytes. */
|
||||
for (pos = 0, stride = 256; pos + stride < buflen; pos += stride)
|
||||
if (uv__getentropy((char *) buf + pos, stride))
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (uv__getentropy((char *) buf + pos, buflen - pos))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return 0;
|
||||
}
|
88
deps/libuv/src/unix/random-getrandom.c
vendored
Normal file
88
deps/libuv/src/unix/random-getrandom.c
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
/* Copyright libuv 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "linux-syscalls.h"
|
||||
|
||||
#define uv__random_getrandom_init() 0
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
typedef ssize_t (*uv__getrandom_cb)(void *, size_t, unsigned);
|
||||
|
||||
static uv__getrandom_cb uv__getrandom;
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
|
||||
static void uv__random_getrandom_init_once(void) {
|
||||
uv__getrandom = (uv__getrandom_cb) dlsym(RTLD_DEFAULT, "getrandom");
|
||||
}
|
||||
|
||||
static int uv__random_getrandom_init(void) {
|
||||
uv_once(&once, uv__random_getrandom_init_once);
|
||||
|
||||
if (uv__getrandom == NULL)
|
||||
return UV_ENOSYS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !__linux__ */
|
||||
|
||||
int uv__random_getrandom(void* buf, size_t buflen) {
|
||||
ssize_t n;
|
||||
size_t pos;
|
||||
int rc;
|
||||
|
||||
rc = uv__random_getrandom_init();
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
for (pos = 0; pos != buflen; pos += n) {
|
||||
do {
|
||||
n = buflen - pos;
|
||||
|
||||
/* Most getrandom() implementations promise that reads <= 256 bytes
|
||||
* will always succeed and won't be interrupted by signals.
|
||||
* It's therefore useful to split it up in smaller reads because
|
||||
* one big read may, in theory, continuously fail with EINTR.
|
||||
*/
|
||||
if (n > 256)
|
||||
n = 256;
|
||||
|
||||
n = uv__getrandom((char *) buf + pos, n, 0);
|
||||
} while (n == -1 && errno == EINTR);
|
||||
|
||||
if (n == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (n == 0)
|
||||
return UV_EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
99
deps/libuv/src/unix/random-sysctl-linux.c
vendored
Normal file
99
deps/libuv/src/unix/random-sysctl-linux.c
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
/* Copyright libuv 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
struct uv__sysctl_args {
|
||||
int* name;
|
||||
int nlen;
|
||||
void* oldval;
|
||||
size_t* oldlenp;
|
||||
void* newval;
|
||||
size_t newlen;
|
||||
unsigned long unused[4];
|
||||
};
|
||||
|
||||
|
||||
int uv__random_sysctl(void* buf, size_t buflen) {
|
||||
static int name[] = {1 /*CTL_KERN*/, 40 /*KERN_RANDOM*/, 6 /*RANDOM_UUID*/};
|
||||
struct uv__sysctl_args args;
|
||||
char uuid[16];
|
||||
char* p;
|
||||
char* pe;
|
||||
size_t n;
|
||||
|
||||
p = buf;
|
||||
pe = p + buflen;
|
||||
|
||||
while (p < pe) {
|
||||
memset(&args, 0, sizeof(args));
|
||||
|
||||
args.name = name;
|
||||
args.nlen = ARRAY_SIZE(name);
|
||||
args.oldval = uuid;
|
||||
args.oldlenp = &n;
|
||||
n = sizeof(uuid);
|
||||
|
||||
/* Emits a deprecation warning with some kernels but that seems like
|
||||
* an okay trade-off for the fallback of the fallback: this function is
|
||||
* only called when neither getrandom(2) nor /dev/urandom are available.
|
||||
* Fails with ENOSYS on kernels configured without CONFIG_SYSCTL_SYSCALL.
|
||||
* At least arm64 never had a _sysctl system call and therefore doesn't
|
||||
* have a SYS__sysctl define either.
|
||||
*/
|
||||
#ifdef SYS__sysctl
|
||||
if (syscall(SYS__sysctl, &args) == -1)
|
||||
return UV__ERR(errno);
|
||||
#else
|
||||
{
|
||||
(void) &args;
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (n != sizeof(uuid))
|
||||
return UV_EIO; /* Can't happen. */
|
||||
|
||||
/* uuid[] is now a type 4 UUID. Bytes 6 and 8 (counting from zero) contain
|
||||
* 4 and 5 bits of entropy, respectively. For ease of use, we skip those
|
||||
* and only use 14 of the 16 bytes.
|
||||
*/
|
||||
uuid[6] = uuid[14];
|
||||
uuid[8] = uuid[15];
|
||||
|
||||
n = pe - p;
|
||||
if (n > 14)
|
||||
n = 14;
|
||||
|
||||
memcpy(p, uuid, n);
|
||||
p += n;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
558
deps/libuv/src/unix/signal.c
vendored
Normal file
558
deps/libuv/src/unix/signal.c
vendored
Normal file
@ -0,0 +1,558 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef SA_RESTART
|
||||
# define SA_RESTART 0
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uv_signal_t* handle;
|
||||
int signum;
|
||||
} uv__signal_msg_t;
|
||||
|
||||
RB_HEAD(uv__signal_tree_s, uv_signal_s);
|
||||
|
||||
|
||||
static int uv__signal_unlock(void);
|
||||
static int uv__signal_start(uv_signal_t* handle,
|
||||
uv_signal_cb signal_cb,
|
||||
int signum,
|
||||
int oneshot);
|
||||
static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events);
|
||||
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2);
|
||||
static void uv__signal_stop(uv_signal_t* handle);
|
||||
static void uv__signal_unregister_handler(int signum);
|
||||
|
||||
|
||||
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] = { -1, -1 };
|
||||
|
||||
RB_GENERATE_STATIC(uv__signal_tree_s,
|
||||
uv_signal_s, tree_entry,
|
||||
uv__signal_compare)
|
||||
|
||||
static void uv__signal_global_reinit(void);
|
||||
|
||||
static void uv__signal_global_init(void) {
|
||||
if (uv__signal_lock_pipefd[0] == -1)
|
||||
/* pthread_atfork can register before and after handlers, one
|
||||
* for each child. This only registers one for the child. That
|
||||
* state is both persistent and cumulative, so if we keep doing
|
||||
* it the handler functions will be called multiple times. Thus
|
||||
* we only want to do it once.
|
||||
*/
|
||||
if (pthread_atfork(NULL, NULL, &uv__signal_global_reinit))
|
||||
abort();
|
||||
|
||||
uv__signal_global_reinit();
|
||||
}
|
||||
|
||||
|
||||
void uv__signal_cleanup(void) {
|
||||
/* We can only use signal-safe functions here.
|
||||
* That includes read/write and close, fortunately.
|
||||
* We do all of this directly here instead of resetting
|
||||
* uv__signal_global_init_guard because
|
||||
* uv__signal_global_once_init is only called from uv_loop_init
|
||||
* and this needs to function in existing loops.
|
||||
*/
|
||||
if (uv__signal_lock_pipefd[0] != -1) {
|
||||
uv__close(uv__signal_lock_pipefd[0]);
|
||||
uv__signal_lock_pipefd[0] = -1;
|
||||
}
|
||||
|
||||
if (uv__signal_lock_pipefd[1] != -1) {
|
||||
uv__close(uv__signal_lock_pipefd[1]);
|
||||
uv__signal_lock_pipefd[1] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_global_reinit(void) {
|
||||
uv__signal_cleanup();
|
||||
|
||||
if (uv__make_pipe(uv__signal_lock_pipefd, 0))
|
||||
abort();
|
||||
|
||||
if (uv__signal_unlock())
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv__signal_global_once_init(void) {
|
||||
uv_once(&uv__signal_global_init_guard, uv__signal_global_init);
|
||||
}
|
||||
|
||||
|
||||
static int uv__signal_lock(void) {
|
||||
int r;
|
||||
char data;
|
||||
|
||||
do {
|
||||
r = read(uv__signal_lock_pipefd[0], &data, sizeof data);
|
||||
} while (r < 0 && errno == EINTR);
|
||||
|
||||
return (r < 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__signal_unlock(void) {
|
||||
int r;
|
||||
char data = 42;
|
||||
|
||||
do {
|
||||
r = write(uv__signal_lock_pipefd[1], &data, sizeof data);
|
||||
} while (r < 0 && errno == EINTR);
|
||||
|
||||
return (r < 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_block_and_lock(sigset_t* saved_sigmask) {
|
||||
sigset_t new_mask;
|
||||
|
||||
if (sigfillset(&new_mask))
|
||||
abort();
|
||||
|
||||
/* to shut up valgrind */
|
||||
sigemptyset(saved_sigmask);
|
||||
if (pthread_sigmask(SIG_SETMASK, &new_mask, saved_sigmask))
|
||||
abort();
|
||||
|
||||
if (uv__signal_lock())
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_unlock_and_unblock(sigset_t* saved_sigmask) {
|
||||
if (uv__signal_unlock())
|
||||
abort();
|
||||
|
||||
if (pthread_sigmask(SIG_SETMASK, saved_sigmask, NULL))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
static uv_signal_t* uv__signal_first_handle(int signum) {
|
||||
/* This function must be called with the signal lock held. */
|
||||
uv_signal_t lookup;
|
||||
uv_signal_t* handle;
|
||||
|
||||
lookup.signum = signum;
|
||||
lookup.flags = 0;
|
||||
lookup.loop = NULL;
|
||||
|
||||
handle = RB_NFIND(uv__signal_tree_s, &uv__signal_tree, &lookup);
|
||||
|
||||
if (handle != NULL && handle->signum == signum)
|
||||
return handle;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_handler(int signum) {
|
||||
uv__signal_msg_t msg;
|
||||
uv_signal_t* handle;
|
||||
int saved_errno;
|
||||
|
||||
saved_errno = errno;
|
||||
memset(&msg, 0, sizeof msg);
|
||||
|
||||
if (uv__signal_lock()) {
|
||||
errno = saved_errno;
|
||||
return;
|
||||
}
|
||||
|
||||
for (handle = uv__signal_first_handle(signum);
|
||||
handle != NULL && handle->signum == signum;
|
||||
handle = RB_NEXT(uv__signal_tree_s, &uv__signal_tree, handle)) {
|
||||
int r;
|
||||
|
||||
msg.signum = signum;
|
||||
msg.handle = handle;
|
||||
|
||||
/* write() should be atomic for small data chunks, so the entire message
|
||||
* should be written at once. In theory the pipe could become full, in
|
||||
* which case the user is out of luck.
|
||||
*/
|
||||
do {
|
||||
r = write(handle->loop->signal_pipefd[1], &msg, sizeof msg);
|
||||
} while (r == -1 && errno == EINTR);
|
||||
|
||||
assert(r == sizeof msg ||
|
||||
(r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)));
|
||||
|
||||
if (r != -1)
|
||||
handle->caught_signals++;
|
||||
}
|
||||
|
||||
uv__signal_unlock();
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
|
||||
static int uv__signal_register_handler(int signum, int oneshot) {
|
||||
/* When this function is called, the signal lock must be held. */
|
||||
struct sigaction sa;
|
||||
|
||||
/* XXX use a separate signal stack? */
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
if (sigfillset(&sa.sa_mask))
|
||||
abort();
|
||||
sa.sa_handler = uv__signal_handler;
|
||||
sa.sa_flags = SA_RESTART;
|
||||
if (oneshot)
|
||||
sa.sa_flags |= SA_RESETHAND;
|
||||
|
||||
/* XXX save old action so we can restore it later on? */
|
||||
if (sigaction(signum, &sa, NULL))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_unregister_handler(int signum) {
|
||||
/* When this function is called, the signal lock must be held. */
|
||||
struct sigaction sa;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = SIG_DFL;
|
||||
|
||||
/* sigaction can only fail with EINVAL or EFAULT; an attempt to deregister a
|
||||
* signal implies that it was successfully registered earlier, so EINVAL
|
||||
* should never happen.
|
||||
*/
|
||||
if (sigaction(signum, &sa, NULL))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
static int uv__signal_loop_once_init(uv_loop_t* loop) {
|
||||
int err;
|
||||
|
||||
/* Return if already initialized. */
|
||||
if (loop->signal_pipefd[0] != -1)
|
||||
return 0;
|
||||
|
||||
err = uv__make_pipe(loop->signal_pipefd, UV__F_NONBLOCK);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
uv__io_init(&loop->signal_io_watcher,
|
||||
uv__signal_event,
|
||||
loop->signal_pipefd[0]);
|
||||
uv__io_start(loop, &loop->signal_io_watcher, POLLIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__signal_loop_fork(uv_loop_t* loop) {
|
||||
uv__io_stop(loop, &loop->signal_io_watcher, POLLIN);
|
||||
uv__close(loop->signal_pipefd[0]);
|
||||
uv__close(loop->signal_pipefd[1]);
|
||||
loop->signal_pipefd[0] = -1;
|
||||
loop->signal_pipefd[1] = -1;
|
||||
return uv__signal_loop_once_init(loop);
|
||||
}
|
||||
|
||||
|
||||
void uv__signal_loop_cleanup(uv_loop_t* loop) {
|
||||
QUEUE* q;
|
||||
|
||||
/* Stop all the signal watchers that are still attached to this loop. This
|
||||
* ensures that the (shared) signal tree doesn't contain any invalid entries
|
||||
* entries, and that signal handlers are removed when appropriate.
|
||||
* It's safe to use QUEUE_FOREACH here because the handles and the handle
|
||||
* queue are not modified by uv__signal_stop().
|
||||
*/
|
||||
QUEUE_FOREACH(q, &loop->handle_queue) {
|
||||
uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue);
|
||||
|
||||
if (handle->type == UV_SIGNAL)
|
||||
uv__signal_stop((uv_signal_t*) handle);
|
||||
}
|
||||
|
||||
if (loop->signal_pipefd[0] != -1) {
|
||||
uv__close(loop->signal_pipefd[0]);
|
||||
loop->signal_pipefd[0] = -1;
|
||||
}
|
||||
|
||||
if (loop->signal_pipefd[1] != -1) {
|
||||
uv__close(loop->signal_pipefd[1]);
|
||||
loop->signal_pipefd[1] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
|
||||
int err;
|
||||
|
||||
err = uv__signal_loop_once_init(loop);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
|
||||
handle->signum = 0;
|
||||
handle->caught_signals = 0;
|
||||
handle->dispatched_signals = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__signal_close(uv_signal_t* handle) {
|
||||
uv__signal_stop(handle);
|
||||
}
|
||||
|
||||
|
||||
int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
|
||||
return uv__signal_start(handle, signal_cb, signum, 0);
|
||||
}
|
||||
|
||||
|
||||
int uv_signal_start_oneshot(uv_signal_t* handle,
|
||||
uv_signal_cb signal_cb,
|
||||
int signum) {
|
||||
return uv__signal_start(handle, signal_cb, signum, 1);
|
||||
}
|
||||
|
||||
|
||||
static int uv__signal_start(uv_signal_t* handle,
|
||||
uv_signal_cb signal_cb,
|
||||
int signum,
|
||||
int oneshot) {
|
||||
sigset_t saved_sigmask;
|
||||
int err;
|
||||
uv_signal_t* first_handle;
|
||||
|
||||
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
|
||||
* eventually.
|
||||
*/
|
||||
if (signum == 0)
|
||||
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.
|
||||
* Additionally, this avoids pending signals getting lost in the small
|
||||
* time frame that handle->signum == 0.
|
||||
*/
|
||||
if (signum == handle->signum) {
|
||||
handle->signal_cb = signal_cb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the signal handler was already active, stop it first. */
|
||||
if (handle->signum != 0) {
|
||||
uv__signal_stop(handle);
|
||||
}
|
||||
|
||||
uv__signal_block_and_lock(&saved_sigmask);
|
||||
|
||||
/* If at this point there are no active signal watchers for this signum (in
|
||||
* any of the loops), it's time to try and register a handler for it here.
|
||||
* Also in case there's only one-shot handlers and a regular handler comes in.
|
||||
*/
|
||||
first_handle = uv__signal_first_handle(signum);
|
||||
if (first_handle == NULL ||
|
||||
(!oneshot && (first_handle->flags & UV_SIGNAL_ONE_SHOT))) {
|
||||
err = uv__signal_register_handler(signum, oneshot);
|
||||
if (err) {
|
||||
/* Registering the signal handler failed. Must be an invalid signal. */
|
||||
uv__signal_unlock_and_unblock(&saved_sigmask);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
handle->signum = signum;
|
||||
if (oneshot)
|
||||
handle->flags |= UV_SIGNAL_ONE_SHOT;
|
||||
|
||||
RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle);
|
||||
|
||||
uv__signal_unlock_and_unblock(&saved_sigmask);
|
||||
|
||||
handle->signal_cb = signal_cb;
|
||||
uv__handle_start(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_event(uv_loop_t* loop,
|
||||
uv__io_t* w,
|
||||
unsigned int events) {
|
||||
uv__signal_msg_t* msg;
|
||||
uv_signal_t* handle;
|
||||
char buf[sizeof(uv__signal_msg_t) * 32];
|
||||
size_t bytes, end, i;
|
||||
int r;
|
||||
|
||||
bytes = 0;
|
||||
end = 0;
|
||||
|
||||
do {
|
||||
r = read(loop->signal_pipefd[0], buf + bytes, sizeof(buf) - bytes);
|
||||
|
||||
if (r == -1 && errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
|
||||
/* If there are bytes in the buffer already (which really is extremely
|
||||
* unlikely if possible at all) we can't exit the function here. We'll
|
||||
* spin until more bytes are read instead.
|
||||
*/
|
||||
if (bytes > 0)
|
||||
continue;
|
||||
|
||||
/* Otherwise, there was nothing there. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Other errors really should never happen. */
|
||||
if (r == -1)
|
||||
abort();
|
||||
|
||||
bytes += r;
|
||||
|
||||
/* `end` is rounded down to a multiple of sizeof(uv__signal_msg_t). */
|
||||
end = (bytes / sizeof(uv__signal_msg_t)) * sizeof(uv__signal_msg_t);
|
||||
|
||||
for (i = 0; i < end; i += sizeof(uv__signal_msg_t)) {
|
||||
msg = (uv__signal_msg_t*) (buf + i);
|
||||
handle = msg->handle;
|
||||
|
||||
if (msg->signum == handle->signum) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSING));
|
||||
handle->signal_cb(handle, handle->signum);
|
||||
}
|
||||
|
||||
handle->dispatched_signals++;
|
||||
|
||||
if (handle->flags & UV_SIGNAL_ONE_SHOT)
|
||||
uv__signal_stop(handle);
|
||||
}
|
||||
|
||||
bytes -= end;
|
||||
|
||||
/* If there are any "partial" messages left, move them to the start of the
|
||||
* the buffer, and spin. This should not happen.
|
||||
*/
|
||||
if (bytes) {
|
||||
memmove(buf, buf + end, bytes);
|
||||
continue;
|
||||
}
|
||||
} while (end == sizeof buf);
|
||||
}
|
||||
|
||||
|
||||
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
|
||||
int f1;
|
||||
int f2;
|
||||
/* Compare signums first so all watchers with the same signnum end up
|
||||
* adjacent.
|
||||
*/
|
||||
if (w1->signum < w2->signum) return -1;
|
||||
if (w1->signum > w2->signum) return 1;
|
||||
|
||||
/* Handlers without UV_SIGNAL_ONE_SHOT set will come first, so if the first
|
||||
* handler returned is a one-shot handler, the rest will be too.
|
||||
*/
|
||||
f1 = w1->flags & UV_SIGNAL_ONE_SHOT;
|
||||
f2 = w2->flags & UV_SIGNAL_ONE_SHOT;
|
||||
if (f1 < f2) return -1;
|
||||
if (f1 > f2) return 1;
|
||||
|
||||
/* Sort by loop pointer, so we can easily look up the first item after
|
||||
* { .signum = x, .loop = NULL }.
|
||||
*/
|
||||
if (w1->loop < w2->loop) return -1;
|
||||
if (w1->loop > w2->loop) return 1;
|
||||
|
||||
if (w1 < w2) return -1;
|
||||
if (w1 > w2) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_signal_stop(uv_signal_t* handle) {
|
||||
assert(!uv__is_closing(handle));
|
||||
uv__signal_stop(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_stop(uv_signal_t* handle) {
|
||||
uv_signal_t* removed_handle;
|
||||
sigset_t saved_sigmask;
|
||||
uv_signal_t* first_handle;
|
||||
int rem_oneshot;
|
||||
int first_oneshot;
|
||||
int ret;
|
||||
|
||||
/* If the watcher wasn't started, this is a no-op. */
|
||||
if (handle->signum == 0)
|
||||
return;
|
||||
|
||||
uv__signal_block_and_lock(&saved_sigmask);
|
||||
|
||||
removed_handle = RB_REMOVE(uv__signal_tree_s, &uv__signal_tree, handle);
|
||||
assert(removed_handle == handle);
|
||||
(void) removed_handle;
|
||||
|
||||
/* Check if there are other active signal watchers observing this signal. If
|
||||
* not, unregister the signal handler.
|
||||
*/
|
||||
first_handle = uv__signal_first_handle(handle->signum);
|
||||
if (first_handle == NULL) {
|
||||
uv__signal_unregister_handler(handle->signum);
|
||||
} else {
|
||||
rem_oneshot = handle->flags & UV_SIGNAL_ONE_SHOT;
|
||||
first_oneshot = first_handle->flags & UV_SIGNAL_ONE_SHOT;
|
||||
if (first_oneshot && !rem_oneshot) {
|
||||
ret = uv__signal_register_handler(handle->signum, 1);
|
||||
assert(ret == 0);
|
||||
(void)ret;
|
||||
}
|
||||
}
|
||||
|
||||
uv__signal_unlock_and_unblock(&saved_sigmask);
|
||||
|
||||
handle->signum = 0;
|
||||
uv__handle_stop(handle);
|
||||
}
|
53
deps/libuv/src/unix/spinlock.h
vendored
Normal file
53
deps/libuv/src/unix/spinlock.h
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_SPINLOCK_H_
|
||||
#define UV_SPINLOCK_H_
|
||||
|
||||
#include "internal.h" /* ACCESS_ONCE, UV_UNUSED */
|
||||
#include "atomic-ops.h"
|
||||
|
||||
#define UV_SPINLOCK_INITIALIZER { 0 }
|
||||
|
||||
typedef struct {
|
||||
int lock;
|
||||
} uv_spinlock_t;
|
||||
|
||||
UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock));
|
||||
UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock));
|
||||
UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock));
|
||||
UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock));
|
||||
|
||||
UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)) {
|
||||
ACCESS_ONCE(int, spinlock->lock) = 0;
|
||||
}
|
||||
|
||||
UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)) {
|
||||
while (!uv_spinlock_trylock(spinlock)) cpu_relax();
|
||||
}
|
||||
|
||||
UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)) {
|
||||
ACCESS_ONCE(int, spinlock->lock) = 0;
|
||||
}
|
||||
|
||||
UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)) {
|
||||
/* TODO(bnoordhuis) Maybe change to a ticket lock to guarantee fair queueing.
|
||||
* Not really critical until we have locks that are (frequently) contended
|
||||
* for by several threads.
|
||||
*/
|
||||
return 0 == cmpxchgi(&spinlock->lock, 0, 1);
|
||||
}
|
||||
|
||||
#endif /* UV_SPINLOCK_H_ */
|
1693
deps/libuv/src/unix/stream.c
vendored
Normal file
1693
deps/libuv/src/unix/stream.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
867
deps/libuv/src/unix/sunos.c
vendored
Normal file
867
deps/libuv/src/unix/sunos.c
vendored
Normal file
@ -0,0 +1,867 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef SUNOS_NO_IFADDRS
|
||||
# include <ifaddrs.h>
|
||||
#endif
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <sys/sockio.h>
|
||||
|
||||
#include <sys/loadavg.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <kstat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/port.h>
|
||||
#include <port.h>
|
||||
|
||||
#define PORT_FIRED 0x69
|
||||
#define PORT_UNUSED 0x0
|
||||
#define PORT_LOADED 0x99
|
||||
#define PORT_DELETED -1
|
||||
|
||||
#if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
|
||||
#define PROCFS_FILE_OFFSET_BITS_HACK 1
|
||||
#undef _FILE_OFFSET_BITS
|
||||
#else
|
||||
#define PROCFS_FILE_OFFSET_BITS_HACK 0
|
||||
#endif
|
||||
|
||||
#include <procfs.h>
|
||||
|
||||
#if (PROCFS_FILE_OFFSET_BITS_HACK - 0 == 1)
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
loop->fs_fd = -1;
|
||||
loop->backend_fd = -1;
|
||||
|
||||
fd = port_create();
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
err = uv__cloexec(fd, 1);
|
||||
if (err) {
|
||||
uv__close(fd);
|
||||
return err;
|
||||
}
|
||||
loop->backend_fd = fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
if (loop->fs_fd != -1) {
|
||||
uv__close(loop->fs_fd);
|
||||
loop->fs_fd = -1;
|
||||
}
|
||||
|
||||
if (loop->backend_fd != -1) {
|
||||
uv__close(loop->backend_fd);
|
||||
loop->backend_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv__io_fork(uv_loop_t* loop) {
|
||||
#if defined(PORT_SOURCE_FILE)
|
||||
if (loop->fs_fd != -1) {
|
||||
/* stop the watcher before we blow away its fileno */
|
||||
uv__io_stop(loop, &loop->fs_event_watcher, POLLIN);
|
||||
}
|
||||
#endif
|
||||
uv__platform_loop_delete(loop);
|
||||
return uv__platform_loop_init(loop);
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
struct port_event* events;
|
||||
uintptr_t i;
|
||||
uintptr_t nfds;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
assert(fd >= 0);
|
||||
|
||||
events = (struct port_event*) loop->watchers[loop->nwatchers];
|
||||
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
|
||||
if (events == NULL)
|
||||
return;
|
||||
|
||||
/* Invalidate events with same file descriptor */
|
||||
for (i = 0; i < nfds; i++)
|
||||
if ((int) events[i].portev_object == fd)
|
||||
events[i].portev_object = -1;
|
||||
}
|
||||
|
||||
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) {
|
||||
perror("(libuv) port_dissociate()");
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
struct port_event events[1024];
|
||||
struct port_event* pe;
|
||||
struct timespec spec;
|
||||
QUEUE* q;
|
||||
uv__io_t* w;
|
||||
sigset_t* pset;
|
||||
sigset_t set;
|
||||
uint64_t base;
|
||||
uint64_t diff;
|
||||
uint64_t idle_poll;
|
||||
unsigned int nfds;
|
||||
unsigned int i;
|
||||
int saved_errno;
|
||||
int have_signals;
|
||||
int nevents;
|
||||
int count;
|
||||
int err;
|
||||
int fd;
|
||||
int user_timeout;
|
||||
int reset_timeout;
|
||||
|
||||
if (loop->nfds == 0) {
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
return;
|
||||
}
|
||||
|
||||
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
|
||||
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);
|
||||
|
||||
if (port_associate(loop->backend_fd,
|
||||
PORT_SOURCE_FD,
|
||||
w->fd,
|
||||
w->pevents,
|
||||
0)) {
|
||||
perror("(libuv) port_associate()");
|
||||
abort();
|
||||
}
|
||||
|
||||
w->events = w->pevents;
|
||||
}
|
||||
|
||||
pset = NULL;
|
||||
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
|
||||
pset = &set;
|
||||
sigemptyset(pset);
|
||||
sigaddset(pset, SIGPROF);
|
||||
}
|
||||
|
||||
assert(timeout >= -1);
|
||||
base = loop->time;
|
||||
count = 48; /* Benchmarks suggest this gives the best throughput. */
|
||||
|
||||
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
|
||||
reset_timeout = 1;
|
||||
user_timeout = timeout;
|
||||
timeout = 0;
|
||||
} else {
|
||||
reset_timeout = 0;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
/* Only need to set the provider_entry_time if timeout != 0. The function
|
||||
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
|
||||
*/
|
||||
if (timeout != 0)
|
||||
uv__metrics_set_provider_entry_time(loop);
|
||||
|
||||
if (timeout != -1) {
|
||||
spec.tv_sec = timeout / 1000;
|
||||
spec.tv_nsec = (timeout % 1000) * 1000000;
|
||||
}
|
||||
|
||||
/* Work around a kernel bug where nfds is not updated. */
|
||||
events[0].portev_source = 0;
|
||||
|
||||
nfds = 1;
|
||||
saved_errno = 0;
|
||||
|
||||
if (pset != NULL)
|
||||
pthread_sigmask(SIG_BLOCK, pset, NULL);
|
||||
|
||||
err = port_getn(loop->backend_fd,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
&nfds,
|
||||
timeout == -1 ? NULL : &spec);
|
||||
|
||||
if (pset != NULL)
|
||||
pthread_sigmask(SIG_UNBLOCK, pset, NULL);
|
||||
|
||||
if (err) {
|
||||
/* Work around another kernel bug: port_getn() may return events even
|
||||
* on error.
|
||||
*/
|
||||
if (errno == EINTR || errno == ETIME) {
|
||||
saved_errno = errno;
|
||||
} else {
|
||||
perror("(libuv) port_getn()");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
SAVE_ERRNO(uv__update_time(loop));
|
||||
|
||||
if (events[0].portev_source == 0) {
|
||||
if (reset_timeout != 0) {
|
||||
timeout = user_timeout;
|
||||
reset_timeout = 0;
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
if (timeout == -1)
|
||||
continue;
|
||||
|
||||
goto update_timeout;
|
||||
}
|
||||
|
||||
if (nfds == 0) {
|
||||
assert(timeout != -1);
|
||||
return;
|
||||
}
|
||||
|
||||
have_signals = 0;
|
||||
nevents = 0;
|
||||
|
||||
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->portev_object;
|
||||
|
||||
/* Skip invalidated events, see uv__platform_invalidate_fd */
|
||||
if (fd == -1)
|
||||
continue;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert((unsigned) fd < loop->nwatchers);
|
||||
|
||||
w = loop->watchers[fd];
|
||||
|
||||
/* File descriptor that we've stopped watching, ignore. */
|
||||
if (w == NULL)
|
||||
continue;
|
||||
|
||||
/* Run signal watchers last. This also affects child process watchers
|
||||
* because those are implemented in terms of signal watchers.
|
||||
*/
|
||||
if (w == &loop->signal_io_watcher) {
|
||||
have_signals = 1;
|
||||
} else {
|
||||
uv__metrics_update_idle_time(loop);
|
||||
w->cb(loop, w, pe->portev_events);
|
||||
}
|
||||
|
||||
nevents++;
|
||||
|
||||
if (w != loop->watchers[fd])
|
||||
continue; /* Disabled by callback. */
|
||||
|
||||
/* Events Ports operates in oneshot mode, rearm timer on next run. */
|
||||
if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue))
|
||||
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
|
||||
}
|
||||
|
||||
if (reset_timeout != 0) {
|
||||
timeout = user_timeout;
|
||||
reset_timeout = 0;
|
||||
}
|
||||
|
||||
if (have_signals != 0) {
|
||||
uv__metrics_update_idle_time(loop);
|
||||
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
|
||||
}
|
||||
|
||||
loop->watchers[loop->nwatchers] = NULL;
|
||||
loop->watchers[loop->nwatchers + 1] = NULL;
|
||||
|
||||
if (have_signals != 0)
|
||||
return; /* Event loop should cycle now so don't poll again. */
|
||||
|
||||
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 (saved_errno == ETIME) {
|
||||
assert(timeout != -1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
if (timeout == -1)
|
||||
continue;
|
||||
|
||||
update_timeout:
|
||||
assert(timeout > 0);
|
||||
|
||||
diff = loop->time - base;
|
||||
if (diff >= (uint64_t) timeout)
|
||||
return;
|
||||
|
||||
timeout -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
return gethrtime();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
ssize_t res;
|
||||
char buf[128];
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid());
|
||||
|
||||
res = *size - 1;
|
||||
if (res > 0)
|
||||
res = readlink(buf, buffer, res);
|
||||
|
||||
if (res == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
buffer[res] = '\0';
|
||||
*size = res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
(void) getloadavg(avg, 3);
|
||||
}
|
||||
|
||||
|
||||
#if defined(PORT_SOURCE_FILE)
|
||||
|
||||
static int uv__fs_event_rearm(uv_fs_event_t *handle) {
|
||||
if (handle->fd == -1)
|
||||
return UV_EBADF;
|
||||
|
||||
if (port_associate(handle->loop->fs_fd,
|
||||
PORT_SOURCE_FILE,
|
||||
(uintptr_t) &handle->fo,
|
||||
FILE_ATTRIB | FILE_MODIFIED,
|
||||
handle) == -1) {
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
handle->fd = PORT_LOADED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__fs_event_read(uv_loop_t* loop,
|
||||
uv__io_t* w,
|
||||
unsigned int revents) {
|
||||
uv_fs_event_t *handle = NULL;
|
||||
timespec_t timeout;
|
||||
port_event_t pe;
|
||||
int events;
|
||||
int r;
|
||||
|
||||
(void) w;
|
||||
(void) revents;
|
||||
|
||||
do {
|
||||
uint_t n = 1;
|
||||
|
||||
/*
|
||||
* Note that our use of port_getn() here (and not port_get()) is deliberate:
|
||||
* there is a bug in event ports (Sun bug 6456558) whereby a zeroed timeout
|
||||
* causes port_get() to return success instead of ETIME when there aren't
|
||||
* actually any events (!); by using port_getn() in lieu of port_get(),
|
||||
* we can at least workaround the bug by checking for zero returned events
|
||||
* and treating it as we would ETIME.
|
||||
*/
|
||||
do {
|
||||
memset(&timeout, 0, sizeof timeout);
|
||||
r = port_getn(loop->fs_fd, &pe, 1, &n, &timeout);
|
||||
}
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if ((r == -1 && errno == ETIME) || n == 0)
|
||||
break;
|
||||
|
||||
handle = (uv_fs_event_t*) pe.portev_user;
|
||||
assert((r == 0) && "unexpected port_get() error");
|
||||
|
||||
events = 0;
|
||||
if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED))
|
||||
events |= UV_CHANGE;
|
||||
if (pe.portev_events & ~(FILE_ATTRIB | FILE_MODIFIED))
|
||||
events |= UV_RENAME;
|
||||
assert(events != 0);
|
||||
handle->fd = PORT_FIRED;
|
||||
handle->cb(handle, NULL, events, 0);
|
||||
|
||||
if (handle->fd != PORT_DELETED) {
|
||||
r = uv__fs_event_rearm(handle);
|
||||
if (r != 0)
|
||||
handle->cb(handle, NULL, 0, r);
|
||||
}
|
||||
}
|
||||
while (handle->fd != PORT_DELETED);
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
uv_fs_event_cb cb,
|
||||
const char* path,
|
||||
unsigned int flags) {
|
||||
int portfd;
|
||||
int first_run;
|
||||
int err;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
return UV_EINVAL;
|
||||
|
||||
first_run = 0;
|
||||
if (handle->loop->fs_fd == -1) {
|
||||
portfd = port_create();
|
||||
if (portfd == -1)
|
||||
return UV__ERR(errno);
|
||||
handle->loop->fs_fd = portfd;
|
||||
first_run = 1;
|
||||
}
|
||||
|
||||
uv__handle_start(handle);
|
||||
handle->path = uv__strdup(path);
|
||||
handle->fd = PORT_UNUSED;
|
||||
handle->cb = cb;
|
||||
|
||||
memset(&handle->fo, 0, sizeof handle->fo);
|
||||
handle->fo.fo_name = handle->path;
|
||||
err = uv__fs_event_rearm(handle);
|
||||
if (err != 0) {
|
||||
uv_fs_event_stop(handle);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (first_run) {
|
||||
uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd);
|
||||
uv__io_start(handle->loop, &handle->loop->fs_event_watcher, POLLIN);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) {
|
||||
port_dissociate(handle->loop->fs_fd,
|
||||
PORT_SOURCE_FILE,
|
||||
(uintptr_t) &handle->fo);
|
||||
}
|
||||
|
||||
handle->fd = PORT_DELETED;
|
||||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
handle->fo.fo_name = NULL;
|
||||
uv__handle_stop(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uv__fs_event_close(uv_fs_event_t* handle) {
|
||||
uv_fs_event_stop(handle);
|
||||
}
|
||||
|
||||
#else /* !defined(PORT_SOURCE_FILE) */
|
||||
|
||||
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
uv_fs_event_cb cb,
|
||||
const char* filename,
|
||||
unsigned int flags) {
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
void uv__fs_event_close(uv_fs_event_t* handle) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
#endif /* defined(PORT_SOURCE_FILE) */
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
psinfo_t psinfo;
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
fd = open("/proc/self/psinfo", O_RDONLY);
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* FIXME(bnoordhuis) Handle EINTR. */
|
||||
err = UV_EINVAL;
|
||||
if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
|
||||
*rss = (size_t)psinfo.pr_rssize * 1024;
|
||||
err = 0;
|
||||
}
|
||||
uv__close(fd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
kstat_ctl_t *kc;
|
||||
kstat_t *ksp;
|
||||
kstat_named_t *knp;
|
||||
|
||||
long hz = sysconf(_SC_CLK_TCK);
|
||||
|
||||
kc = kstat_open();
|
||||
if (kc == NULL)
|
||||
return UV_EPERM;
|
||||
|
||||
ksp = kstat_lookup(kc, (char*) "unix", 0, (char*) "system_misc");
|
||||
if (kstat_read(kc, ksp, NULL) == -1) {
|
||||
*uptime = -1;
|
||||
} else {
|
||||
knp = (kstat_named_t*) kstat_data_lookup(ksp, (char*) "clk_intr");
|
||||
*uptime = knp->value.ul / hz;
|
||||
}
|
||||
kstat_close(kc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
int lookup_instance;
|
||||
kstat_ctl_t *kc;
|
||||
kstat_t *ksp;
|
||||
kstat_named_t *knp;
|
||||
uv_cpu_info_t* cpu_info;
|
||||
|
||||
kc = kstat_open();
|
||||
if (kc == NULL)
|
||||
return UV_EPERM;
|
||||
|
||||
/* Get count of cpus */
|
||||
lookup_instance = 0;
|
||||
while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
|
||||
lookup_instance++;
|
||||
}
|
||||
|
||||
*cpu_infos = uv__malloc(lookup_instance * sizeof(**cpu_infos));
|
||||
if (!(*cpu_infos)) {
|
||||
kstat_close(kc);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
*count = lookup_instance;
|
||||
|
||||
cpu_info = *cpu_infos;
|
||||
lookup_instance = 0;
|
||||
while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
|
||||
if (kstat_read(kc, ksp, NULL) == -1) {
|
||||
cpu_info->speed = 0;
|
||||
cpu_info->model = NULL;
|
||||
} else {
|
||||
knp = kstat_data_lookup(ksp, (char*) "clock_MHz");
|
||||
assert(knp->data_type == KSTAT_DATA_INT32 ||
|
||||
knp->data_type == KSTAT_DATA_INT64);
|
||||
cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32
|
||||
: knp->value.i64;
|
||||
|
||||
knp = kstat_data_lookup(ksp, (char*) "brand");
|
||||
assert(knp->data_type == KSTAT_DATA_STRING);
|
||||
cpu_info->model = uv__strdup(KSTAT_NAMED_STR_PTR(knp));
|
||||
}
|
||||
|
||||
lookup_instance++;
|
||||
cpu_info++;
|
||||
}
|
||||
|
||||
cpu_info = *cpu_infos;
|
||||
lookup_instance = 0;
|
||||
for (;;) {
|
||||
ksp = kstat_lookup(kc, (char*) "cpu", lookup_instance, (char*) "sys");
|
||||
|
||||
if (ksp == NULL)
|
||||
break;
|
||||
|
||||
if (kstat_read(kc, ksp, NULL) == -1) {
|
||||
cpu_info->cpu_times.user = 0;
|
||||
cpu_info->cpu_times.nice = 0;
|
||||
cpu_info->cpu_times.sys = 0;
|
||||
cpu_info->cpu_times.idle = 0;
|
||||
cpu_info->cpu_times.irq = 0;
|
||||
} else {
|
||||
knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_user");
|
||||
assert(knp->data_type == KSTAT_DATA_UINT64);
|
||||
cpu_info->cpu_times.user = knp->value.ui64;
|
||||
|
||||
knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_kernel");
|
||||
assert(knp->data_type == KSTAT_DATA_UINT64);
|
||||
cpu_info->cpu_times.sys = knp->value.ui64;
|
||||
|
||||
knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_idle");
|
||||
assert(knp->data_type == KSTAT_DATA_UINT64);
|
||||
cpu_info->cpu_times.idle = knp->value.ui64;
|
||||
|
||||
knp = kstat_data_lookup(ksp, (char*) "intr");
|
||||
assert(knp->data_type == KSTAT_DATA_UINT64);
|
||||
cpu_info->cpu_times.irq = knp->value.ui64;
|
||||
cpu_info->cpu_times.nice = 0;
|
||||
}
|
||||
|
||||
lookup_instance++;
|
||||
cpu_info++;
|
||||
}
|
||||
|
||||
kstat_close(kc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef SUNOS_NO_IFADDRS
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
#else /* SUNOS_NO_IFADDRS */
|
||||
/*
|
||||
* Inspired By:
|
||||
* https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris
|
||||
* http://www.pauliesworld.org/project/getmac.c
|
||||
*/
|
||||
static int uv__set_phys_addr(uv_interface_address_t* address,
|
||||
struct ifaddrs* ent) {
|
||||
|
||||
struct sockaddr_dl* sa_addr;
|
||||
int sockfd;
|
||||
size_t i;
|
||||
struct arpreq arpreq;
|
||||
|
||||
/* This appears to only work as root */
|
||||
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
|
||||
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
|
||||
for (i = 0; i < sizeof(address->phys_addr); i++) {
|
||||
/* Check that all bytes of phys_addr are zero. */
|
||||
if (address->phys_addr[i] != 0)
|
||||
return 0;
|
||||
}
|
||||
memset(&arpreq, 0, sizeof(arpreq));
|
||||
if (address->address.address4.sin_family == AF_INET) {
|
||||
struct sockaddr_in* sin = ((struct sockaddr_in*)&arpreq.arp_pa);
|
||||
sin->sin_addr.s_addr = address->address.address4.sin_addr.s_addr;
|
||||
} else if (address->address.address4.sin_family == AF_INET6) {
|
||||
struct sockaddr_in6* sin = ((struct sockaddr_in6*)&arpreq.arp_pa);
|
||||
memcpy(sin->sin6_addr.s6_addr,
|
||||
address->address.address6.sin6_addr.s6_addr,
|
||||
sizeof(address->address.address6.sin6_addr.s6_addr));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd < 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) {
|
||||
uv__close(sockfd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr));
|
||||
uv__close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__ifaddr_exclude(struct ifaddrs *ent) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
|
||||
return 1;
|
||||
if (ent->ifa_addr == NULL)
|
||||
return 1;
|
||||
if (ent->ifa_addr->sa_family != AF_INET &&
|
||||
ent->ifa_addr->sa_family != AF_INET6)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
uv_interface_address_t* address;
|
||||
struct ifaddrs* addrs;
|
||||
struct ifaddrs* ent;
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
if (getifaddrs(&addrs))
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* Count the number of interfaces */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (uv__ifaddr_exclude(ent))
|
||||
continue;
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
if (*count == 0) {
|
||||
freeifaddrs(addrs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*addresses = uv__malloc(*count * sizeof(**addresses));
|
||||
if (!(*addresses)) {
|
||||
freeifaddrs(addrs);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
address = *addresses;
|
||||
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (uv__ifaddr_exclude(ent))
|
||||
continue;
|
||||
|
||||
address->name = uv__strdup(ent->ifa_name);
|
||||
|
||||
if (ent->ifa_addr->sa_family == AF_INET6) {
|
||||
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
|
||||
} else {
|
||||
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
|
||||
}
|
||||
|
||||
if (ent->ifa_netmask->sa_family == AF_INET6) {
|
||||
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
|
||||
} else {
|
||||
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
|
||||
}
|
||||
|
||||
address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) ||
|
||||
(ent->ifa_flags & IFF_LOOPBACK));
|
||||
|
||||
uv__set_phys_addr(address, ent);
|
||||
address++;
|
||||
}
|
||||
|
||||
freeifaddrs(addrs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* SUNOS_NO_IFADDRS */
|
||||
|
||||
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);
|
||||
}
|
36
deps/libuv/src/unix/sysinfo-loadavg.c
vendored
Normal file
36
deps/libuv/src/unix/sysinfo-loadavg.c
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
/* 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
struct sysinfo info;
|
||||
|
||||
if (sysinfo(&info) < 0) return;
|
||||
|
||||
avg[0] = (double) info.loads[0] / 65536.0;
|
||||
avg[1] = (double) info.loads[1] / 65536.0;
|
||||
avg[2] = (double) info.loads[2] / 65536.0;
|
||||
}
|
42
deps/libuv/src/unix/sysinfo-memory.c
vendored
Normal file
42
deps/libuv/src/unix/sysinfo-memory.c
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
/* 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
struct sysinfo info;
|
||||
|
||||
if (sysinfo(&info) == 0)
|
||||
return (uint64_t) info.freeram * info.mem_unit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
struct sysinfo info;
|
||||
|
||||
if (sysinfo(&info) == 0)
|
||||
return (uint64_t) info.totalram * info.mem_unit;
|
||||
return 0;
|
||||
}
|
461
deps/libuv/src/unix/tcp.c
vendored
Normal file
461
deps/libuv/src/unix/tcp.c
vendored
Normal file
@ -0,0 +1,461 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
|
||||
struct sockaddr_storage saddr;
|
||||
socklen_t slen;
|
||||
int sockfd;
|
||||
int err;
|
||||
|
||||
err = uv__socket(domain, SOCK_STREAM, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
sockfd = err;
|
||||
|
||||
err = uv__stream_open((uv_stream_t*) handle, sockfd, flags);
|
||||
if (err) {
|
||||
uv__close(sockfd);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (flags & UV_HANDLE_BOUND) {
|
||||
/* Bind this new socket to an arbitrary port */
|
||||
slen = sizeof(saddr);
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen)) {
|
||||
uv__close(sockfd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen)) {
|
||||
uv__close(sockfd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
|
||||
struct sockaddr_storage saddr;
|
||||
socklen_t slen;
|
||||
|
||||
if (domain == AF_UNSPEC) {
|
||||
handle->flags |= flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uv__stream_fd(handle) != -1) {
|
||||
|
||||
if (flags & UV_HANDLE_BOUND) {
|
||||
|
||||
if (handle->flags & UV_HANDLE_BOUND) {
|
||||
/* It is already bound to a port. */
|
||||
handle->flags |= flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Query to see if tcp socket is bound. */
|
||||
slen = sizeof(saddr);
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen))
|
||||
return UV__ERR(errno);
|
||||
|
||||
if ((saddr.ss_family == AF_INET6 &&
|
||||
((struct sockaddr_in6*) &saddr)->sin6_port != 0) ||
|
||||
(saddr.ss_family == AF_INET &&
|
||||
((struct sockaddr_in*) &saddr)->sin_port != 0)) {
|
||||
/* Handle is already bound to a port. */
|
||||
handle->flags |= flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bind to arbitrary port */
|
||||
if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen))
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
handle->flags |= flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return new_socket(handle, domain, flags);
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
|
||||
int domain;
|
||||
|
||||
/* Use the lower 8 bits for the domain */
|
||||
domain = flags & 0xFF;
|
||||
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (flags & ~0xFF)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
|
||||
|
||||
/* If anything fails beyond this point we need to remove the handle from
|
||||
* the handle queue, since it was added by uv__handle_init in uv_stream_init.
|
||||
*/
|
||||
|
||||
if (domain != AF_UNSPEC) {
|
||||
int err = maybe_new_socket(tcp, domain, 0);
|
||||
if (err) {
|
||||
QUEUE_REMOVE(&tcp->handle_queue);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
|
||||
return uv_tcp_init_ex(loop, tcp, AF_UNSPEC);
|
||||
}
|
||||
|
||||
|
||||
int uv__tcp_bind(uv_tcp_t* tcp,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
unsigned int flags) {
|
||||
int err;
|
||||
int on;
|
||||
|
||||
/* Cannot set IPv6-only mode on non-IPv6 socket. */
|
||||
if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
|
||||
return UV_EINVAL;
|
||||
|
||||
err = maybe_new_socket(tcp, addr->sa_family, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
on = 1;
|
||||
if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
|
||||
return UV__ERR(errno);
|
||||
|
||||
#ifndef __OpenBSD__
|
||||
#ifdef IPV6_V6ONLY
|
||||
if (addr->sa_family == AF_INET6) {
|
||||
on = (flags & UV_TCP_IPV6ONLY) != 0;
|
||||
if (setsockopt(tcp->io_watcher.fd,
|
||||
IPPROTO_IPV6,
|
||||
IPV6_V6ONLY,
|
||||
&on,
|
||||
sizeof on) == -1) {
|
||||
#if defined(__MVS__)
|
||||
if (errno == EOPNOTSUPP)
|
||||
return UV_EINVAL;
|
||||
#endif
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
errno = 0;
|
||||
if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) {
|
||||
if (errno == EAFNOSUPPORT)
|
||||
/* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
|
||||
* socket created with AF_INET to an AF_INET6 address or vice versa. */
|
||||
return UV_EINVAL;
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
tcp->delayed_error = UV__ERR(errno);
|
||||
|
||||
tcp->flags |= UV_HANDLE_BOUND;
|
||||
if (addr->sa_family == AF_INET6)
|
||||
tcp->flags |= UV_HANDLE_IPV6;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__tcp_connect(uv_connect_t* req,
|
||||
uv_tcp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
uv_connect_cb cb) {
|
||||
int err;
|
||||
int r;
|
||||
|
||||
assert(handle->type == UV_TCP);
|
||||
|
||||
if (handle->connect_req != NULL)
|
||||
return UV_EALREADY; /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */
|
||||
|
||||
err = maybe_new_socket(handle,
|
||||
addr->sa_family,
|
||||
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
handle->delayed_error = 0;
|
||||
|
||||
do {
|
||||
errno = 0;
|
||||
r = connect(uv__stream_fd(handle), addr, addrlen);
|
||||
} while (r == -1 && errno == EINTR);
|
||||
|
||||
/* We not only check the return value, but also check the errno != 0.
|
||||
* Because in rare cases connect() will return -1 but the errno
|
||||
* is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227)
|
||||
* and actually the tcp three-way handshake is completed.
|
||||
*/
|
||||
if (r == -1 && errno != 0) {
|
||||
if (errno == EINPROGRESS)
|
||||
; /* not an error */
|
||||
else if (errno == ECONNREFUSED
|
||||
#if defined(__OpenBSD__)
|
||||
|| errno == EINVAL
|
||||
#endif
|
||||
)
|
||||
/* If we get ECONNREFUSED (Solaris) or EINVAL (OpenBSD) wait until the
|
||||
* next tick to report the error. Solaris and OpenBSD wants to report
|
||||
* immediately -- other unixes want to wait.
|
||||
*/
|
||||
handle->delayed_error = UV__ERR(ECONNREFUSED);
|
||||
else
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
uv__req_init(handle->loop, req, UV_CONNECT);
|
||||
req->cb = cb;
|
||||
req->handle = (uv_stream_t*) handle;
|
||||
QUEUE_INIT(&req->queue);
|
||||
handle->connect_req = req;
|
||||
|
||||
uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
|
||||
|
||||
if (handle->delayed_error)
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
|
||||
int err;
|
||||
|
||||
if (uv__fd_exists(handle->loop, sock))
|
||||
return UV_EEXIST;
|
||||
|
||||
err = uv__nonblock(sock, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return uv__stream_open((uv_stream_t*)handle,
|
||||
sock,
|
||||
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_getsockname(const uv_tcp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen) {
|
||||
|
||||
if (handle->delayed_error)
|
||||
return handle->delayed_error;
|
||||
|
||||
return uv__getsockpeername((const uv_handle_t*) handle,
|
||||
getsockname,
|
||||
name,
|
||||
namelen);
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_getpeername(const uv_tcp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen) {
|
||||
|
||||
if (handle->delayed_error)
|
||||
return handle->delayed_error;
|
||||
|
||||
return uv__getsockpeername((const uv_handle_t*) handle,
|
||||
getpeername,
|
||||
name,
|
||||
namelen);
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
|
||||
int fd;
|
||||
struct linger l = { 1, 0 };
|
||||
|
||||
/* Disallow setting SO_LINGER to zero due to some platform inconsistencies */
|
||||
if (handle->flags & UV_HANDLE_SHUTTING)
|
||||
return UV_EINVAL;
|
||||
|
||||
fd = uv__stream_fd(handle);
|
||||
if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)))
|
||||
return UV__ERR(errno);
|
||||
|
||||
uv_close((uv_handle_t*) handle, close_cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
|
||||
static int single_accept_cached = -1;
|
||||
unsigned long flags;
|
||||
int single_accept;
|
||||
int err;
|
||||
|
||||
if (tcp->delayed_error)
|
||||
return tcp->delayed_error;
|
||||
|
||||
single_accept = uv__load_relaxed(&single_accept_cached);
|
||||
if (single_accept == -1) {
|
||||
const char* val = getenv("UV_TCP_SINGLE_ACCEPT");
|
||||
single_accept = (val != NULL && atoi(val) != 0); /* Off by default. */
|
||||
uv__store_relaxed(&single_accept_cached, single_accept);
|
||||
}
|
||||
|
||||
if (single_accept)
|
||||
tcp->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
|
||||
|
||||
flags = 0;
|
||||
#if defined(__MVS__)
|
||||
/* on zOS the listen call does not bind automatically
|
||||
if the socket is unbound. Hence the manual binding to
|
||||
an arbitrary port is required to be done manually
|
||||
*/
|
||||
flags |= UV_HANDLE_BOUND;
|
||||
#endif
|
||||
err = maybe_new_socket(tcp, AF_INET, flags);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (listen(tcp->io_watcher.fd, backlog))
|
||||
return UV__ERR(errno);
|
||||
|
||||
tcp->connection_cb = cb;
|
||||
tcp->flags |= UV_HANDLE_BOUND;
|
||||
|
||||
/* Start listening for connections. */
|
||||
tcp->io_watcher.cb = uv__server_io;
|
||||
uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__tcp_nodelay(int fd, int on) {
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)))
|
||||
return UV__ERR(errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
|
||||
return UV__ERR(errno);
|
||||
|
||||
#ifdef TCP_KEEPIDLE
|
||||
if (on) {
|
||||
int intvl = 1; /* 1 second; same as default on Win32 */
|
||||
int cnt = 10; /* 10 retries; same as hardcoded on Win32 */
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
|
||||
return UV__ERR(errno);
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
|
||||
return UV__ERR(errno);
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Solaris/SmartOS, if you don't support keep-alive,
|
||||
* then don't advertise it in your system headers...
|
||||
*/
|
||||
/* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */
|
||||
#if defined(TCP_KEEPALIVE) && !defined(__sun)
|
||||
if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
|
||||
return UV__ERR(errno);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
|
||||
int err;
|
||||
|
||||
if (uv__stream_fd(handle) != -1) {
|
||||
err = uv__tcp_nodelay(uv__stream_fd(handle), on);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (on)
|
||||
handle->flags |= UV_HANDLE_TCP_NODELAY;
|
||||
else
|
||||
handle->flags &= ~UV_HANDLE_TCP_NODELAY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
|
||||
int err;
|
||||
|
||||
if (uv__stream_fd(handle) != -1) {
|
||||
err =uv__tcp_keepalive(uv__stream_fd(handle), on, delay);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (on)
|
||||
handle->flags |= UV_HANDLE_TCP_KEEPALIVE;
|
||||
else
|
||||
handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE;
|
||||
|
||||
/* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge
|
||||
* uv_tcp_t with an int that's almost never used...
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
|
||||
if (enable)
|
||||
handle->flags &= ~UV_HANDLE_TCP_SINGLE_ACCEPT;
|
||||
else
|
||||
handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__tcp_close(uv_tcp_t* handle) {
|
||||
uv__stream_close((uv_stream_t*)handle);
|
||||
}
|
842
deps/libuv/src/unix/thread.c
vendored
Normal file
842
deps/libuv/src/unix/thread.c
vendored
Normal file
@ -0,0 +1,842 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h> /* getrlimit() */
|
||||
#include <unistd.h> /* getpagesize() */
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __MVS__
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/sem.h>
|
||||
#endif
|
||||
|
||||
#if defined(__GLIBC__) && !defined(__UCLIBC__)
|
||||
#include <gnu/libc-version.h> /* gnu_get_libc_version() */
|
||||
#endif
|
||||
|
||||
#undef NANOSEC
|
||||
#define NANOSEC ((uint64_t) 1e9)
|
||||
|
||||
#if defined(PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t));
|
||||
#endif
|
||||
|
||||
/* Note: guard clauses should match uv_barrier_t's in include/uv/unix.h. */
|
||||
#if defined(_AIX) || \
|
||||
defined(__OpenBSD__) || \
|
||||
!defined(PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
|
||||
struct _uv_barrier* b;
|
||||
int rc;
|
||||
|
||||
if (barrier == NULL || count == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
b = uv__malloc(sizeof(*b));
|
||||
if (b == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
b->in = 0;
|
||||
b->out = 0;
|
||||
b->threshold = count;
|
||||
|
||||
rc = uv_mutex_init(&b->mutex);
|
||||
if (rc != 0)
|
||||
goto error2;
|
||||
|
||||
rc = uv_cond_init(&b->cond);
|
||||
if (rc != 0)
|
||||
goto error;
|
||||
|
||||
barrier->b = b;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
uv_mutex_destroy(&b->mutex);
|
||||
error2:
|
||||
uv__free(b);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int uv_barrier_wait(uv_barrier_t* barrier) {
|
||||
struct _uv_barrier* b;
|
||||
int last;
|
||||
|
||||
if (barrier == NULL || barrier->b == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
b = barrier->b;
|
||||
uv_mutex_lock(&b->mutex);
|
||||
|
||||
if (++b->in == b->threshold) {
|
||||
b->in = 0;
|
||||
b->out = b->threshold;
|
||||
uv_cond_signal(&b->cond);
|
||||
} else {
|
||||
do
|
||||
uv_cond_wait(&b->cond, &b->mutex);
|
||||
while (b->in != 0);
|
||||
}
|
||||
|
||||
last = (--b->out == 0);
|
||||
if (!last)
|
||||
uv_cond_signal(&b->cond); /* Not needed for last thread. */
|
||||
|
||||
uv_mutex_unlock(&b->mutex);
|
||||
return last;
|
||||
}
|
||||
|
||||
|
||||
void uv_barrier_destroy(uv_barrier_t* barrier) {
|
||||
struct _uv_barrier* b;
|
||||
|
||||
b = barrier->b;
|
||||
uv_mutex_lock(&b->mutex);
|
||||
|
||||
assert(b->in == 0);
|
||||
assert(b->out == 0);
|
||||
|
||||
if (b->in != 0 || b->out != 0)
|
||||
abort();
|
||||
|
||||
uv_mutex_unlock(&b->mutex);
|
||||
uv_mutex_destroy(&b->mutex);
|
||||
uv_cond_destroy(&b->cond);
|
||||
|
||||
uv__free(barrier->b);
|
||||
barrier->b = NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
|
||||
return UV__ERR(pthread_barrier_init(barrier, NULL, count));
|
||||
}
|
||||
|
||||
|
||||
int uv_barrier_wait(uv_barrier_t* barrier) {
|
||||
int rc;
|
||||
|
||||
rc = pthread_barrier_wait(barrier);
|
||||
if (rc != 0)
|
||||
if (rc != PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
abort();
|
||||
|
||||
return rc == PTHREAD_BARRIER_SERIAL_THREAD;
|
||||
}
|
||||
|
||||
|
||||
void uv_barrier_destroy(uv_barrier_t* barrier) {
|
||||
if (pthread_barrier_destroy(barrier))
|
||||
abort();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* On MacOS, threads other than the main thread are created with a reduced
|
||||
* stack size by default. Adjust to RLIMIT_STACK aligned to the page size.
|
||||
*
|
||||
* On Linux, threads created by musl have a much smaller stack than threads
|
||||
* created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency.
|
||||
*/
|
||||
static size_t thread_stack_size(void) {
|
||||
#if defined(__APPLE__) || defined(__linux__)
|
||||
struct rlimit lim;
|
||||
|
||||
/* getrlimit() can fail on some aarch64 systems due to a glibc bug where
|
||||
* the system call wrapper invokes the wrong system call. Don't treat
|
||||
* that as fatal, just use the default stack size instead.
|
||||
*/
|
||||
if (0 == getrlimit(RLIMIT_STACK, &lim) && lim.rlim_cur != RLIM_INFINITY) {
|
||||
/* pthread_attr_setstacksize() expects page-aligned values. */
|
||||
lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
|
||||
|
||||
/* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is
|
||||
* too small to safely receive signals on.
|
||||
*
|
||||
* Musl's PTHREAD_STACK_MIN + MINSIGSTKSZ == 8192 on arm64 (which has
|
||||
* the largest MINSIGSTKSZ of the architectures that musl supports) so
|
||||
* let's use that as a lower bound.
|
||||
*
|
||||
* We use a hardcoded value because PTHREAD_STACK_MIN + MINSIGSTKSZ
|
||||
* is between 28 and 133 KB when compiling against glibc, depending
|
||||
* on the architecture.
|
||||
*/
|
||||
if (lim.rlim_cur >= 8192)
|
||||
if (lim.rlim_cur >= PTHREAD_STACK_MIN)
|
||||
return lim.rlim_cur;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(__linux__)
|
||||
return 0;
|
||||
#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__)
|
||||
return 4 << 20; /* glibc default. */
|
||||
#else
|
||||
return 2 << 20; /* glibc default. */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
||||
uv_thread_options_t params;
|
||||
params.flags = UV_THREAD_NO_FLAGS;
|
||||
return uv_thread_create_ex(tid, ¶ms, entry, arg);
|
||||
}
|
||||
|
||||
int uv_thread_create_ex(uv_thread_t* tid,
|
||||
const uv_thread_options_t* params,
|
||||
void (*entry)(void *arg),
|
||||
void *arg) {
|
||||
int err;
|
||||
pthread_attr_t* attr;
|
||||
pthread_attr_t attr_storage;
|
||||
size_t pagesize;
|
||||
size_t stack_size;
|
||||
|
||||
/* Used to squelch a -Wcast-function-type warning. */
|
||||
union {
|
||||
void (*in)(void*);
|
||||
void* (*out)(void*);
|
||||
} f;
|
||||
|
||||
stack_size =
|
||||
params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
|
||||
|
||||
attr = NULL;
|
||||
if (stack_size == 0) {
|
||||
stack_size = thread_stack_size();
|
||||
} else {
|
||||
pagesize = (size_t)getpagesize();
|
||||
/* Round up to the nearest page boundary. */
|
||||
stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1);
|
||||
#ifdef PTHREAD_STACK_MIN
|
||||
if (stack_size < PTHREAD_STACK_MIN)
|
||||
stack_size = PTHREAD_STACK_MIN;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (stack_size > 0) {
|
||||
attr = &attr_storage;
|
||||
|
||||
if (pthread_attr_init(attr))
|
||||
abort();
|
||||
|
||||
if (pthread_attr_setstacksize(attr, stack_size))
|
||||
abort();
|
||||
}
|
||||
|
||||
f.in = entry;
|
||||
err = pthread_create(tid, attr, f.out, arg);
|
||||
|
||||
if (attr != NULL)
|
||||
pthread_attr_destroy(attr);
|
||||
|
||||
return UV__ERR(err);
|
||||
}
|
||||
|
||||
|
||||
uv_thread_t uv_thread_self(void) {
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
int uv_thread_join(uv_thread_t *tid) {
|
||||
return UV__ERR(pthread_join(*tid, NULL));
|
||||
}
|
||||
|
||||
|
||||
int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
|
||||
return pthread_equal(*t1, *t2);
|
||||
}
|
||||
|
||||
|
||||
int uv_mutex_init(uv_mutex_t* mutex) {
|
||||
#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK)
|
||||
return UV__ERR(pthread_mutex_init(mutex, NULL));
|
||||
#else
|
||||
pthread_mutexattr_t attr;
|
||||
int err;
|
||||
|
||||
if (pthread_mutexattr_init(&attr))
|
||||
abort();
|
||||
|
||||
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK))
|
||||
abort();
|
||||
|
||||
err = pthread_mutex_init(mutex, &attr);
|
||||
|
||||
if (pthread_mutexattr_destroy(&attr))
|
||||
abort();
|
||||
|
||||
return UV__ERR(err);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv_mutex_init_recursive(uv_mutex_t* mutex) {
|
||||
pthread_mutexattr_t attr;
|
||||
int err;
|
||||
|
||||
if (pthread_mutexattr_init(&attr))
|
||||
abort();
|
||||
|
||||
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
|
||||
abort();
|
||||
|
||||
err = pthread_mutex_init(mutex, &attr);
|
||||
|
||||
if (pthread_mutexattr_destroy(&attr))
|
||||
abort();
|
||||
|
||||
return UV__ERR(err);
|
||||
}
|
||||
|
||||
|
||||
void uv_mutex_destroy(uv_mutex_t* mutex) {
|
||||
if (pthread_mutex_destroy(mutex))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_mutex_lock(uv_mutex_t* mutex) {
|
||||
if (pthread_mutex_lock(mutex))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_mutex_trylock(uv_mutex_t* mutex) {
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_trylock(mutex);
|
||||
if (err) {
|
||||
if (err != EBUSY && err != EAGAIN)
|
||||
abort();
|
||||
return UV_EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_mutex_unlock(uv_mutex_t* mutex) {
|
||||
if (pthread_mutex_unlock(mutex))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_rwlock_init(uv_rwlock_t* rwlock) {
|
||||
return UV__ERR(pthread_rwlock_init(rwlock, NULL));
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
|
||||
if (pthread_rwlock_destroy(rwlock))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
|
||||
if (pthread_rwlock_rdlock(rwlock))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
|
||||
int err;
|
||||
|
||||
err = pthread_rwlock_tryrdlock(rwlock);
|
||||
if (err) {
|
||||
if (err != EBUSY && err != EAGAIN)
|
||||
abort();
|
||||
return UV_EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
|
||||
if (pthread_rwlock_unlock(rwlock))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
|
||||
if (pthread_rwlock_wrlock(rwlock))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
|
||||
int err;
|
||||
|
||||
err = pthread_rwlock_trywrlock(rwlock);
|
||||
if (err) {
|
||||
if (err != EBUSY && err != EAGAIN)
|
||||
abort();
|
||||
return UV_EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
|
||||
if (pthread_rwlock_unlock(rwlock))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_once(uv_once_t* guard, void (*callback)(void)) {
|
||||
if (pthread_once(guard, callback))
|
||||
abort();
|
||||
}
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
|
||||
int uv_sem_init(uv_sem_t* sem, unsigned int value) {
|
||||
kern_return_t err;
|
||||
|
||||
err = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value);
|
||||
if (err == KERN_SUCCESS)
|
||||
return 0;
|
||||
if (err == KERN_INVALID_ARGUMENT)
|
||||
return UV_EINVAL;
|
||||
if (err == KERN_RESOURCE_SHORTAGE)
|
||||
return UV_ENOMEM;
|
||||
|
||||
abort();
|
||||
return UV_EINVAL; /* Satisfy the compiler. */
|
||||
}
|
||||
|
||||
|
||||
void uv_sem_destroy(uv_sem_t* sem) {
|
||||
if (semaphore_destroy(mach_task_self(), *sem))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_sem_post(uv_sem_t* sem) {
|
||||
if (semaphore_signal(*sem))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_sem_wait(uv_sem_t* sem) {
|
||||
int r;
|
||||
|
||||
do
|
||||
r = semaphore_wait(*sem);
|
||||
while (r == KERN_ABORTED);
|
||||
|
||||
if (r != KERN_SUCCESS)
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_sem_trywait(uv_sem_t* sem) {
|
||||
mach_timespec_t interval;
|
||||
kern_return_t err;
|
||||
|
||||
interval.tv_sec = 0;
|
||||
interval.tv_nsec = 0;
|
||||
|
||||
err = semaphore_timedwait(*sem, interval);
|
||||
if (err == KERN_SUCCESS)
|
||||
return 0;
|
||||
if (err == KERN_OPERATION_TIMED_OUT)
|
||||
return UV_EAGAIN;
|
||||
|
||||
abort();
|
||||
return UV_EINVAL; /* Satisfy the compiler. */
|
||||
}
|
||||
|
||||
#else /* !(defined(__APPLE__) && defined(__MACH__)) */
|
||||
|
||||
#if defined(__GLIBC__) && !defined(__UCLIBC__)
|
||||
|
||||
/* Hack around https://sourceware.org/bugzilla/show_bug.cgi?id=12674
|
||||
* by providing a custom implementation for glibc < 2.21 in terms of other
|
||||
* concurrency primitives.
|
||||
* Refs: https://github.com/nodejs/node/issues/19903 */
|
||||
|
||||
/* To preserve ABI compatibility, we treat the uv_sem_t as storage for
|
||||
* a pointer to the actual struct we're using underneath. */
|
||||
|
||||
static uv_once_t glibc_version_check_once = UV_ONCE_INIT;
|
||||
static int platform_needs_custom_semaphore = 0;
|
||||
|
||||
static void glibc_version_check(void) {
|
||||
const char* version = gnu_get_libc_version();
|
||||
platform_needs_custom_semaphore =
|
||||
version[0] == '2' && version[1] == '.' &&
|
||||
atoi(version + 2) < 21;
|
||||
}
|
||||
|
||||
#elif defined(__MVS__)
|
||||
|
||||
#define platform_needs_custom_semaphore 1
|
||||
|
||||
#else /* !defined(__GLIBC__) && !defined(__MVS__) */
|
||||
|
||||
#define platform_needs_custom_semaphore 0
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct uv_semaphore_s {
|
||||
uv_mutex_t mutex;
|
||||
uv_cond_t cond;
|
||||
unsigned int value;
|
||||
} uv_semaphore_t;
|
||||
|
||||
#if (defined(__GLIBC__) && !defined(__UCLIBC__)) || \
|
||||
platform_needs_custom_semaphore
|
||||
STATIC_ASSERT(sizeof(uv_sem_t) >= sizeof(uv_semaphore_t*));
|
||||
#endif
|
||||
|
||||
static int uv__custom_sem_init(uv_sem_t* sem_, unsigned int value) {
|
||||
int err;
|
||||
uv_semaphore_t* sem;
|
||||
|
||||
sem = uv__malloc(sizeof(*sem));
|
||||
if (sem == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
if ((err = uv_mutex_init(&sem->mutex)) != 0) {
|
||||
uv__free(sem);
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = uv_cond_init(&sem->cond)) != 0) {
|
||||
uv_mutex_destroy(&sem->mutex);
|
||||
uv__free(sem);
|
||||
return err;
|
||||
}
|
||||
|
||||
sem->value = value;
|
||||
*(uv_semaphore_t**)sem_ = sem;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__custom_sem_destroy(uv_sem_t* sem_) {
|
||||
uv_semaphore_t* sem;
|
||||
|
||||
sem = *(uv_semaphore_t**)sem_;
|
||||
uv_cond_destroy(&sem->cond);
|
||||
uv_mutex_destroy(&sem->mutex);
|
||||
uv__free(sem);
|
||||
}
|
||||
|
||||
|
||||
static void uv__custom_sem_post(uv_sem_t* sem_) {
|
||||
uv_semaphore_t* sem;
|
||||
|
||||
sem = *(uv_semaphore_t**)sem_;
|
||||
uv_mutex_lock(&sem->mutex);
|
||||
sem->value++;
|
||||
if (sem->value == 1)
|
||||
uv_cond_signal(&sem->cond);
|
||||
uv_mutex_unlock(&sem->mutex);
|
||||
}
|
||||
|
||||
|
||||
static void uv__custom_sem_wait(uv_sem_t* sem_) {
|
||||
uv_semaphore_t* sem;
|
||||
|
||||
sem = *(uv_semaphore_t**)sem_;
|
||||
uv_mutex_lock(&sem->mutex);
|
||||
while (sem->value == 0)
|
||||
uv_cond_wait(&sem->cond, &sem->mutex);
|
||||
sem->value--;
|
||||
uv_mutex_unlock(&sem->mutex);
|
||||
}
|
||||
|
||||
|
||||
static int uv__custom_sem_trywait(uv_sem_t* sem_) {
|
||||
uv_semaphore_t* sem;
|
||||
|
||||
sem = *(uv_semaphore_t**)sem_;
|
||||
if (uv_mutex_trylock(&sem->mutex) != 0)
|
||||
return UV_EAGAIN;
|
||||
|
||||
if (sem->value == 0) {
|
||||
uv_mutex_unlock(&sem->mutex);
|
||||
return UV_EAGAIN;
|
||||
}
|
||||
|
||||
sem->value--;
|
||||
uv_mutex_unlock(&sem->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uv__sem_init(uv_sem_t* sem, unsigned int value) {
|
||||
if (sem_init(sem, 0, value))
|
||||
return UV__ERR(errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__sem_destroy(uv_sem_t* sem) {
|
||||
if (sem_destroy(sem))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
static void uv__sem_post(uv_sem_t* sem) {
|
||||
if (sem_post(sem))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
static void uv__sem_wait(uv_sem_t* sem) {
|
||||
int r;
|
||||
|
||||
do
|
||||
r = sem_wait(sem);
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r)
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
static int uv__sem_trywait(uv_sem_t* sem) {
|
||||
int r;
|
||||
|
||||
do
|
||||
r = sem_trywait(sem);
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r) {
|
||||
if (errno == EAGAIN)
|
||||
return UV_EAGAIN;
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_sem_init(uv_sem_t* sem, unsigned int value) {
|
||||
#if defined(__GLIBC__) && !defined(__UCLIBC__)
|
||||
uv_once(&glibc_version_check_once, glibc_version_check);
|
||||
#endif
|
||||
|
||||
if (platform_needs_custom_semaphore)
|
||||
return uv__custom_sem_init(sem, value);
|
||||
else
|
||||
return uv__sem_init(sem, value);
|
||||
}
|
||||
|
||||
|
||||
void uv_sem_destroy(uv_sem_t* sem) {
|
||||
if (platform_needs_custom_semaphore)
|
||||
uv__custom_sem_destroy(sem);
|
||||
else
|
||||
uv__sem_destroy(sem);
|
||||
}
|
||||
|
||||
|
||||
void uv_sem_post(uv_sem_t* sem) {
|
||||
if (platform_needs_custom_semaphore)
|
||||
uv__custom_sem_post(sem);
|
||||
else
|
||||
uv__sem_post(sem);
|
||||
}
|
||||
|
||||
|
||||
void uv_sem_wait(uv_sem_t* sem) {
|
||||
if (platform_needs_custom_semaphore)
|
||||
uv__custom_sem_wait(sem);
|
||||
else
|
||||
uv__sem_wait(sem);
|
||||
}
|
||||
|
||||
|
||||
int uv_sem_trywait(uv_sem_t* sem) {
|
||||
if (platform_needs_custom_semaphore)
|
||||
return uv__custom_sem_trywait(sem);
|
||||
else
|
||||
return uv__sem_trywait(sem);
|
||||
}
|
||||
|
||||
#endif /* defined(__APPLE__) && defined(__MACH__) */
|
||||
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__)
|
||||
|
||||
int uv_cond_init(uv_cond_t* cond) {
|
||||
return UV__ERR(pthread_cond_init(cond, NULL));
|
||||
}
|
||||
|
||||
#else /* !(defined(__APPLE__) && defined(__MACH__)) */
|
||||
|
||||
int uv_cond_init(uv_cond_t* cond) {
|
||||
pthread_condattr_t attr;
|
||||
int err;
|
||||
|
||||
err = pthread_condattr_init(&attr);
|
||||
if (err)
|
||||
return UV__ERR(err);
|
||||
|
||||
err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
|
||||
if (err)
|
||||
goto error2;
|
||||
|
||||
err = pthread_cond_init(cond, &attr);
|
||||
if (err)
|
||||
goto error2;
|
||||
|
||||
err = pthread_condattr_destroy(&attr);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
pthread_cond_destroy(cond);
|
||||
error2:
|
||||
pthread_condattr_destroy(&attr);
|
||||
return UV__ERR(err);
|
||||
}
|
||||
|
||||
#endif /* defined(__APPLE__) && defined(__MACH__) */
|
||||
|
||||
void uv_cond_destroy(uv_cond_t* cond) {
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
/* It has been reported that destroying condition variables that have been
|
||||
* signalled but not waited on can sometimes result in application crashes.
|
||||
* See https://codereview.chromium.org/1323293005.
|
||||
*/
|
||||
pthread_mutex_t mutex;
|
||||
struct timespec ts;
|
||||
int err;
|
||||
|
||||
if (pthread_mutex_init(&mutex, NULL))
|
||||
abort();
|
||||
|
||||
if (pthread_mutex_lock(&mutex))
|
||||
abort();
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1;
|
||||
|
||||
err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts);
|
||||
if (err != 0 && err != ETIMEDOUT)
|
||||
abort();
|
||||
|
||||
if (pthread_mutex_unlock(&mutex))
|
||||
abort();
|
||||
|
||||
if (pthread_mutex_destroy(&mutex))
|
||||
abort();
|
||||
#endif /* defined(__APPLE__) && defined(__MACH__) */
|
||||
|
||||
if (pthread_cond_destroy(cond))
|
||||
abort();
|
||||
}
|
||||
|
||||
void uv_cond_signal(uv_cond_t* cond) {
|
||||
if (pthread_cond_signal(cond))
|
||||
abort();
|
||||
}
|
||||
|
||||
void uv_cond_broadcast(uv_cond_t* cond) {
|
||||
if (pthread_cond_broadcast(cond))
|
||||
abort();
|
||||
}
|
||||
|
||||
void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
|
||||
if (pthread_cond_wait(cond, mutex))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
|
||||
int r;
|
||||
struct timespec ts;
|
||||
#if defined(__MVS__)
|
||||
struct timeval tv;
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
ts.tv_sec = timeout / NANOSEC;
|
||||
ts.tv_nsec = timeout % NANOSEC;
|
||||
r = pthread_cond_timedwait_relative_np(cond, mutex, &ts);
|
||||
#else
|
||||
#if defined(__MVS__)
|
||||
if (gettimeofday(&tv, NULL))
|
||||
abort();
|
||||
timeout += tv.tv_sec * NANOSEC + tv.tv_usec * 1e3;
|
||||
#else
|
||||
timeout += uv__hrtime(UV_CLOCK_PRECISE);
|
||||
#endif
|
||||
ts.tv_sec = timeout / NANOSEC;
|
||||
ts.tv_nsec = timeout % NANOSEC;
|
||||
r = pthread_cond_timedwait(cond, mutex, &ts);
|
||||
#endif
|
||||
|
||||
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
if (r == ETIMEDOUT)
|
||||
return UV_ETIMEDOUT;
|
||||
|
||||
abort();
|
||||
#ifndef __SUNPRO_C
|
||||
return UV_EINVAL; /* Satisfy the compiler. */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv_key_create(uv_key_t* key) {
|
||||
return UV__ERR(pthread_key_create(key, NULL));
|
||||
}
|
||||
|
||||
|
||||
void uv_key_delete(uv_key_t* key) {
|
||||
if (pthread_key_delete(*key))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void* uv_key_get(uv_key_t* key) {
|
||||
return pthread_getspecific(*key);
|
||||
}
|
||||
|
||||
|
||||
void uv_key_set(uv_key_t* key, void* value) {
|
||||
if (pthread_setspecific(*key, value))
|
||||
abort();
|
||||
}
|
402
deps/libuv/src/unix/tty.c
vendored
Normal file
402
deps/libuv/src/unix/tty.c
vendored
Normal file
@ -0,0 +1,402 @@
|
||||
/* Copyright Joyent, Inc. and other Node 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 "uv.h"
|
||||
#include "internal.h"
|
||||
#include "spinlock.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#if defined(__MVS__) && !defined(IMAXBEL)
|
||||
#define IMAXBEL 0
|
||||
#endif
|
||||
|
||||
#if defined(__PASE__)
|
||||
/* On IBM i PASE, for better compatibility with running interactive programs in
|
||||
* a 5250 environment, isatty() will return true for the stdin/stdout/stderr
|
||||
* streams created by QSH/QP2TERM.
|
||||
*
|
||||
* For more, see docs on PASE_STDIO_ISATTY in
|
||||
* https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_74/apis/pase_environ.htm
|
||||
*
|
||||
* This behavior causes problems for Node as it expects that if isatty() returns
|
||||
* true that TTY ioctls will be supported by that fd (which is not an
|
||||
* unreasonable expectation) and when they don't it crashes with assertion
|
||||
* errors.
|
||||
*
|
||||
* Here, we create our own version of isatty() that uses ioctl() to identify
|
||||
* whether the fd is *really* a TTY or not.
|
||||
*/
|
||||
static int isreallyatty(int file) {
|
||||
int rc;
|
||||
|
||||
rc = !ioctl(file, TXISATTY + 0x81, NULL);
|
||||
if (!rc && errno != EBADF)
|
||||
errno = ENOTTY;
|
||||
|
||||
return rc;
|
||||
}
|
||||
#define isatty(fd) isreallyatty(fd)
|
||||
#endif
|
||||
|
||||
static int orig_termios_fd = -1;
|
||||
static struct termios orig_termios;
|
||||
static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
|
||||
|
||||
static int uv__tty_is_slave(const int fd) {
|
||||
int result;
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
int dummy;
|
||||
|
||||
result = ioctl(fd, TIOCGPTN, &dummy) != 0;
|
||||
#elif defined(__APPLE__)
|
||||
char dummy[256];
|
||||
|
||||
result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0;
|
||||
#elif defined(__NetBSD__)
|
||||
/*
|
||||
* NetBSD as an extension returns with ptsname(3) and ptsname_r(3) the slave
|
||||
* device name for both descriptors, the master one and slave one.
|
||||
*
|
||||
* Implement function to compare major device number with pts devices.
|
||||
*
|
||||
* The major numbers are machine-dependent, on NetBSD/amd64 they are
|
||||
* respectively:
|
||||
* - master tty: ptc - major 6
|
||||
* - slave tty: pts - major 5
|
||||
*/
|
||||
|
||||
struct stat sb;
|
||||
/* Lookup device's major for the pts driver and cache it. */
|
||||
static devmajor_t pts = NODEVMAJOR;
|
||||
|
||||
if (pts == NODEVMAJOR) {
|
||||
pts = getdevmajor("pts", S_IFCHR);
|
||||
if (pts == NODEVMAJOR)
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Lookup stat structure behind the file descriptor. */
|
||||
if (fstat(fd, &sb) != 0)
|
||||
abort();
|
||||
|
||||
/* Assert character device. */
|
||||
if (!S_ISCHR(sb.st_mode))
|
||||
abort();
|
||||
|
||||
/* Assert valid major. */
|
||||
if (major(sb.st_rdev) == NODEVMAJOR)
|
||||
abort();
|
||||
|
||||
result = (pts == major(sb.st_rdev));
|
||||
#else
|
||||
/* Fallback to ptsname
|
||||
*/
|
||||
result = ptsname(fd) == NULL;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) {
|
||||
uv_handle_type type;
|
||||
int flags;
|
||||
int newfd;
|
||||
int r;
|
||||
int saved_flags;
|
||||
int mode;
|
||||
char path[256];
|
||||
(void)unused; /* deprecated parameter is no longer needed */
|
||||
|
||||
/* File descriptors that refer to files cannot be monitored with epoll.
|
||||
* That restriction also applies to character devices like /dev/random
|
||||
* (but obviously not /dev/tty.)
|
||||
*/
|
||||
type = uv_guess_handle(fd);
|
||||
if (type == UV_FILE || type == UV_UNKNOWN_HANDLE)
|
||||
return UV_EINVAL;
|
||||
|
||||
flags = 0;
|
||||
newfd = -1;
|
||||
|
||||
/* Save the fd flags in case we need to restore them due to an error. */
|
||||
do
|
||||
saved_flags = fcntl(fd, F_GETFL);
|
||||
while (saved_flags == -1 && errno == EINTR);
|
||||
|
||||
if (saved_flags == -1)
|
||||
return UV__ERR(errno);
|
||||
mode = saved_flags & O_ACCMODE;
|
||||
|
||||
/* Reopen the file descriptor when it refers to a tty. This lets us put the
|
||||
* tty in non-blocking mode without affecting other processes that share it
|
||||
* with us.
|
||||
*
|
||||
* Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also
|
||||
* affects fd 1 of `cat` because both file descriptors refer to the same
|
||||
* struct file in the kernel. When we reopen our fd 0, it points to a
|
||||
* different struct file, hence changing its properties doesn't affect
|
||||
* other processes.
|
||||
*/
|
||||
if (type == UV_TTY) {
|
||||
/* Reopening a pty in master mode won't work either because the reopened
|
||||
* pty will be in slave mode (*BSD) or reopening will allocate a new
|
||||
* master/slave pair (Linux). Therefore check if the fd points to a
|
||||
* slave device.
|
||||
*/
|
||||
if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
|
||||
r = uv__open_cloexec(path, mode | O_NOCTTY);
|
||||
else
|
||||
r = -1;
|
||||
|
||||
if (r < 0) {
|
||||
/* fallback to using blocking writes */
|
||||
if (mode != O_RDONLY)
|
||||
flags |= UV_HANDLE_BLOCKING_WRITES;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
newfd = r;
|
||||
|
||||
r = uv__dup2_cloexec(newfd, fd);
|
||||
if (r < 0 && r != UV_EINVAL) {
|
||||
/* EINVAL means newfd == fd which could conceivably happen if another
|
||||
* thread called close(fd) between our calls to isatty() and open().
|
||||
* That's a rather unlikely event but let's handle it anyway.
|
||||
*/
|
||||
uv__close(newfd);
|
||||
return r;
|
||||
}
|
||||
|
||||
fd = newfd;
|
||||
}
|
||||
|
||||
skip:
|
||||
uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
|
||||
|
||||
/* If anything fails beyond this point we need to remove the handle from
|
||||
* the handle queue, since it was added by uv__handle_init in uv_stream_init.
|
||||
*/
|
||||
|
||||
if (!(flags & UV_HANDLE_BLOCKING_WRITES))
|
||||
uv__nonblock(fd, 1);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
r = uv__stream_try_select((uv_stream_t*) tty, &fd);
|
||||
if (r) {
|
||||
int rc = r;
|
||||
if (newfd != -1)
|
||||
uv__close(newfd);
|
||||
QUEUE_REMOVE(&tty->handle_queue);
|
||||
do
|
||||
r = fcntl(fd, F_SETFL, saved_flags);
|
||||
while (r == -1 && errno == EINTR);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mode != O_WRONLY)
|
||||
flags |= UV_HANDLE_READABLE;
|
||||
if (mode != O_RDONLY)
|
||||
flags |= UV_HANDLE_WRITABLE;
|
||||
|
||||
uv__stream_open((uv_stream_t*) tty, fd, flags);
|
||||
tty->mode = UV_TTY_MODE_NORMAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uv__tty_make_raw(struct termios* tio) {
|
||||
assert(tio != NULL);
|
||||
|
||||
#if defined __sun || defined __MVS__
|
||||
/*
|
||||
* This implementation of cfmakeraw for Solaris and derivatives is taken from
|
||||
* http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html.
|
||||
*/
|
||||
tio->c_iflag &= ~(IMAXBEL | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR |
|
||||
IGNCR | ICRNL | IXON);
|
||||
tio->c_oflag &= ~OPOST;
|
||||
tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
||||
tio->c_cflag &= ~(CSIZE | PARENB);
|
||||
tio->c_cflag |= CS8;
|
||||
#else
|
||||
cfmakeraw(tio);
|
||||
#endif /* #ifdef __sun */
|
||||
}
|
||||
|
||||
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||
struct termios tmp;
|
||||
int fd;
|
||||
|
||||
if (tty->mode == (int) mode)
|
||||
return 0;
|
||||
|
||||
fd = uv__stream_fd(tty);
|
||||
if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) {
|
||||
if (tcgetattr(fd, &tty->orig_termios))
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* This is used for uv_tty_reset_mode() */
|
||||
uv_spinlock_lock(&termios_spinlock);
|
||||
if (orig_termios_fd == -1) {
|
||||
orig_termios = tty->orig_termios;
|
||||
orig_termios_fd = fd;
|
||||
}
|
||||
uv_spinlock_unlock(&termios_spinlock);
|
||||
}
|
||||
|
||||
tmp = tty->orig_termios;
|
||||
switch (mode) {
|
||||
case UV_TTY_MODE_NORMAL:
|
||||
break;
|
||||
case UV_TTY_MODE_RAW:
|
||||
tmp.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
||||
tmp.c_oflag |= (ONLCR);
|
||||
tmp.c_cflag |= (CS8);
|
||||
tmp.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
|
||||
tmp.c_cc[VMIN] = 1;
|
||||
tmp.c_cc[VTIME] = 0;
|
||||
break;
|
||||
case UV_TTY_MODE_IO:
|
||||
uv__tty_make_raw(&tmp);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Apply changes after draining */
|
||||
if (tcsetattr(fd, TCSADRAIN, &tmp))
|
||||
return UV__ERR(errno);
|
||||
|
||||
tty->mode = mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
|
||||
struct winsize ws;
|
||||
int err;
|
||||
|
||||
do
|
||||
err = ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws);
|
||||
while (err == -1 && errno == EINTR);
|
||||
|
||||
if (err == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
*width = ws.ws_col;
|
||||
*height = ws.ws_row;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uv_handle_type uv_guess_handle(uv_file file) {
|
||||
struct sockaddr sa;
|
||||
struct stat s;
|
||||
socklen_t len;
|
||||
int type;
|
||||
|
||||
if (file < 0)
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
if (isatty(file))
|
||||
return UV_TTY;
|
||||
|
||||
if (fstat(file, &s))
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
if (S_ISREG(s.st_mode))
|
||||
return UV_FILE;
|
||||
|
||||
if (S_ISCHR(s.st_mode))
|
||||
return UV_FILE; /* XXX UV_NAMED_PIPE? */
|
||||
|
||||
if (S_ISFIFO(s.st_mode))
|
||||
return UV_NAMED_PIPE;
|
||||
|
||||
if (!S_ISSOCK(s.st_mode))
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
len = sizeof(type);
|
||||
if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len))
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
len = sizeof(sa);
|
||||
if (getsockname(file, &sa, &len))
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
if (type == SOCK_DGRAM)
|
||||
if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
|
||||
return UV_UDP;
|
||||
|
||||
if (type == SOCK_STREAM) {
|
||||
#if defined(_AIX) || defined(__DragonFly__)
|
||||
/* on AIX/DragonFly the getsockname call returns an empty sa structure
|
||||
* for sockets of type AF_UNIX. For all other types it will
|
||||
* return a properly filled in structure.
|
||||
*/
|
||||
if (len == 0)
|
||||
return UV_NAMED_PIPE;
|
||||
#endif /* defined(_AIX) || defined(__DragonFly__) */
|
||||
|
||||
if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
|
||||
return UV_TCP;
|
||||
if (sa.sa_family == AF_UNIX)
|
||||
return UV_NAMED_PIPE;
|
||||
}
|
||||
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
/* This function is async signal-safe, meaning that it's safe to call from
|
||||
* inside a signal handler _unless_ execution was inside uv_tty_set_mode()'s
|
||||
* critical section when the signal was raised.
|
||||
*/
|
||||
int uv_tty_reset_mode(void) {
|
||||
int saved_errno;
|
||||
int err;
|
||||
|
||||
saved_errno = errno;
|
||||
if (!uv_spinlock_trylock(&termios_spinlock))
|
||||
return UV_EBUSY; /* In uv_tty_set_mode(). */
|
||||
|
||||
err = 0;
|
||||
if (orig_termios_fd != -1)
|
||||
if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios))
|
||||
err = UV__ERR(errno);
|
||||
|
||||
uv_spinlock_unlock(&termios_spinlock);
|
||||
errno = saved_errno;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void uv_tty_set_vterm_state(uv_tty_vtermstate_t state) {
|
||||
}
|
||||
|
||||
int uv_tty_get_vterm_state(uv_tty_vtermstate_t* state) {
|
||||
return UV_ENOTSUP;
|
||||
}
|
1332
deps/libuv/src/unix/udp.c
vendored
Normal file
1332
deps/libuv/src/unix/udp.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user