Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/native/java/net/linux_close.c
32287 views
/*1* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <assert.h>26#include <limits.h>27#include <stdio.h>28#include <stdlib.h>29#include <signal.h>30#include <pthread.h>31#include <sys/types.h>32#include <sys/socket.h>33#include <sys/time.h>34#include <sys/resource.h>35#include <sys/uio.h>36#include <unistd.h>37#include <errno.h>38#include <sys/poll.h>3940/*41* Stack allocated by thread when doing blocking operation42*/43typedef struct threadEntry {44pthread_t thr; /* this thread */45struct threadEntry *next; /* next thread */46int intr; /* interrupted */47} threadEntry_t;4849/*50* Heap allocated during initialized - one entry per fd51*/52typedef struct {53pthread_mutex_t lock; /* fd lock */54threadEntry_t *threads; /* threads blocked on fd */55} fdEntry_t;5657/*58* Signal to unblock thread59*/60static int sigWakeup = (__SIGRTMAX - 2);6162/*63* fdTable holds one entry per file descriptor, up to a certain64* maximum.65* Theoretically, the number of possible file descriptors can get66* large, though usually it does not. Entries for small value file67* descriptors are kept in a simple table, which covers most scenarios.68* Entries for large value file descriptors are kept in an overflow69* table, which is organized as a sparse two dimensional array whose70* slabs are allocated on demand. This covers all corner cases while71* keeping memory consumption reasonable.72*/7374/* Base table for low value file descriptors */75static fdEntry_t* fdTable = NULL;76/* Maximum size of base table (in number of entries). */77static const int fdTableMaxSize = 0x1000; /* 4K */78/* Actual size of base table (in number of entries) */79static int fdTableLen = 0;80/* Max. theoretical number of file descriptors on system. */81static int fdLimit = 0;8283/* Overflow table, should base table not be large enough. Organized as84* an array of n slabs, each holding 64k entries.85*/86static fdEntry_t** fdOverflowTable = NULL;87/* Number of slabs in the overflow table */88static int fdOverflowTableLen = 0;89/* Number of entries in one slab */90static const int fdOverflowTableSlabSize = 0x10000; /* 64k */91pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER;9293/*94* Null signal handler95*/96static void sig_wakeup(int sig) {97}9899/*100* Initialization routine (executed when library is loaded)101* Allocate fd tables and sets up signal handler.102*/103static void __attribute((constructor)) init() {104struct rlimit nbr_files;105sigset_t sigset;106struct sigaction sa;107int i = 0;108109/* Determine the maximum number of possible file descriptors. */110if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) {111fprintf(stderr, "library initialization failed - "112"unable to get max # of allocated fds\n");113abort();114}115if (nbr_files.rlim_max != RLIM_INFINITY) {116fdLimit = nbr_files.rlim_max;117} else {118/* We just do not know. */119fdLimit = INT_MAX;120}121122/* Allocate table for low value file descriptors. */123fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize;124fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t));125if (fdTable == NULL) {126fprintf(stderr, "library initialization failed - "127"unable to allocate file descriptor table - out of memory");128abort();129} else {130for (i = 0; i < fdTableLen; i ++) {131pthread_mutex_init(&fdTable[i].lock, NULL);132}133}134135/* Allocate overflow table, if needed */136if (fdLimit > fdTableMaxSize) {137fdOverflowTableLen = ((fdLimit - fdTableMaxSize) / fdOverflowTableSlabSize) + 1;138fdOverflowTable = (fdEntry_t**) calloc(fdOverflowTableLen, sizeof(fdEntry_t*));139if (fdOverflowTable == NULL) {140fprintf(stderr, "library initialization failed - "141"unable to allocate file descriptor overflow table - out of memory");142abort();143}144}145146/*147* Setup the signal handler148*/149sa.sa_handler = sig_wakeup;150sa.sa_flags = 0;151sigemptyset(&sa.sa_mask);152sigaction(sigWakeup, &sa, NULL);153154sigemptyset(&sigset);155sigaddset(&sigset, sigWakeup);156sigprocmask(SIG_UNBLOCK, &sigset, NULL);157}158159/*160* Return the fd table for this fd.161*/162static inline fdEntry_t *getFdEntry(int fd)163{164fdEntry_t* result = NULL;165166if (fd < 0) {167return NULL;168}169170/* This should not happen. If it does, our assumption about171* max. fd value was wrong. */172assert(fd < fdLimit);173174if (fd < fdTableMaxSize) {175/* fd is in base table. */176assert(fd < fdTableLen);177result = &fdTable[fd];178} else {179/* fd is in overflow table. */180const int indexInOverflowTable = fd - fdTableMaxSize;181const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize;182const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize;183fdEntry_t* slab = NULL;184assert(rootindex < fdOverflowTableLen);185assert(slabindex < fdOverflowTableSlabSize);186pthread_mutex_lock(&fdOverflowTableLock);187/* Allocate new slab in overflow table if needed */188if (fdOverflowTable[rootindex] == NULL) {189fdEntry_t* const newSlab =190(fdEntry_t*)calloc(fdOverflowTableSlabSize, sizeof(fdEntry_t));191if (newSlab == NULL) {192fprintf(stderr, "Unable to allocate file descriptor overflow"193" table slab - out of memory");194pthread_mutex_unlock(&fdOverflowTableLock);195abort();196} else {197int i;198for (i = 0; i < fdOverflowTableSlabSize; i ++) {199pthread_mutex_init(&newSlab[i].lock, NULL);200}201fdOverflowTable[rootindex] = newSlab;202}203}204pthread_mutex_unlock(&fdOverflowTableLock);205slab = fdOverflowTable[rootindex];206result = &slab[slabindex];207}208209return result;210211}212213/*214* Start a blocking operation :-215* Insert thread onto thread list for the fd.216*/217static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self)218{219self->thr = pthread_self();220self->intr = 0;221222pthread_mutex_lock(&(fdEntry->lock));223{224self->next = fdEntry->threads;225fdEntry->threads = self;226}227pthread_mutex_unlock(&(fdEntry->lock));228}229230/*231* End a blocking operation :-232* Remove thread from thread list for the fd233* If fd has been interrupted then set errno to EBADF234*/235static inline void endOp236(fdEntry_t *fdEntry, threadEntry_t *self)237{238int orig_errno = errno;239pthread_mutex_lock(&(fdEntry->lock));240{241threadEntry_t *curr, *prev=NULL;242curr = fdEntry->threads;243while (curr != NULL) {244if (curr == self) {245if (curr->intr) {246orig_errno = EBADF;247}248if (prev == NULL) {249fdEntry->threads = curr->next;250} else {251prev->next = curr->next;252}253break;254}255prev = curr;256curr = curr->next;257}258}259pthread_mutex_unlock(&(fdEntry->lock));260errno = orig_errno;261}262263/*264* Close or dup2 a file descriptor ensuring that all threads blocked on265* the file descriptor are notified via a wakeup signal.266*267* fd1 < 0 => close(fd2)268* fd1 >= 0 => dup2(fd1, fd2)269*270* Returns -1 with errno set if operation fails.271*/272static int closefd(int fd1, int fd2) {273int rv, orig_errno;274fdEntry_t *fdEntry = getFdEntry(fd2);275if (fdEntry == NULL) {276errno = EBADF;277return -1;278}279280/*281* Lock the fd to hold-off additional I/O on this fd.282*/283pthread_mutex_lock(&(fdEntry->lock));284285{286/*287* And close/dup the file descriptor288* (restart if interrupted by signal)289*/290do {291if (fd1 < 0) {292rv = close(fd2);293} else {294rv = dup2(fd1, fd2);295}296} while (rv == -1 && errno == EINTR);297298/*299* Send a wakeup signal to all threads blocked on this300* file descriptor.301*/302threadEntry_t *curr = fdEntry->threads;303while (curr != NULL) {304curr->intr = 1;305pthread_kill( curr->thr, sigWakeup );306curr = curr->next;307}308}309310/*311* Unlock without destroying errno312*/313orig_errno = errno;314pthread_mutex_unlock(&(fdEntry->lock));315errno = orig_errno;316317return rv;318}319320/*321* Wrapper for dup2 - same semantics as dup2 system call except322* that any threads blocked in an I/O system call on fd2 will be323* preempted and return -1/EBADF;324*/325int NET_Dup2(int fd, int fd2) {326if (fd < 0) {327errno = EBADF;328return -1;329}330return closefd(fd, fd2);331}332333/*334* Wrapper for close - same semantics as close system call335* except that any threads blocked in an I/O on fd will be336* preempted and the I/O system call will return -1/EBADF.337*/338int NET_SocketClose(int fd) {339return closefd(-1, fd);340}341342/************** Basic I/O operations here ***************/343344/*345* Macro to perform a blocking IO operation. Restarts346* automatically if interrupted by signal (other than347* our wakeup signal)348*/349#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \350int ret; \351threadEntry_t self; \352fdEntry_t *fdEntry = getFdEntry(FD); \353if (fdEntry == NULL) { \354errno = EBADF; \355return -1; \356} \357do { \358startOp(fdEntry, &self); \359ret = FUNC; \360endOp(fdEntry, &self); \361} while (ret == -1 && errno == EINTR); \362return ret; \363}364365int NET_Read(int s, void* buf, size_t len) {366BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) );367}368369int NET_NonBlockingRead(int s, void* buf, size_t len) {370BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, MSG_DONTWAIT) );371}372373int NET_ReadV(int s, const struct iovec * vector, int count) {374BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) );375}376377int NET_RecvFrom(int s, void *buf, int len, unsigned int flags,378struct sockaddr *from, int *fromlen) {379socklen_t socklen = *fromlen;380BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, &socklen) );381*fromlen = socklen;382}383384int NET_Send(int s, void *msg, int len, unsigned int flags) {385BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) );386}387388int NET_WriteV(int s, const struct iovec * vector, int count) {389BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) );390}391392int NET_SendTo(int s, const void *msg, int len, unsigned int393flags, const struct sockaddr *to, int tolen) {394BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) );395}396397int NET_Accept(int s, struct sockaddr *addr, int *addrlen) {398socklen_t socklen = *addrlen;399BLOCKING_IO_RETURN_INT( s, accept(s, addr, &socklen) );400*addrlen = socklen;401}402403int NET_Connect(int s, struct sockaddr *addr, int addrlen) {404BLOCKING_IO_RETURN_INT( s, connect(s, addr, addrlen) );405}406407#ifndef USE_SELECT408int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) {409BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) );410}411#else412int NET_Select(int s, fd_set *readfds, fd_set *writefds,413fd_set *exceptfds, struct timeval *timeout) {414BLOCKING_IO_RETURN_INT( s-1,415select(s, readfds, writefds, exceptfds, timeout) );416}417#endif418419/*420* Wrapper for poll(s, timeout).421* Auto restarts with adjusted timeout if interrupted by422* signal other than our wakeup signal.423*/424int NET_Timeout0(int s, long timeout, long currentTime) {425long prevtime = currentTime, newtime;426struct timeval t;427fdEntry_t *fdEntry = getFdEntry(s);428429/*430* Check that fd hasn't been closed.431*/432if (fdEntry == NULL) {433errno = EBADF;434return -1;435}436437for(;;) {438struct pollfd pfd;439int rv;440threadEntry_t self;441442/*443* Poll the fd. If interrupted by our wakeup signal444* errno will be set to EBADF.445*/446pfd.fd = s;447pfd.events = POLLIN | POLLERR;448449startOp(fdEntry, &self);450rv = poll(&pfd, 1, timeout);451endOp(fdEntry, &self);452453/*454* If interrupted then adjust timeout. If timeout455* has expired return 0 (indicating timeout expired).456*/457if (rv < 0 && errno == EINTR) {458if (timeout > 0) {459gettimeofday(&t, NULL);460newtime = t.tv_sec * 1000 + t.tv_usec / 1000;461timeout -= newtime - prevtime;462if (timeout <= 0) {463return 0;464}465prevtime = newtime;466}467} else {468return rv;469}470471}472}473474475