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
  23  * questions.
  24  */
  25 
  26 /*
  27  * This file contains implementations of NET_... functions. The NET_.. functions are
  28  * 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; this
  32  *  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 done
  37  * automatically via __attribute((constructor)), on AIX this is done manually
  38  * (see aix_close_init).
  39  *
  40  */












  41 #include <stdio.h>
  42 #include <stdlib.h>
  43 #include <signal.h>
  44 #include <pthread.h>
  45 #include <sys/types.h>
  46 #include <sys/socket.h>
  47 #include <sys/time.h>
  48 #include <sys/resource.h>
  49 #include <sys/uio.h>
  50 #include <unistd.h>
  51 #include <errno.h>
  52 
  53 #include <sys/poll.h>
  54 
  55 /*
  56  * Stack allocated by thread when doing blocking operation
  57  */
  58 typedef struct threadEntry {
  59     pthread_t thr;                      /* this thread */
  60     struct threadEntry *next;           /* next thread */
  61     int intr;                           /* interrupted */
  62 } threadEntry_t;
  63 
  64 /*
  65  * Heap allocated during initialized - one entry per fd
  66  */
  67 typedef struct {
  68     pthread_mutex_t lock;               /* fd lock */
  69     threadEntry_t *threads;             /* threads blocked on fd */
  70 } fdEntry_t;
  71 
  72 /*
  73  * Signal to unblock thread
  74  */
  75 static int sigWakeup = (SIGRTMAX - 1);
  76 
  77 /*
  78  * The fd table and the number of file descriptors
  79  */
  80 static fdEntry_t *fdTable = NULL;
  81 static int fdCount = 0;
  82 
  83 /*
  84  * Null signal handler
  85  */
  86 static void sig_wakeup(int sig) {
  87 }
  88 
  89 /*
  90  * Initialization routine (executed when library is loaded)
  91  * Allocate fd tables and sets up signal handler.
  92  *
  93  * On AIX we don't have __attribute((constructor)) so we need to initialize
  94  * manually (from JNI_OnLoad() in 'src/share/native/java/net/net_util.c')
  95  */
  96 void aix_close_init() {
  97     struct rlimit nbr_files;
  98     sigset_t sigset;
  99     struct sigaction sa;
 100 
 101     /* Check already initialized */
 102     if (fdCount > 0 && fdTable != NULL) {
 103         return;
 104     }
 105 
 106     /*
 107      * Allocate table based on the maximum number of
 108      * file descriptors.
 109      */
 110     if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) {
 111         fprintf(stderr, "library initialization failed - "
 112                 "unable to get max # of allocated fds\n");
 113         abort();
 114     }
 115     fdCount = nbr_files.rlim_max;
 116     /*
 117      * We have a conceptual problem here, when the number of files is
 118      * unlimited. As a kind of workaround, we ensure the table is big
 119      * enough for handle even a large number of files. Since SAP itself
 120      * recommends a limit of 32000 files, we just use 64000 as 'infinity'.
 121      */
 122     if (nbr_files.rlim_max == RLIM_INFINITY) {
 123         fdCount = 64000;
 124     }
 125     fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t));
 126     if (fdTable == NULL) {
 127         fprintf(stderr, "library initialization failed - "
 128                 "unable to allocate file descriptor table - out of memory");
 129         abort();
 130     }
 131 
 132     {
 133         int i;
 134         for (i=0; i < fdCount; i++) {
 135             pthread_mutex_init(&fdTable[i].lock, NULL);
 136         }
 137     }
 138 
 139     /*
 140      * Setup the signal handler
 141      */
 142     sa.sa_handler = sig_wakeup;
 143     sa.sa_flags   = 0;
 144     sigemptyset(&sa.sa_mask);
 145     sigaction(sigWakeup, &sa, NULL);
 146 
 147     sigemptyset(&sigset);
 148     sigaddset(&sigset, sigWakeup);
 149     sigprocmask(SIG_UNBLOCK, &sigset, NULL);
 150 }
 151 
 152 /*
 153  * Return the fd table for this fd or NULL is fd out
 154  * of range.
 155  */
 156 static inline fdEntry_t *getFdEntry(int fd)
 157 {
 158     if (fd < 0 || fd >= fdCount) {
 159         return NULL;
 160     }
 161     return &fdTable[fd];
 162 }
 163 
 164 /*
 165  * Start a blocking operation :-
 166  *    Insert thread onto thread list for the fd.
 167  */
 168 static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self)
 169 {
 170     self->thr = pthread_self();
 171     self->intr = 0;
 172 
 173     pthread_mutex_lock(&(fdEntry->lock));
 174     {
 175         self->next = fdEntry->threads;
 176         fdEntry->threads = self;
 177     }
 178     pthread_mutex_unlock(&(fdEntry->lock));
 179 }
 180 
 181 /*
 182  * End a blocking operation :-
 183  *     Remove thread from thread list for the fd
 184  *     If fd has been interrupted then set errno to EBADF
 185  */
 186 static inline void endOp
 187     (fdEntry_t *fdEntry, threadEntry_t *self)
 188 {
 189     int orig_errno = errno;
 190     pthread_mutex_lock(&(fdEntry->lock));
 191     {
 192         threadEntry_t *curr, *prev=NULL;
 193         curr = fdEntry->threads;
 194         while (curr != NULL) {
 195             if (curr == self) {
 196                 if (curr->intr) {
 197                     orig_errno = EBADF;
 198                 }
 199                 if (prev == NULL) {
 200                     fdEntry->threads = curr->next;
 201                 } else {
 202                     prev->next = curr->next;
 203                 }
 204                 break;
 205             }
 206             prev = curr;
 207             curr = curr->next;
 208         }
 209     }
 210     pthread_mutex_unlock(&(fdEntry->lock));
 211     errno = orig_errno;
 212 }
 213 
 214 /*
 215  * Close or dup2 a file descriptor ensuring that all threads blocked on
 216  * the file descriptor are notified via a wakeup signal.
 217  *
 218  *      fd1 < 0    => close(fd2)
 219  *      fd1 >= 0   => dup2(fd1, fd2)
 220  *
 221  * Returns -1 with errno set if operation fails.
 222  */
 223 static int closefd(int fd1, int fd2) {
 224     int rv, orig_errno;
 225     fdEntry_t *fdEntry = getFdEntry(fd2);
 226     if (fdEntry == NULL) {
 227         errno = EBADF;
 228         return -1;
 229     }
 230 
 231     /*
 232      * Lock the fd to hold-off additional I/O on this fd.
 233      */
 234     pthread_mutex_lock(&(fdEntry->lock));
 235 
 236     {
 237         /* On fast machines we see that we enter dup2 before the
 238          * accepting thread had a chance to get and process the signal.
 239          * So in case we woke a thread up, give it some time to cope.
 240          * Also see https://bugs.openjdk.java.net/browse/JDK-8006395 */
 241         int num_woken = 0;
 242 
 243         /*
 244          * Send a wakeup signal to all threads blocked on this
 245          * file descriptor.
 246          */
 247         threadEntry_t *curr = fdEntry->threads;
 248         while (curr != NULL) {
 249             curr->intr = 1;
 250             pthread_kill( curr->thr, sigWakeup );
 251             num_woken ++;
 252             curr = curr->next;
 253         }
 254 
 255         if (num_woken > 0) {
 256           usleep(num_woken * 50);
 257         }
 258 
 259         /*
 260          * And close/dup the file descriptor
 261          * (restart if interrupted by signal)
 262          */
 263         do {
 264             if (fd1 < 0) {
 265                 rv = close(fd2);
 266             } else {
 267                 rv = dup2(fd1, fd2);
 268             }
 269         } while (rv == -1 && errno == EINTR);
 270     }
 271 
 272     /*
 273      * Unlock without destroying errno
 274      */
 275     orig_errno = errno;
 276     pthread_mutex_unlock(&(fdEntry->lock));
 277     errno = orig_errno;
 278 
 279     return rv;
 280 }
 281 
 282 /*
 283  * Wrapper for dup2 - same semantics as dup2 system call except
 284  * that any threads blocked in an I/O system call on fd2 will be
 285  * preempted and return -1/EBADF;
 286  */
 287 int NET_Dup2(int fd, int fd2) {
 288     if (fd < 0) {
 289         errno = EBADF;
 290         return -1;
 291     }
 292     return closefd(fd, fd2);
 293 }
 294 
 295 /*
 296  * Wrapper for close - same semantics as close system call
 297  * except that any threads blocked in an I/O on fd will be
 298  * preempted and the I/O system call will return -1/EBADF.
 299  */
 300 int NET_SocketClose(int fd) {
 301     return closefd(-1, fd);
 302 }
 303 
 304 /************** Basic I/O operations here ***************/
 305 
 306 /*
 307  * Macro to perform a blocking IO operation. Restarts
 308  * automatically if interrupted by signal (other than
 309  * our wakeup signal)
 310  */
 311 #define BLOCKING_IO_RETURN_INT(FD, FUNC) {      \
 312     int ret;                                    \
 313     threadEntry_t self;                         \
 314     fdEntry_t *fdEntry = getFdEntry(FD);        \
 315     if (fdEntry == NULL) {                      \
 316         errno = EBADF;                          \
 317         return -1;                              \
 318     }                                           \
 319     do {                                        \
 320         startOp(fdEntry, &self);                \
 321         ret = FUNC;                             \
 322         endOp(fdEntry, &self);                  \
 323     } while (ret == -1 && errno == EINTR);      \
 324     return ret;                                 \
 325 }
 326 
 327 int NET_Read(int s, void* buf, size_t len) {
 328     BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) );
 329 }
 330 
 331 int NET_ReadV(int s, const struct iovec * vector, int count) {
 332     BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) );
 333 }
 334 
 335 int NET_RecvFrom(int s, void *buf, int len, unsigned int flags,
 336        struct sockaddr *from, int *fromlen) {
 337     socklen_t socklen = *fromlen;
 338     BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, &socklen) );
 339     *fromlen = socklen;
 340 }
 341 
 342 int NET_Send(int s, void *msg, int len, unsigned int flags) {
 343     BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) );
 344 }
 345 
 346 int NET_WriteV(int s, const struct iovec * vector, int count) {
 347     BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) );
 348 }
 349 
 350 int NET_SendTo(int s, const void *msg, int len,  unsigned  int
 351        flags, const struct sockaddr *to, int tolen) {
 352     BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) );
 353 }
 354 
 355 int NET_Accept(int s, struct sockaddr *addr, int *addrlen) {
 356     socklen_t socklen = *addrlen;
 357     BLOCKING_IO_RETURN_INT( s, accept(s, addr, &socklen) );
 358     *addrlen = socklen;
 359 }
 360 
 361 int NET_Connect(int s, struct sockaddr *addr, int addrlen) {
 362     BLOCKING_IO_RETURN_INT( s, connect(s, addr, addrlen) );
 363 }
 364 
 365 #ifndef USE_SELECT
 366 int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) {
 367     BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) );
 368 }
 369 #else
 370 int NET_Select(int s, fd_set *readfds, fd_set *writefds,
 371                fd_set *exceptfds, struct timeval *timeout) {
 372     BLOCKING_IO_RETURN_INT( s-1,
 373                             select(s, readfds, writefds, exceptfds, timeout) );
 374 }
 375 #endif
 376 
 377 /*
 378  * Wrapper for poll(s, timeout).
 379  * Auto restarts with adjusted timeout if interrupted by
 380  * signal other than our wakeup signal.
 381  */
 382 int NET_Timeout(int s, long timeout) {
 383     long prevtime = 0, newtime;
 384     struct timeval t;
 385     fdEntry_t *fdEntry = getFdEntry(s);
 386 
 387     /*
 388      * Check that fd hasn't been closed.
 389      */
 390     if (fdEntry == NULL) {
 391         errno = EBADF;
 392         return -1;
 393     }
 394 
 395     /*
 396      * Pick up current time as may need to adjust timeout
 397      */
 398     if (timeout > 0) {
 399         gettimeofday(&t, NULL);
 400         prevtime = t.tv_sec * 1000  +  t.tv_usec / 1000;
 401     }
 402 
 403     for(;;) {
 404         struct pollfd pfd;
 405         int rv;
 406         threadEntry_t self;
 407 
 408         /*
 409          * Poll the fd. If interrupted by our wakeup signal
 410          * errno will be set to EBADF.
 411          */
 412         pfd.fd = s;
 413         pfd.events = POLLIN | POLLERR;
 414 
 415         startOp(fdEntry, &self);
 416         rv = poll(&pfd, 1, timeout);
 417         endOp(fdEntry, &self);
 418 
 419         /*
 420          * If interrupted then adjust timeout. If timeout
 421          * has expired return 0 (indicating timeout expired).
 422          */
 423         if (rv < 0 && errno == EINTR) {
 424             if (timeout > 0) {
 425                 gettimeofday(&t, NULL);
 426                 newtime = t.tv_sec * 1000  +  t.tv_usec / 1000;
 427                 timeout -= newtime - prevtime;
 428                 if (timeout <= 0) {
 429                     return 0;
 430                 }
 431                 prevtime = newtime;
 432             }
 433         } else {
 434             return rv;
 435         }
 436 
 437     }
 438 }
--- EOF ---