1 /*
2 * Copyright (c) 2001, 2012, 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 #include <stdio.h>
27 #include <stdlib.h>
28 #include <sys/param.h>
29 #include <signal.h>
30 #include <pthread.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/select.h>
34 #include <sys/time.h>
35 #include <sys/resource.h>
36 #include <sys/uio.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <sys/poll.h>
40
41 /*
42 * Stack allocated by thread when doing blocking operation
43 */
44 typedef struct threadEntry {
45 pthread_t thr; /* this thread */
46 struct threadEntry *next; /* next thread */
47 int intr; /* interrupted */
48 } threadEntry_t;
49
50 /*
51 * Heap allocated during initialized - one entry per fd
52 */
53 typedef struct {
54 pthread_mutex_t lock; /* fd lock */
55 threadEntry_t *threads; /* threads blocked on fd */
56 } fdEntry_t;
57
58 /*
59 * Signal to unblock thread
60 */
61 static int sigWakeup = SIGIO;
62
63 /*
64 * The fd table and the number of file descriptors
65 */
66 static fdEntry_t *fdTable;
67 static int fdCount;
68
69 /*
70 * This limit applies if getlimit() returns unlimited.
71 * Unfortunately, this means if someone wants a higher limit
72 * then they have to set an explicit limit, higher than this,
73 * which is probably counter-intuitive.
74 */
75 #define MAX_FD_COUNT 4096
76
77 /*
78 * Null signal handler
79 */
80 static void sig_wakeup(int sig) {
81 }
82
83 /*
84 * Initialization routine (executed when library is loaded)
85 * Allocate fd tables and sets up signal handler.
86 */
87 static void __attribute((constructor)) init() {
88 struct rlimit nbr_files;
89 sigset_t sigset;
90 struct sigaction sa;
91 int i;
92
93 /*
94 * Allocate table based on the maximum number of
95 * file descriptors.
96 */
97 getrlimit(RLIMIT_NOFILE, &nbr_files);
98 if (nbr_files.rlim_max == RLIM_INFINITY) {
99 fdCount = MAX_FD_COUNT;
100 } else {
101 fdCount = nbr_files.rlim_max;
102 }
103 fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t));
104 if (fdTable == NULL) {
105 fprintf(stderr, "library initialization failed - "
106 "unable to allocate file descriptor table - out of memory");
107 abort();
108 }
109 for (i=0; i<fdCount; i++) {
110 pthread_mutex_init(&fdTable[i].lock, NULL);
111 }
112
113 /*
114 * Setup the signal handler
115 */
116 sa.sa_handler = sig_wakeup;
117 sa.sa_flags = 0;
118 sigemptyset(&sa.sa_mask);
119 sigaction(sigWakeup, &sa, NULL);
120
121 sigemptyset(&sigset);
122 sigaddset(&sigset, sigWakeup);
123 sigprocmask(SIG_UNBLOCK, &sigset, NULL);
124 }
125
126 /*
127 * Return the fd table for this fd or NULL is fd out
128 * of range.
129 */
130 static inline fdEntry_t *getFdEntry(int fd)
131 {
132 if (fd < 0 || fd >= fdCount) {
133 return NULL;
134 }
135 return &fdTable[fd];
136 }
137
138 /*
139 * Start a blocking operation :-
140 * Insert thread onto thread list for the fd.
141 */
142 static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self)
143 {
144 self->thr = pthread_self();
145 self->intr = 0;
146
147 pthread_mutex_lock(&(fdEntry->lock));
148 {
149 self->next = fdEntry->threads;
150 fdEntry->threads = self;
151 }
152 pthread_mutex_unlock(&(fdEntry->lock));
153 }
154
155 /*
|
1 /*
2 * Copyright (c) 2001, 2016, 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 #include <assert.h>
27 #include <limits.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <sys/param.h>
31 #include <signal.h>
32 #include <pthread.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/select.h>
36 #include <sys/time.h>
37 #include <sys/resource.h>
38 #include <sys/uio.h>
39 #include <unistd.h>
40 #include <errno.h>
41 #include <sys/poll.h>
42
43 /*
44 * Stack allocated by thread when doing blocking operation
45 */
46 typedef struct threadEntry {
47 pthread_t thr; /* this thread */
48 struct threadEntry *next; /* next thread */
49 int intr; /* interrupted */
50 } threadEntry_t;
51
52 /*
53 * Heap allocated during initialized - one entry per fd
54 */
55 typedef struct {
56 pthread_mutex_t lock; /* fd lock */
57 threadEntry_t *threads; /* threads blocked on fd */
58 } fdEntry_t;
59
60 /*
61 * Signal to unblock thread
62 */
63 static int sigWakeup = SIGIO;
64
65 /*
66 * fdTable holds one entry per file descriptor, up to a certain
67 * maximum.
68 * Theoretically, the number of possible file descriptors can get
69 * large, though usually it does not. To save memory, we keep file
70 * descriptors with large numerical values in an overflow table. That
71 * table is organized as a two-dimensional sparse array, allocated
72 * on demand.
73 */
74
75 static fdEntry_t* fdTable;
76 /* Max. number of file descriptors in fdTable. */
77 static const int fdTableMaxSize = 0x1000; /* 4K */
78 /* Max. theoretical number of file descriptor on system. */
79 static int fdLimit;
80 /* Length of fdTable, in number of entries. */
81 static int fdTableLen;
82
83 /* Overflow table: organized as array of n slabs, each holding
84 * 64k entries.
85 */
86 static fdEntry_t** fdOverflowTable;
87 /* Number of slabs in the overflow table */
88 static int fdOverflowTableLen;
89 /* Number of entries in one slab */
90 static const int fdOverflowTableSlabSize = 0x10000; /* 64k */
91 pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER;
92
93 /*
94 * Null signal handler
95 */
96 static void sig_wakeup(int sig) {
97 }
98
99 /*
100 * Initialization routine (executed when library is loaded)
101 * Allocate fd tables and sets up signal handler.
102 */
103 static void __attribute((constructor)) init() {
104 struct rlimit nbr_files;
105 sigset_t sigset;
106 struct sigaction sa;
107 int i = 0;
108
109 /* Determine the maximum number of possible file descriptors. */
110 getrlimit(RLIMIT_NOFILE, &nbr_files);
111 if (nbr_files.rlim_max != RLIM_INFINITY) {
112 fdLimit = nbr_files.rlim_max;
113 } else {
114 /* We just do not know. */
115 fdLimit = INT_MAX;
116 }
117
118 /* Allocate table for low value file descriptors. */
119 fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize;
120 fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t));
121 if (fdTable == NULL) {
122 fprintf(stderr, "library initialization failed - "
123 "unable to allocate file descriptor table - out of memory");
124 abort();
125 } else {
126 for (i = 0; i < fdTableLen; i ++) {
127 pthread_mutex_init(&fdTable[i].lock, NULL);
128 }
129 }
130
131 /* Allocate overflow table, if needed */
132 if (fdLimit > fdTableMaxSize) {
133 fdOverflowTableLen = ((fdLimit - fdTableMaxSize) / fdOverflowTableSlabSize) + 1;
134 fdOverflowTable = (fdEntry_t**) calloc(fdOverflowTableLen, sizeof(fdEntry_t*));
135 if (fdOverflowTable == NULL) {
136 fprintf(stderr, "library initialization failed - "
137 "unable to allocate file descriptor overflow table - out of memory");
138 abort();
139 }
140 }
141
142 /*
143 * Setup the signal handler
144 */
145 sa.sa_handler = sig_wakeup;
146 sa.sa_flags = 0;
147 sigemptyset(&sa.sa_mask);
148 sigaction(sigWakeup, &sa, NULL);
149
150 sigemptyset(&sigset);
151 sigaddset(&sigset, sigWakeup);
152 sigprocmask(SIG_UNBLOCK, &sigset, NULL);
153 }
154
155 /*
156 * Return the fd table for this fd.
157 */
158 static inline fdEntry_t *getFdEntry(int fd)
159 {
160 fdEntry_t* result = NULL;
161
162 if (fd < 0) {
163 return NULL;
164 }
165
166 /* This should not happen. If it does, our assumption about
167 * max. fd value was wrong. */
168 assert(fd < fdLimit);
169
170 if (fd < fdTableMaxSize) {
171 assert(fd < fdTableLen);
172 result = fdTable + fd;
173 } else {
174 const int indexInOverflowTable = fd - fdTableMaxSize;
175 const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize;
176 const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize;
177 assert(rootindex < fdOverflowTableLen);
178 assert(slabindex < fdOverflowTableSlabSize);
179 pthread_mutex_lock(&fdOverflowTableLock);
180 if (fdOverflowTable[rootindex] == NULL) {
181 fdEntry_t* const newSlab =
182 (fdEntry_t*)calloc(fdOverflowTableSlabSize, sizeof(fdEntry_t));
183 if (newSlab == NULL) {
184 fprintf(stderr, "Unable to allocate file descriptor table - out of memory");
185 pthread_mutex_unlock(&fdOverflowTableLock);
186 abort();
187 } else {
188 int i;
189 for (i = 0; i < fdOverflowTableSlabSize; i ++) {
190 pthread_mutex_init(&newSlab[i].lock, NULL);
191 }
192 fdOverflowTable[rootindex] = newSlab;
193 }
194 }
195 pthread_mutex_unlock(&fdOverflowTableLock);
196 result = fdOverflowTable[rootindex] + slabindex;
197 }
198
199 return result;
200
201 }
202
203 /*
204 * Start a blocking operation :-
205 * Insert thread onto thread list for the fd.
206 */
207 static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self)
208 {
209 self->thr = pthread_self();
210 self->intr = 0;
211
212 pthread_mutex_lock(&(fdEntry->lock));
213 {
214 self->next = fdEntry->threads;
215 fdEntry->threads = self;
216 }
217 pthread_mutex_unlock(&(fdEntry->lock));
218 }
219
220 /*
|