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