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 /*
|
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 holds one entry per file descriptor.
63 * Note: the number of possible file descriptors can get quite large;
64 * RLIMIT_NO_FILE can be large or even infinite.
65 * Instead of allocating a plain array of RLIMIT_NO_FILE len, we
66 * allocate a two dimensional sparse array: file descriptors are
67 * of type int, which on all our platforms is 32bit; so we
68 * use the upper 16 bit as index into a base table, and the lower
69 * 16bit as index into the actual entry table; the latter is only
70 * allocated on demand.
71 * Usually (<64K file descriptors and file descriptors handed out
72 * sequentually) there will only be the base table and one entry
73 * table in slot 0. But this approach handles corner cases like
74 * large file descriptor values seamlessly.
75 */
76 static fdEntry_t** fdTable;
77 static pthread_mutex_t fdTableLock = PTHREAD_MUTEX_INITIALIZER;
78
79 /*
80 * Null signal handler
81 */
82 static void sig_wakeup(int sig) {
83 }
84
85 /*
86 * Initialization routine (executed when library is loaded)
87 * Allocate fd tables and sets up signal handler.
88 */
89 static void __attribute((constructor)) init() {
90 sigset_t sigset;
91 struct sigaction sa;
92
93 fdTable = (fdEntry_t**)calloc(0x10000, sizeof(fdEntry_t*));
94 if (fdTable == NULL) {
95 fprintf(stderr, "library initialization failed - "
96 "unable to allocate file descriptor table - out of memory");
97 abort();
98 }
99
100 /*
101 * Setup the signal handler
102 */
103 sa.sa_handler = sig_wakeup;
104 sa.sa_flags = 0;
105 sigemptyset(&sa.sa_mask);
106 sigaction(sigWakeup, &sa, NULL);
107
108 sigemptyset(&sigset);
109 sigaddset(&sigset, sigWakeup);
110 sigprocmask(SIG_UNBLOCK, &sigset, NULL);
111 }
112
113 /*
114 * Return the fd table for this fd or NULL is fd out
115 * of range.
116 */
117 static inline fdEntry_t *getFdEntry(int fd)
118 {
119 int base_index;
120 int index;
121 fdEntry_t* entryTable = NULL;
122
123 if (fd < 0) {
124 return NULL;
125 }
126
127 base_index = fd >> 16;
128 index = fd & 0xFFFF;
129
130 /* Look up the entry table; create it if needed */
131 pthread_mutex_lock(&fdTableLock);
132 if (fdTable[base_index] == NULL) {
133 entryTable = calloc(0x10000, sizeof(fdEntry_t));
134 if (entryTable == NULL) {
135 fprintf(stderr, "Unable to allocate file descriptor table - out of memory");
136 pthread_mutex_unlock(&fdTableLock);
137 abort();
138 }
139 fdTable[base_index] = entryTable;
140 } else {
141 entryTable = fdTable[base_index];
142 }
143 pthread_mutex_unlock(&fdTableLock);
144
145 return entryTable + index;
146 }
147
148 /*
149 * Start a blocking operation :-
150 * Insert thread onto thread list for the fd.
151 */
152 static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self)
153 {
154 self->thr = pthread_self();
155 self->intr = 0;
156
157 pthread_mutex_lock(&(fdEntry->lock));
158 {
159 self->next = fdEntry->threads;
160 fdEntry->threads = self;
161 }
162 pthread_mutex_unlock(&(fdEntry->lock));
163 }
164
165 /*
|