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 /*
|