< prev index next >

src/java.base/aix/native/libnet/aix_close.c

Print this page
rev 13795 : 8150460: (linux|bsd|aix)_close.c: file descriptor table may become large or may not work at all
Reviewed-by:
   1 /*
   2  * Copyright (c) 2001, 2013, Oracle 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 it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * 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 WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 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 USA
  22  * or visit www.oracle.com if you need additional information or have any


  33  *
  34  * This was originally copied from the linux_close.c implementation.
  35  *
  36  * Side Note: This coding needs initialization. Under Linux this is done
  37  * automatically via __attribute((constructor)), on AIX this is done manually
  38  * (see aix_close_init).
  39  *
  40  */
  41 
  42 /*
  43    AIX needs a workaround for I/O cancellation, see:
  44    http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/close.htm
  45    ...
  46    The close subroutine is blocked until all subroutines which use the file
  47    descriptor return to usr space. For example, when a thread is calling close
  48    and another thread is calling select with the same file descriptor, the
  49    close subroutine does not return until the select call returns.
  50    ...
  51 */
  52 


  53 #include <stdio.h>
  54 #include <stdlib.h>
  55 #include <signal.h>
  56 #include <pthread.h>
  57 #include <sys/types.h>
  58 #include <sys/socket.h>
  59 #include <sys/time.h>
  60 #include <sys/resource.h>
  61 #include <sys/uio.h>
  62 #include <unistd.h>
  63 #include <errno.h>
  64 #include <sys/poll.h>
  65 
  66 /*
  67  * Stack allocated by thread when doing blocking operation
  68  */
  69 typedef struct threadEntry {
  70     pthread_t thr;                      /* this thread */
  71     struct threadEntry *next;           /* next thread */
  72     int intr;                           /* interrupted */
  73 } threadEntry_t;
  74 
  75 /*
  76  * Heap allocated during initialized - one entry per fd
  77  */
  78 typedef struct {
  79     pthread_mutex_t lock;               /* fd lock */
  80     threadEntry_t *threads;             /* threads blocked on fd */
  81 } fdEntry_t;
  82 
  83 /*
  84  * Signal to unblock thread
  85  */
  86 static int sigWakeup = (SIGRTMAX - 1);
  87 
  88 /*
  89  * The fd table and the number of file descriptors
  90  */
  91 static fdEntry_t *fdTable = NULL;
  92 static int fdCount = 0;






















  93 
  94 /*
  95  * Null signal handler
  96  */
  97 static void sig_wakeup(int sig) {
  98 }
  99 
 100 /*
 101  * Initialization routine (executed when library is loaded)
 102  * Allocate fd tables and sets up signal handler.
 103  *
 104  * On AIX we don't have __attribute((constructor)) so we need to initialize
 105  * manually (from JNI_OnLoad() in 'src/share/native/java/net/net_util.c')
 106  */
 107 void aix_close_init() {
 108     struct rlimit nbr_files;
 109     sigset_t sigset;
 110     struct sigaction sa;

 111 
 112     /* Check already initialized */
 113     if (fdCount > 0 && fdTable != NULL) {
 114         return;
 115     }
 116 
 117     /*
 118      * Allocate table based on the maximum number of
 119      * file descriptors.
 120      */
 121     if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) {
 122         fprintf(stderr, "library initialization failed - "
 123                 "unable to get max # of allocated fds\n");
 124         abort();
 125     }
 126     fdCount = nbr_files.rlim_max;
 127     /*
 128      * We have a conceptual problem here, when the number of files is
 129      * unlimited. As a kind of workaround, we ensure the table is big
 130      * enough for handle even a large number of files. Since SAP itself
 131      * recommends a limit of 32000 files, we just use 64000 as 'infinity'.
 132      */
 133     if (nbr_files.rlim_max == RLIM_INFINITY) {
 134         fdCount = 64000;
 135     }
 136     fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t));
 137     if (fdTable == NULL) {
 138         fprintf(stderr, "library initialization failed - "
 139                 "unable to allocate file descriptor table - out of memory");
 140         abort();




 141     }
 142 
 143     {
 144         int i;
 145         for (i=0; i < fdCount; i++) {
 146             pthread_mutex_init(&fdTable[i].lock, NULL);




 147         }
 148     }
 149 
 150     /*
 151      * Setup the signal handler
 152      */
 153     sa.sa_handler = sig_wakeup;
 154     sa.sa_flags   = 0;
 155     sigemptyset(&sa.sa_mask);
 156     sigaction(sigWakeup, &sa, NULL);
 157 
 158     sigemptyset(&sigset);
 159     sigaddset(&sigset, sigWakeup);
 160     sigprocmask(SIG_UNBLOCK, &sigset, NULL);
 161 }
 162 
 163 /*
 164  * Return the fd table for this fd or NULL is fd out
 165  * of range.
 166  */
 167 static inline fdEntry_t *getFdEntry(int fd)
 168 {
 169     if (fd < 0 || fd >= fdCount) {


 170         return NULL;
 171     }
 172     return &fdTable[fd];

































 173 }
 174 
 175 /*
 176  * Start a blocking operation :-
 177  *    Insert thread onto thread list for the fd.
 178  */
 179 static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self)
 180 {
 181     self->thr = pthread_self();
 182     self->intr = 0;
 183 
 184     pthread_mutex_lock(&(fdEntry->lock));
 185     {
 186         self->next = fdEntry->threads;
 187         fdEntry->threads = self;
 188     }
 189     pthread_mutex_unlock(&(fdEntry->lock));
 190 }
 191 
 192 /*


   1 /*
   2  * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2016, SAP SE and/or its affiliates. All rights reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.  Oracle designates this
   9  * particular file as subject to the "Classpath" exception as provided
  10  * by Oracle in the LICENSE file that accompanied this code.
  11  *
  12  * This code is distributed in the hope that it will be useful, but WITHOUT
  13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15  * version 2 for more details (a copy is included in the LICENSE file that
  16  * accompanied this code).
  17  *
  18  * You should have received a copy of the GNU General Public License version
  19  * 2 along with this work; if not, write to the Free Software Foundation,
  20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  21  *
  22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  23  * or visit www.oracle.com if you need additional information or have any


  34  *
  35  * This was originally copied from the linux_close.c implementation.
  36  *
  37  * Side Note: This coding needs initialization. Under Linux this is done
  38  * automatically via __attribute((constructor)), on AIX this is done manually
  39  * (see aix_close_init).
  40  *
  41  */
  42 
  43 /*
  44    AIX needs a workaround for I/O cancellation, see:
  45    http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/close.htm
  46    ...
  47    The close subroutine is blocked until all subroutines which use the file
  48    descriptor return to usr space. For example, when a thread is calling close
  49    and another thread is calling select with the same file descriptor, the
  50    close subroutine does not return until the select call returns.
  51    ...
  52 */
  53 
  54 #include <assert.h>
  55 #include <limits.h>
  56 #include <stdio.h>
  57 #include <stdlib.h>
  58 #include <signal.h>
  59 #include <pthread.h>
  60 #include <sys/types.h>
  61 #include <sys/socket.h>
  62 #include <sys/time.h>
  63 #include <sys/resource.h>
  64 #include <sys/uio.h>
  65 #include <unistd.h>
  66 #include <errno.h>
  67 #include <sys/poll.h>
  68 
  69 /*
  70  * Stack allocated by thread when doing blocking operation
  71  */
  72 typedef struct threadEntry {
  73     pthread_t thr;                      /* this thread */
  74     struct threadEntry *next;           /* next thread */
  75     int intr;                           /* interrupted */
  76 } threadEntry_t;
  77 
  78 /*
  79  * Heap allocated during initialized - one entry per fd
  80  */
  81 typedef struct {
  82     pthread_mutex_t lock;               /* fd lock */
  83     threadEntry_t *threads;             /* threads blocked on fd */
  84 } fdEntry_t;
  85 
  86 /*
  87  * Signal to unblock thread
  88  */
  89 static int sigWakeup = (SIGRTMAX - 1);
  90 
  91 /*
  92  * fdTable holds one entry per file descriptor, up to a certain
  93  * maximum.
  94  * Theoretically, the number of possible file descriptors can get
  95  * large, though usually it does not. To save memory, we keep file
  96  * descriptors with large numerical values in an overflow table. That
  97  * table is organized as a two-dimensional sparse array, allocated
  98  * on demand.
  99  */
 100 
 101 static fdEntry_t* fdTable;
 102 /* Max. number of file descriptors in fdTable. */
 103 static const int fdTableMaxSize = 0x1000; /* 4K */
 104 /* Max. theoretical number of file descriptor on system. */
 105 static int fdLimit;
 106 /* Length of fdTable, in number of entries. */
 107 static int fdTableLen;
 108 
 109 /* Overflow table: organized as array of n slabs, each holding
 110  *   64k entries.
 111  */
 112 static fdEntry_t** fdOverflowTable;
 113 /* Number of slabs in the overflow table */
 114 static int fdOverflowTableLen;
 115 /* Number of entries in one slab */
 116 static const int fdOverflowTableSlabSize = 0x10000; /* 64k */
 117 pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER;
 118 
 119 /*
 120  * Null signal handler
 121  */
 122 static void sig_wakeup(int sig) {
 123 }
 124 
 125 /*
 126  * Initialization routine (executed when library is loaded)
 127  * Allocate fd tables and sets up signal handler.
 128  *
 129  * On AIX we don't have __attribute((constructor)) so we need to initialize
 130  * manually (from JNI_OnLoad() in 'src/share/native/java/net/net_util.c')
 131  */
 132 void aix_close_init() {
 133     struct rlimit nbr_files;
 134     sigset_t sigset;
 135     struct sigaction sa;
 136     int i = 0;
 137 
 138     assert(fdTable == NULL);



 139 
 140     /* Determine the maximum number of possible file descriptors. */
 141     getrlimit(RLIMIT_NOFILE, &nbr_files);
 142     if (nbr_files.rlim_max != RLIM_INFINITY) {
 143         fdLimit = nbr_files.rlim_max;
 144     } else {
 145         /* We just do not know. */
 146         fdLimit = INT_MAX;
 147     }
 148 
 149     /* Allocate table for low value file descriptors. */
 150     fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize;
 151     fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t));








 152     if (fdTable == NULL) {
 153         fprintf(stderr, "library initialization failed - "
 154                 "unable to allocate file descriptor table - out of memory");
 155         abort();
 156     } else {
 157         for (i = 0; i < fdTableLen; i ++) {
 158             pthread_mutex_init(&fdTable[i].lock, NULL);
 159         }
 160     }
 161 
 162     /* Allocate overflow table, if needed */
 163     if (fdLimit > fdTableMaxSize) {
 164         fdOverflowTableLen = ((fdLimit - fdTableMaxSize) / fdOverflowTableSlabSize) + 1;
 165         fdOverflowTable = (fdEntry_t**) calloc(fdOverflowTableLen, sizeof(fdEntry_t*));
 166         if (fdOverflowTable == NULL) {
 167             fprintf(stderr, "library initialization failed - "
 168                     "unable to allocate file descriptor overflow table - out of memory");
 169             abort();
 170         }
 171     }
 172 
 173     /*
 174      * Setup the signal handler
 175      */
 176     sa.sa_handler = sig_wakeup;
 177     sa.sa_flags   = 0;
 178     sigemptyset(&sa.sa_mask);
 179     sigaction(sigWakeup, &sa, NULL);
 180 
 181     sigemptyset(&sigset);
 182     sigaddset(&sigset, sigWakeup);
 183     sigprocmask(SIG_UNBLOCK, &sigset, NULL);
 184 }
 185 
 186 /*
 187  * Return the fd table for this fd.

 188  */
 189 static inline fdEntry_t *getFdEntry(int fd)
 190 {
 191     fdEntry_t* result = NULL;
 192 
 193     if (fd < 0) {
 194         return NULL;
 195     }
 196 
 197     /* This should not happen. If it does, our assumption about
 198      * max. fd value was wrong. */
 199     assert(fd < fdLimit);
 200 
 201     if (fd < fdTableMaxSize) {
 202         assert(fd < fdTableLen);
 203         result = fdTable + fd;
 204     } else {
 205         const int indexInOverflowTable = fd - fdTableMaxSize;
 206         const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize;
 207         const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize;
 208         assert(rootindex < fdOverflowTableLen);
 209         assert(slabindex < fdOverflowTableSlabSize);
 210         pthread_mutex_lock(&fdOverflowTableLock);
 211         if (fdOverflowTable[rootindex] == NULL) {
 212             fdEntry_t* const newSlab =
 213                 (fdEntry_t*)calloc(fdOverflowTableSlabSize, sizeof(fdEntry_t));
 214             if (newSlab == NULL) {
 215                 fprintf(stderr, "Unable to allocate file descriptor table - out of memory");
 216                 pthread_mutex_unlock(&fdOverflowTableLock);
 217                 abort();
 218             } else {
 219                 int i;
 220                 for (i = 0; i < fdOverflowTableSlabSize; i ++) {
 221                     pthread_mutex_init(&newSlab[i].lock, NULL);
 222                 }
 223                 fdOverflowTable[rootindex] = newSlab;
 224             }
 225         }
 226         pthread_mutex_unlock(&fdOverflowTableLock);
 227         result = fdOverflowTable[rootindex] + slabindex;
 228     }
 229     return result;
 230 }
 231 
 232 /*
 233  * Start a blocking operation :-
 234  *    Insert thread onto thread list for the fd.
 235  */
 236 static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self)
 237 {
 238     self->thr = pthread_self();
 239     self->intr = 0;
 240 
 241     pthread_mutex_lock(&(fdEntry->lock));
 242     {
 243         self->next = fdEntry->threads;
 244         fdEntry->threads = self;
 245     }
 246     pthread_mutex_unlock(&(fdEntry->lock));
 247 }
 248 
 249 /*


< prev index next >