Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/aix/native/java/net/aix_close.c
47458 views
/*1* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2016, SAP SE and/or its affiliates. All rights reserved.3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.4*5* This code is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation. Oracle designates this8* particular file as subject to the "Classpath" exception as provided9* by Oracle in the LICENSE file that accompanied this code.10*11* This code is distributed in the hope that it will be useful, but WITHOUT12* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or13* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License14* version 2 for more details (a copy is included in the LICENSE file that15* accompanied this code).16*17* You should have received a copy of the GNU General Public License version18* 2 along with this work; if not, write to the Free Software Foundation,19* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.20*21* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA22* or visit www.oracle.com if you need additional information or have any23* questions.24*/2526/*27* This file contains implementations of NET_... functions. The NET_.. functions are28* wrappers for common file- and socket functions plus provisions for non-blocking IO.29*30* (basically, the layers remember all file descriptors waiting for a particular fd;31* all threads waiting on a certain fd can be woken up by sending them a signal; this32* is done e.g. when the fd is closed.)33*34* This was originally copied from the linux_close.c implementation.35*36* Side Note: This coding needs initialization. Under Linux this is done37* automatically via __attribute((constructor)), on AIX this is done manually38* (see aix_close_init).39*40*/4142#include <assert.h>43#include <limits.h>44#include <stdio.h>45#include <stdlib.h>46#include <signal.h>47#include <pthread.h>48#include <sys/types.h>49#include <sys/socket.h>50#include <sys/time.h>51#include <sys/resource.h>52#include <sys/uio.h>53#include <unistd.h>54#include <errno.h>5556#include <sys/poll.h>5758/*59* Stack allocated by thread when doing blocking operation60*/61typedef struct threadEntry {62pthread_t thr; /* this thread */63struct threadEntry *next; /* next thread */64int intr; /* interrupted */65} threadEntry_t;6667/*68* Heap allocated during initialized - one entry per fd69*/70typedef struct {71pthread_mutex_t lock; /* fd lock */72threadEntry_t *threads; /* threads blocked on fd */73} fdEntry_t;7475/*76* Signal to unblock thread77*/78static int sigWakeup = (SIGRTMAX - 1);7980/*81* fdTable holds one entry per file descriptor, up to a certain82* maximum.83* Theoretically, the number of possible file descriptors can get84* large, though usually it does not. Entries for small value file85* descriptors are kept in a simple table, which covers most scenarios.86* Entries for large value file descriptors are kept in an overflow87* table, which is organized as a sparse two dimensional array whose88* slabs are allocated on demand. This covers all corner cases while89* keeping memory consumption reasonable.90*/9192/* Base table for low value file descriptors */93static fdEntry_t* fdTable = NULL;94/* Maximum size of base table (in number of entries). */95static const int fdTableMaxSize = 0x1000; /* 4K */96/* Actual size of base table (in number of entries) */97static int fdTableLen = 0;98/* Max. theoretical number of file descriptors on system. */99static int fdLimit = 0;100101/* Overflow table, should base table not be large enough. Organized as102* an array of n slabs, each holding 64k entries.103*/104static fdEntry_t** fdOverflowTable = NULL;105/* Number of slabs in the overflow table */106static int fdOverflowTableLen = 0;107/* Number of entries in one slab */108static const int fdOverflowTableSlabSize = 0x10000; /* 64k */109pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER;110111/*112* Null signal handler113*/114static void sig_wakeup(int sig) {115}116117/*118* Initialization routine (executed when library is loaded)119* Allocate fd tables and sets up signal handler.120*121* On AIX we don't have __attribute((constructor)) so we need to initialize122* manually (from JNI_OnLoad() in 'src/share/native/java/net/net_util.c')123*/124void aix_close_init() {125struct rlimit nbr_files;126sigset_t sigset;127struct sigaction sa;128int i = 0;129130/* Determine the maximum number of possible file descriptors. */131if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) {132fprintf(stderr, "library initialization failed - "133"unable to get max # of allocated fds\n");134abort();135}136if (nbr_files.rlim_max != RLIM_INFINITY) {137fdLimit = nbr_files.rlim_max;138} else {139/* We just do not know. */140fdLimit = INT_MAX;141}142143/* Allocate table for low value file descriptors. */144fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize;145fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t));146if (fdTable == NULL) {147fprintf(stderr, "library initialization failed - "148"unable to allocate file descriptor table - out of memory");149abort();150} else {151for (i = 0; i < fdTableLen; i ++) {152pthread_mutex_init(&fdTable[i].lock, NULL);153}154}155156/* Allocate overflow table, if needed */157if (fdLimit > fdTableMaxSize) {158fdOverflowTableLen = ((fdLimit - fdTableMaxSize) / fdOverflowTableSlabSize) + 1;159fdOverflowTable = (fdEntry_t**) calloc(fdOverflowTableLen, sizeof(fdEntry_t*));160if (fdOverflowTable == NULL) {161fprintf(stderr, "library initialization failed - "162"unable to allocate file descriptor overflow table - out of memory");163abort();164}165}166167/*168* Setup the signal handler169*/170sa.sa_handler = sig_wakeup;171sa.sa_flags = 0;172sigemptyset(&sa.sa_mask);173sigaction(sigWakeup, &sa, NULL);174175sigemptyset(&sigset);176sigaddset(&sigset, sigWakeup);177sigprocmask(SIG_UNBLOCK, &sigset, NULL);178}179180/*181* Return the fd table for this fd.182*/183static inline fdEntry_t *getFdEntry(int fd)184{185fdEntry_t* result = NULL;186187if (fd < 0) {188return NULL;189}190191/* This should not happen. If it does, our assumption about192* max. fd value was wrong. */193assert(fd < fdLimit);194195if (fd < fdTableMaxSize) {196/* fd is in base table. */197assert(fd < fdTableLen);198result = &fdTable[fd];199} else {200/* fd is in overflow table. */201const int indexInOverflowTable = fd - fdTableMaxSize;202const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize;203const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize;204fdEntry_t* slab = NULL;205assert(rootindex < fdOverflowTableLen);206assert(slabindex < fdOverflowTableSlabSize);207pthread_mutex_lock(&fdOverflowTableLock);208/* Allocate new slab in overflow table if needed */209if (fdOverflowTable[rootindex] == NULL) {210fdEntry_t* const newSlab =211(fdEntry_t*)calloc(fdOverflowTableSlabSize, sizeof(fdEntry_t));212if (newSlab == NULL) {213fprintf(stderr, "Unable to allocate file descriptor overflow"214" table slab - out of memory");215pthread_mutex_unlock(&fdOverflowTableLock);216abort();217} else {218int i;219for (i = 0; i < fdOverflowTableSlabSize; i ++) {220pthread_mutex_init(&newSlab[i].lock, NULL);221}222fdOverflowTable[rootindex] = newSlab;223}224}225pthread_mutex_unlock(&fdOverflowTableLock);226slab = fdOverflowTable[rootindex];227result = &slab[slabindex];228}229230return result;231232}233234235/*236* Start a blocking operation :-237* Insert thread onto thread list for the fd.238*/239static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self)240{241self->thr = pthread_self();242self->intr = 0;243244pthread_mutex_lock(&(fdEntry->lock));245{246self->next = fdEntry->threads;247fdEntry->threads = self;248}249pthread_mutex_unlock(&(fdEntry->lock));250}251252/*253* End a blocking operation :-254* Remove thread from thread list for the fd255* If fd has been interrupted then set errno to EBADF256*/257static inline void endOp258(fdEntry_t *fdEntry, threadEntry_t *self)259{260int orig_errno = errno;261pthread_mutex_lock(&(fdEntry->lock));262{263threadEntry_t *curr, *prev=NULL;264curr = fdEntry->threads;265while (curr != NULL) {266if (curr == self) {267if (curr->intr) {268orig_errno = EBADF;269}270if (prev == NULL) {271fdEntry->threads = curr->next;272} else {273prev->next = curr->next;274}275break;276}277prev = curr;278curr = curr->next;279}280}281pthread_mutex_unlock(&(fdEntry->lock));282errno = orig_errno;283}284285/*286* Close or dup2 a file descriptor ensuring that all threads blocked on287* the file descriptor are notified via a wakeup signal.288*289* fd1 < 0 => close(fd2)290* fd1 >= 0 => dup2(fd1, fd2)291*292* Returns -1 with errno set if operation fails.293*/294static int closefd(int fd1, int fd2) {295int rv, orig_errno;296fdEntry_t *fdEntry = getFdEntry(fd2);297if (fdEntry == NULL) {298errno = EBADF;299return -1;300}301302/*303* Lock the fd to hold-off additional I/O on this fd.304*/305pthread_mutex_lock(&(fdEntry->lock));306307{308/* On fast machines we see that we enter dup2 before the309* accepting thread had a chance to get and process the signal.310* So in case we woke a thread up, give it some time to cope.311* Also see https://bugs.openjdk.java.net/browse/JDK-8006395 */312int num_woken = 0;313314/*315* Send a wakeup signal to all threads blocked on this316* file descriptor.317*/318threadEntry_t *curr = fdEntry->threads;319while (curr != NULL) {320curr->intr = 1;321pthread_kill( curr->thr, sigWakeup );322num_woken ++;323curr = curr->next;324}325326if (num_woken > 0) {327usleep(num_woken * 50);328}329330/*331* And close/dup the file descriptor332* (restart if interrupted by signal)333*/334do {335if (fd1 < 0) {336rv = close(fd2);337} else {338rv = dup2(fd1, fd2);339}340} while (rv == -1 && errno == EINTR);341}342343/*344* Unlock without destroying errno345*/346orig_errno = errno;347pthread_mutex_unlock(&(fdEntry->lock));348errno = orig_errno;349350return rv;351}352353/*354* Wrapper for dup2 - same semantics as dup2 system call except355* that any threads blocked in an I/O system call on fd2 will be356* preempted and return -1/EBADF;357*/358int NET_Dup2(int fd, int fd2) {359if (fd < 0) {360errno = EBADF;361return -1;362}363return closefd(fd, fd2);364}365366/*367* Wrapper for close - same semantics as close system call368* except that any threads blocked in an I/O on fd will be369* preempted and the I/O system call will return -1/EBADF.370*/371int NET_SocketClose(int fd) {372return closefd(-1, fd);373}374375/************** Basic I/O operations here ***************/376377/*378* Macro to perform a blocking IO operation. Restarts379* automatically if interrupted by signal (other than380* our wakeup signal)381*/382#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \383int ret; \384threadEntry_t self; \385fdEntry_t *fdEntry = getFdEntry(FD); \386if (fdEntry == NULL) { \387errno = EBADF; \388return -1; \389} \390do { \391startOp(fdEntry, &self); \392ret = FUNC; \393endOp(fdEntry, &self); \394} while (ret == -1 && errno == EINTR); \395return ret; \396}397398int NET_Read(int s, void* buf, size_t len) {399BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) );400}401402int NET_NonBlockingRead(int s, void* buf, size_t len) {403BLOCKING_IO_RETURN_INT(s, recv(s, buf, len, MSG_NONBLOCK));404}405406int NET_ReadV(int s, const struct iovec * vector, int count) {407BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) );408}409410int NET_RecvFrom(int s, void *buf, int len, unsigned int flags,411struct sockaddr *from, int *fromlen) {412socklen_t socklen = *fromlen;413BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, &socklen) );414*fromlen = socklen;415}416417int NET_Send(int s, void *msg, int len, unsigned int flags) {418BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) );419}420421int NET_WriteV(int s, const struct iovec * vector, int count) {422BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) );423}424425int NET_SendTo(int s, const void *msg, int len, unsigned int426flags, const struct sockaddr *to, int tolen) {427BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) );428}429430int NET_Accept(int s, struct sockaddr *addr, int *addrlen) {431socklen_t socklen = *addrlen;432BLOCKING_IO_RETURN_INT( s, accept(s, addr, &socklen) );433*addrlen = socklen;434}435436int NET_Connect(int s, struct sockaddr *addr, int addrlen) {437int crc = -1, prc = -1;438threadEntry_t self;439fdEntry_t* fdEntry = getFdEntry(s);440441if (fdEntry == NULL) {442errno = EBADF;443return -1;444}445446/* On AIX, when the system call connect() is interrupted, the connection447* is not aborted and it will be established asynchronously by the kernel.448* Hence, no need to restart connect() when EINTR is received449*/450startOp(fdEntry, &self);451crc = connect(s, addr, addrlen);452endOp(fdEntry, &self);453454if (crc == -1 && errno == EINTR) {455struct pollfd s_pollfd;456int sockopt_arg = 0;457socklen_t len;458459s_pollfd.fd = s;460s_pollfd.events = POLLOUT | POLLERR;461462/* poll the file descriptor */463do {464startOp(fdEntry, &self);465prc = poll(&s_pollfd, 1, -1);466endOp(fdEntry, &self);467} while (prc == -1 && errno == EINTR);468469if (prc < 0)470return prc;471472len = sizeof(sockopt_arg);473474/* Check whether the connection has been established */475if (getsockopt(s, SOL_SOCKET, SO_ERROR, &sockopt_arg, &len) == -1)476return -1;477478if (sockopt_arg != 0 ) {479errno = sockopt_arg;480return -1;481}482} else {483return crc;484}485486/* At this point, fd is connected. Set successful return code */487return 0;488}489490#ifndef USE_SELECT491int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) {492BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) );493}494#else495int NET_Select(int s, fd_set *readfds, fd_set *writefds,496fd_set *exceptfds, struct timeval *timeout) {497BLOCKING_IO_RETURN_INT( s-1,498select(s, readfds, writefds, exceptfds, timeout) );499}500#endif501502/*503* Wrapper for poll(s, timeout).504* Auto restarts with adjusted timeout if interrupted by505* signal other than our wakeup signal.506*/507int NET_Timeout0(int s, long timeout, long currentTime) {508long prevtime = currentTime, newtime;509struct timeval t;510fdEntry_t *fdEntry = getFdEntry(s);511512/*513* Check that fd hasn't been closed.514*/515if (fdEntry == NULL) {516errno = EBADF;517return -1;518}519520for(;;) {521struct pollfd pfd;522int rv;523threadEntry_t self;524525/*526* Poll the fd. If interrupted by our wakeup signal527* errno will be set to EBADF.528*/529pfd.fd = s;530pfd.events = POLLIN | POLLERR;531532startOp(fdEntry, &self);533rv = poll(&pfd, 1, timeout);534endOp(fdEntry, &self);535536/*537* If interrupted then adjust timeout. If timeout538* has expired return 0 (indicating timeout expired).539*/540if (rv < 0 && errno == EINTR) {541if (timeout > 0) {542gettimeofday(&t, NULL);543newtime = t.tv_sec * 1000 + t.tv_usec / 1000;544timeout -= newtime - prevtime;545if (timeout <= 0) {546return 0;547}548prevtime = newtime;549}550} else {551return rv;552}553554}555}556557558