pollevent.cc revision 56
1/*
2 * Copyright (c) 2003 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/ioctl.h>
30#include <sys/types.h>
31
32#include <fcntl.h>
33#include <signal.h>
34#include <unistd.h>
35
36#include "sim/async.hh"
37#include "sim/host.hh"
38#include "base/misc.hh"
39#include "base/pollevent.hh"
40#include "sim/universe.hh"
41
42PollQueue pollQueue;
43
44/////////////////////////////////////////////////////
45//
46PollEvent::PollEvent(int _fd, int _events)
47    : queue(NULL), enabled(true)
48{
49    pfd.fd = _fd;
50    pfd.events = _events;
51}
52
53PollEvent::~PollEvent()
54{
55    if (queue)
56        queue->remove(this);
57}
58
59void
60PollEvent::disable()
61{
62    if (!enabled) return;
63    enabled = false;
64
65    if (queue)
66        queue->copy();
67}
68
69void
70PollEvent::enable()
71{
72    if (enabled) return;
73    enabled = true;
74
75    if (queue)
76        queue->copy();
77}
78
79/////////////////////////////////////////////////////
80//
81PollQueue::PollQueue()
82    : poll_fds(NULL), max_size(0), num_fds(0)
83{ }
84
85PollQueue::~PollQueue()
86{
87    removeHandler();
88    for (int i = 0; i < num_fds; i++)
89        setupAsyncIO(poll_fds[0].fd, false);
90
91    delete [] poll_fds;
92}
93
94void
95PollQueue::copy()
96{
97    eventvec_t::iterator i = events.begin();
98    eventvec_t::iterator end = events.end();
99
100    num_fds = 0;
101
102    while (i < end) {
103        if ((*i)->enabled)
104            poll_fds[num_fds++] = (*i)->pfd;
105        ++i;
106    }
107}
108
109void
110PollQueue::remove(PollEvent *event)
111{
112    eventvec_t::iterator i = events.begin();
113    eventvec_t::iterator end = events.end();
114
115    while (i < end) {
116        if (*i == event) {
117           events.erase(i);
118           copy();
119           event->queue = NULL;
120           return;
121        }
122
123        ++i;
124    }
125
126    panic("Event does not exist.  Cannot remove.");
127}
128
129void
130PollQueue::schedule(PollEvent *event)
131{
132    if (event->queue)
133        panic("Event already scheduled!");
134
135    event->queue = this;
136    events.push_back(event);
137    setupAsyncIO(event->pfd.fd, true);
138
139    // if we ran out of space in the fd array, double the capacity
140    // if this is the first time that we've scheduled an event, create
141    // the array with an initial size of 16
142    if (++num_fds > max_size) {
143        if (max_size > 0) {
144            delete [] poll_fds;
145            max_size *= 2;
146        } else {
147            max_size = 16;
148            setupHandler();
149        }
150
151        poll_fds = new pollfd[max_size];
152    }
153
154    copy();
155}
156
157void
158PollQueue::service()
159{
160    int ret = poll(poll_fds, num_fds, 0);
161
162    if (ret <= 0)
163        return;
164
165    for (int i = 0; i < num_fds; i++) {
166        int revents = poll_fds[i].revents;
167        if (revents) {
168            events[i]->process(revents);
169            if (--ret <= 0)
170                break;
171        }
172    }
173}
174
175struct sigaction PollQueue::oldio;
176struct sigaction PollQueue::oldalrm;
177bool PollQueue::handler = false;
178
179void
180PollQueue::setupAsyncIO(int fd, bool set)
181{
182    int flags = fcntl(fd, F_GETFL);
183    if (flags == -1)
184        panic("Could not set up async IO");
185
186    if (set)
187        flags |= FASYNC;
188    else
189        flags &= ~(FASYNC);
190
191    if (fcntl(fd, F_SETFL, flags) == -1)
192        panic("Could not set up async IO");
193
194    if (set) {
195      if (fcntl(fd, F_SETOWN, getpid()) == -1)
196        panic("Could not set up async IO");
197    }
198}
199
200void
201PollQueue::setupHandler()
202{
203    struct sigaction act;
204
205    act.sa_handler = handleIO;
206    sigemptyset(&act.sa_mask);
207    act.sa_flags = 0;
208
209    if (sigaction(SIGIO, &act, &oldio) == -1)
210        panic("could not do sigaction");
211
212    act.sa_handler = handleALRM;
213    sigemptyset(&act.sa_mask);
214    act.sa_flags = 0;
215
216    if (sigaction(SIGALRM, &act, &oldalrm) == -1)
217        panic("could not do sigaction");
218
219    alarm(1);
220
221    handler = true;
222}
223
224void
225PollQueue::removeHandler()
226{
227    if (sigaction(SIGIO, &oldio, NULL) == -1)
228        panic("could not remove handler");
229
230    if (sigaction(SIGIO, &oldalrm, NULL) == -1)
231        panic("could not remove handler");
232}
233
234void
235PollQueue::handleIO(int sig)
236{
237    if (sig != SIGIO)
238        panic("Wrong Handler");
239
240    async_event = true;
241    async_io = true;
242}
243
244void
245PollQueue::handleALRM(int sig)
246{
247    if (sig != SIGALRM)
248        panic("Wrong Handler");
249
250    async_event = true;
251    async_alarm = true;
252    alarm(1);
253}
254
255