~ubuntu-branches/ubuntu/vivid/cctools/vivid

« back to all changes in this revision

Viewing changes to parrot/src/pfs_poll.cc

  • Committer: Bazaar Package Importer
  • Author(s): Michael Hanke
  • Date: 2011-05-07 09:05:00 UTC
  • Revision ID: james.westby@ubuntu.com-20110507090500-lqpmdtwndor6e7os
Tags: upstream-3.3.2
ImportĀ upstreamĀ versionĀ 3.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright (C) 2003-2004 Douglas Thain and the University of Wisconsin
 
3
Copyright (C) 2005- The University of Notre Dame
 
4
This software is distributed under the GNU General Public License.
 
5
See the file COPYING for details.
 
6
*/
 
7
 
 
8
#include "pfs_poll.h"
 
9
#include "pfs_process.h"
 
10
#include "pfs_critical.h"
 
11
 
 
12
extern "C" {
 
13
#include "macros.h"
 
14
#include "debug.h"
 
15
}
 
16
 
 
17
#include <string.h>
 
18
#include <errno.h>
 
19
#include <fcntl.h>
 
20
#include <unistd.h>
 
21
#include <sys/select.h>
 
22
#include <stdio.h>
 
23
#include <signal.h>
 
24
 
 
25
/*
 
26
This code has a race condition that is unavoidable.
 
27
We want to select on a number of file descriptors,
 
28
but be woken up if a sigchild comes in.  Sadly, Linux
 
29
has no atomic pselect.  To combat this, we put an
 
30
upper bound on the select sleep time, and check an
 
31
integer shortly before selecting.  Not much else
 
32
to do.
 
33
*/
 
34
 
 
35
#define POLL_TIME_MAX 1
 
36
 
 
37
#define POLL_TABLE_MAX 4096
 
38
#define SLEEP_TABLE_MAX 4096
 
39
 
 
40
struct poll_entry {
 
41
        int fd;
 
42
        pid_t pid;
 
43
        int flags;
 
44
};
 
45
 
 
46
struct sleep_entry {
 
47
        struct timeval stoptime;
 
48
        pid_t pid;
 
49
};
 
50
 
 
51
static struct poll_entry poll_table[POLL_TABLE_MAX];
 
52
static struct sleep_entry sleep_table[SLEEP_TABLE_MAX];
 
53
 
 
54
static int poll_table_size = 0;
 
55
static int sleep_table_size = 0;
 
56
static int poll_abort_now = 0;
 
57
 
 
58
extern void install_handler( int sig, void (*handler)(int sig));
 
59
extern void handle_sigchld( int sig );
 
60
 
 
61
void pfs_poll_abort()
 
62
{
 
63
        poll_abort_now = 1;
 
64
}
 
65
 
 
66
void pfs_poll_init()
 
67
{
 
68
        int i;
 
69
        for(i=0;i<POLL_TABLE_MAX;i++) {
 
70
                poll_table[i].pid = -1;
 
71
        }
 
72
        for(i=0;i<SLEEP_TABLE_MAX;i++) {
 
73
                sleep_table[i].pid = -1;
 
74
        }
 
75
}
 
76
 
 
77
void pfs_poll_clear( int pid )
 
78
{
 
79
        int i;
 
80
        for(i=0;i<poll_table_size;i++) {
 
81
                if(poll_table[i].pid==pid) poll_table[i].pid = -1;
 
82
        }
 
83
        for(i=0;i<sleep_table_size;i++) {
 
84
                if(sleep_table[i].pid==pid) sleep_table[i].pid = -1;
 
85
        }
 
86
}
 
87
 
 
88
void pfs_poll_sleep()
 
89
{
 
90
        struct timeval curtime;
 
91
        struct timeval stoptime;
 
92
        struct timeval sleeptime;
 
93
        fd_set rfds, wfds, efds;
 
94
        struct sleep_entry *s;
 
95
        struct poll_entry *p;
 
96
        int maxfd=0, i;
 
97
        int result;
 
98
 
 
99
        FD_ZERO(&rfds);
 
100
        FD_ZERO(&wfds);
 
101
        FD_ZERO(&efds);
 
102
 
 
103
        poll_abort_now = 0;
 
104
 
 
105
        gettimeofday(&curtime,0);
 
106
        stoptime = curtime;
 
107
        stoptime.tv_sec += POLL_TIME_MAX;
 
108
 
 
109
        for(i=0;i<poll_table_size;i++) {
 
110
                p = &poll_table[i];
 
111
                if(p->pid>=0) {
 
112
                        maxfd = MAX(p->fd+1,maxfd);
 
113
                        if(p->flags&PFS_POLL_READ) FD_SET(p->fd,&rfds);
 
114
                        if(p->flags&PFS_POLL_WRITE) FD_SET(p->fd,&wfds);
 
115
                        if(p->flags&PFS_POLL_EXCEPT) FD_SET(p->fd,&efds);
 
116
                }
 
117
        }
 
118
        for(i=0;i<sleep_table_size;i++) {
 
119
                s = &sleep_table[i];
 
120
                if(s->pid>=0) {
 
121
                        if(timercmp(&stoptime,&s->stoptime,>)) {
 
122
                                stoptime = s->stoptime;
 
123
                        }
 
124
                }
 
125
        }
 
126
 
 
127
        sleeptime.tv_sec = stoptime.tv_sec - curtime.tv_sec;
 
128
        sleeptime.tv_usec = stoptime.tv_usec - curtime.tv_usec;
 
129
 
 
130
        while(sleeptime.tv_usec<0) {
 
131
                sleeptime.tv_usec += 1000000;
 
132
                sleeptime.tv_sec -= 1;
 
133
        }
 
134
 
 
135
        CRITICAL_END
 
136
 
 
137
        if(!poll_abort_now && sleeptime.tv_sec>0) usleep(1);
 
138
 
 
139
        if(sleeptime.tv_sec<0 || poll_abort_now) {
 
140
                sleeptime.tv_sec = 0;
 
141
                sleeptime.tv_usec = 0;
 
142
        }
 
143
 
 
144
        result = select(maxfd,&rfds,&wfds,&efds,&sleeptime);
 
145
 
 
146
        CRITICAL_BEGIN
 
147
 
 
148
        if(result>0) {
 
149
                for(i=0;i<poll_table_size;i++) {
 
150
                        p = &poll_table[i];
 
151
                        if(p->pid>=0) {
 
152
                                if(
 
153
                                        (p->flags&PFS_POLL_READ && FD_ISSET(p->fd,&rfds)) ||
 
154
                                        (p->flags&PFS_POLL_WRITE && FD_ISSET(p->fd,&wfds)) ||
 
155
                                        (p->flags&PFS_POLL_EXCEPT && FD_ISSET(p->fd,&efds))
 
156
                                ) {
 
157
                                        pid_t pid = p->pid;
 
158
                                        debug(D_POLL,"waking pid %d because of fd %d",pid,p->fd);
 
159
                                        pfs_poll_clear(pid);
 
160
                                        pfs_process_wake(pid);
 
161
                                }
 
162
                        }
 
163
                }
 
164
        } else if(result==0) {
 
165
                // select timed out, which should never happen, except
 
166
                // that it does when the jvm linked with hdfs sets up its
 
167
                // signal handlers to avoid sigchld.  In that case, re-install
 
168
                install_handler(SIGCHLD,handle_sigchld);
 
169
 
 
170
                gettimeofday(&curtime,0);
 
171
 
 
172
                for(i=0;i<sleep_table_size;i++) {
 
173
                        s = &sleep_table[i];
 
174
                        if(s->pid>=0) {
 
175
                                if(timercmp(&curtime,&s->stoptime,>)) {
 
176
                                        pid_t pid = s->pid;
 
177
                                        debug(D_POLL,"waking pid %d because time expired",pid);
 
178
                                        pfs_poll_clear(pid);
 
179
                                        pfs_process_wake(pid);
 
180
                                }
 
181
                        }
 
182
                }
 
183
        } else if(errno==EBADF) {
 
184
                debug(D_POLL,"select returned EBADF, which really shouldn't happen.");
 
185
                debug(D_POLL,"waking up all processes to clean up and try again.");
 
186
 
 
187
                p = &poll_table[i];
 
188
                if(p->pid>=0) {
 
189
                        pid_t pid = p->pid;
 
190
                        debug(D_POLL,"waking pid %d",pid);
 
191
                        pfs_poll_clear(pid);
 
192
                        pfs_process_wake(pid);
 
193
                }
 
194
        }
 
195
 
 
196
}
 
197
 
 
198
void pfs_poll_wakeon( int fd, int flags )
 
199
{
 
200
        struct poll_entry *p;
 
201
        int i;
 
202
 
 
203
        debug(D_POLL,"wake on fd %d flags %s",fd,pfs_poll_string(flags));
 
204
 
 
205
        for(i=0;i<POLL_TABLE_MAX;i++) {
 
206
                p = &poll_table[i];
 
207
                if(p->pid<0) {
 
208
                        p->fd = fd;
 
209
                        p->pid = pfs_process_getpid();
 
210
                        p->flags = flags;
 
211
                        if(i>=poll_table_size) poll_table_size=i+1;
 
212
                        return;
 
213
                }
 
214
        }
 
215
 
 
216
        fatal("ran out of poll table space!");
 
217
}
 
218
 
 
219
void pfs_poll_wakein( struct timeval tv )
 
220
{
 
221
        struct sleep_entry *s;
 
222
        int i;
 
223
 
 
224
        debug(D_POLL,"wake in time %d.%06d",tv.tv_sec,tv.tv_usec);
 
225
 
 
226
        for(i=0;i<SLEEP_TABLE_MAX;i++) {
 
227
                s = &sleep_table[i];
 
228
                if(s->pid<0) {
 
229
                        s->pid = pfs_process_getpid();
 
230
                        gettimeofday(&s->stoptime,0);
 
231
                        s->stoptime.tv_sec += tv.tv_sec;
 
232
                        s->stoptime.tv_usec += tv.tv_usec;
 
233
                        while(s->stoptime.tv_usec>1000000) {
 
234
                                s->stoptime.tv_sec++;
 
235
                                s->stoptime.tv_usec-=1000000;
 
236
                        }
 
237
                        if(i>=sleep_table_size) sleep_table_size=i+1;
 
238
                        return;
 
239
                }
 
240
        }
 
241
 
 
242
        fatal("ran out of sleep table space!");
 
243
}
 
244
 
 
245
char * pfs_poll_string( int flags )
 
246
{
 
247
        static char str[4];
 
248
        if(flags&PFS_POLL_READ) {
 
249
                str[0] = 'r';
 
250
        } else {
 
251
                str[0] = '-';
 
252
        }
 
253
        if(flags&PFS_POLL_WRITE) {
 
254
                str[1] = 'w';
 
255
        } else {
 
256
                str[1] = '-';
 
257
        }
 
258
        if(flags&PFS_POLL_EXCEPT) {
 
259
                str[2] = 'e';
 
260
        } else {
 
261
                str[2] = '-';
 
262
        }
 
263
        str[3] = 0;
 
264
        return str;
 
265
}
 
266