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