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