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 /*
|
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 <limits.h>
37 #include <errno.h>
38 #include <sys/poll.h>
39
40 /*
41 * Stack allocated by thread when doing blocking operation
42 */
43 typedef struct threadEntry {
44 pthread_t thr; /* this thread */
45 struct threadEntry *next; /* next thread */
46 int intr; /* interrupted */
47 } threadEntry_t;
48
49 /*
50 * Heap allocated during initialized - one entry per fd
51 */
52 typedef struct {
53 pthread_mutex_t lock; /* fd lock */
54 threadEntry_t *threads; /* threads blocked on fd */
55 } fdEntry_t;
56
57 /*
58 * Signal to unblock thread
59 */
60 static int sigWakeup = (__SIGRTMAX - 2);
61
62 /*
63 * The fd table holds one entry per file descriptor.
64 * Note: the number of possible file descriptors can get quite large;
65 * RLIMIT_NO_FILE can be large or even infinite.
66 * The fd table is organized as sparse two dimensional array, with a
67 * root array holding pointers to entry arrays, which in turn hold
68 * the entries. entry arrays are allocated on demand, save for the
69 * very first one, which is pre-allocated.
70 */
71 fdEntry_t** fdTable;
72 pthread_mutex_t fdTableLock = PTHREAD_MUTEX_INITIALIZER;
73 /* Number of bits to apply to the file descriptor to get the index into
74 * the root array resp. entry array */
75 unsigned fdTableRootArrayBits;
76 unsigned fdTableEntryArrayBits;
77
78 /*
79 * Null signal handler
80 */
81 static void sig_wakeup(int sig) {
82 }
83
84 /*
85 * Initialization routine (executed when library is loaded)
86 * Allocate fd tables and sets up signal handler.
87 */
88 static void __attribute((constructor)) init() {
89 struct rlimit nbr_files;
90 unsigned max = 0;
91 unsigned maxbits;
92 sigset_t sigset;
93 struct sigaction sa;
94
95 /* Determine the maximum number of possible file descriptors. */
96 getrlimit(RLIMIT_NOFILE, &nbr_files);
97 if (nbr_files.rlim_max != RLIM_INFINITY) {
98 max = nbr_files.rlim_max;
99 } else {
100 max = INT_MAX;
101 }
102
103 /* How many bits do we need to cover all possible values for
104 * file descriptors? */
105 for (maxbits = 1;
106 (unsigned) 1 << maxbits < max && maxbits < 32;
107 maxbits ++);
108
109 /* Calculate size of entry arrays: for small possible file descriptor ranges,
110 * fall back to a linear array. For larger ranges, make the entry tables 64K.
111 * This means for the largest possible range of INT_MAX (32bit ints), the root
112 * table will be 32K entries (32K * 64K = INT_MAX) */
113 fdTableEntryArrayBits = maxbits > 16 ? 16 : maxbits;
114 fdTableRootArrayBits = maxbits - fdTableEntryArrayBits;
115
116 /* Allocate root array */
117 fdTable = (fdEntry_t**)calloc(1 << fdTableRootArrayBits, sizeof(fdEntry_t*));
118 if (fdTable == NULL) {
119 fprintf(stderr, "library initialization failed - "
120 "unable to allocate file descriptor table - out of memory");
121 abort();
122 }
123 fdTable[0] = (fdEntry_t*)calloc(1 << fdTableEntryArrayBits, sizeof(fdEntry_t));
124 if (fdTable[0] == NULL) {
125 fprintf(stderr, "library initialization failed - "
126 "unable to allocate file descriptor table - out of memory");
127 abort();
128 }
129
130 /*
131 * Setup the signal handler
132 */
133 sa.sa_handler = sig_wakeup;
134 sa.sa_flags = 0;
135 sigemptyset(&sa.sa_mask);
136 sigaction(sigWakeup, &sa, NULL);
137
138 sigemptyset(&sigset);
139 sigaddset(&sigset, sigWakeup);
140 sigprocmask(SIG_UNBLOCK, &sigset, NULL);
141 }
142
143 /*
144 * Return the fd table for this fd or NULL is fd out
145 * of range.
146 */
147 static inline fdEntry_t *getFdEntry(int fd)
148 {
149 int rootArrayIndex;
150 int entryArrayIndex;
151 unsigned rootArrayMask;
152 unsigned entryArrayMask;
153 fdEntry_t* entryTable = NULL;
154
155 if (fd < 0) {
156 return NULL;
157 }
158
159 entryArrayMask = (1 << fdTableEntryArrayBits) - 1;
160 rootArrayMask =
161 ((1 << (fdTableRootArrayBits + fdTableEntryArrayBits)) - 1) & ~entryArrayMask;
162
163 entryArrayIndex = fd & entryArrayMask;
164 rootArrayIndex = (fd & rootArrayMask) >> fdTableEntryArrayBits;
165
166 if (rootArrayIndex == 0) {
167 /* fast path: first entry array gets preallocated. */
168 entryTable = fdTable[0];
169 } else {
170 /* Slow path: check if entry array exists, create it if needed */
171 pthread_mutex_lock(&fdTableLock);
172 if (fdTable[rootArrayIndex] == NULL) {
173 entryTable = (fdEntry_t*)calloc(1 << fdTableEntryArrayBits, sizeof(fdEntry_t));
174 if (entryTable == NULL) {
175 fprintf(stderr, "Unable to allocate file descriptor table - out of memory");
176 pthread_mutex_unlock(&fdTableLock);
177 abort();
178 }
179 fdTable[rootArrayIndex] = entryTable;
180 } else {
181 entryTable = fdTable[rootArrayIndex];
182 }
183 pthread_mutex_unlock(&fdTableLock);
184 }
185
186 return entryTable + entryArrayIndex;
187 }
188
189 /*
190 * Start a blocking operation :-
191 * Insert thread onto thread list for the fd.
192 */
193 static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self)
194 {
195 self->thr = pthread_self();
196 self->intr = 0;
197
198 pthread_mutex_lock(&(fdEntry->lock));
199 {
200 self->next = fdEntry->threads;
201 fdEntry->threads = self;
202 }
203 pthread_mutex_unlock(&(fdEntry->lock));
204 }
205
206 /*
|