pollevent.cc revision 2665:a124942bacb8
1/*
2 * Copyright (c) 2002-2005 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 * Authors: Nathan Binkert
29 */
30
31#include <sys/ioctl.h>
32#include <sys/types.h>
33
34#include <fcntl.h>
35#include <signal.h>
36#include <unistd.h>
37
38#include "sim/async.hh"
39#include "sim/host.hh"
40#include "base/misc.hh"
41#include "base/pollevent.hh"
42#include "sim/root.hh"
43#include "sim/serialize.hh"
44
45using namespace std;
46
47PollQueue pollQueue;
48
49/////////////////////////////////////////////////////
50//
51PollEvent::PollEvent(int _fd, int _events)
52    : queue(NULL), enabled(true)
53{
54    pfd.fd = _fd;
55    pfd.events = _events;
56}
57
58PollEvent::~PollEvent()
59{
60    if (queue)
61        queue->remove(this);
62}
63
64void
65PollEvent::disable()
66{
67    if (!enabled) return;
68    enabled = false;
69
70    if (queue)
71        queue->copy();
72}
73
74void
75PollEvent::enable()
76{
77    if (enabled) return;
78    enabled = true;
79
80    if (queue)
81        queue->copy();
82}
83
84void
85PollEvent::serialize(ostream &os)
86{
87    SERIALIZE_SCALAR(pfd.fd);
88    SERIALIZE_SCALAR(pfd.events);
89    SERIALIZE_SCALAR(enabled);
90}
91
92void
93PollEvent::unserialize(Checkpoint *cp, const std::string &section)
94{
95    UNSERIALIZE_SCALAR(pfd.fd);
96    UNSERIALIZE_SCALAR(pfd.events);
97    UNSERIALIZE_SCALAR(enabled);
98}
99
100/////////////////////////////////////////////////////
101//
102PollQueue::PollQueue()
103    : poll_fds(NULL), max_size(0), num_fds(0)
104{ }
105
106PollQueue::~PollQueue()
107{
108    removeHandler();
109    for (int i = 0; i < num_fds; i++)
110        setupAsyncIO(poll_fds[0].fd, false);
111
112    delete [] poll_fds;
113}
114
115void
116PollQueue::copy()
117{
118    eventvec_t::iterator i = events.begin();
119    eventvec_t::iterator end = events.end();
120
121    num_fds = 0;
122
123    while (i < end) {
124        if ((*i)->enabled)
125            poll_fds[num_fds++] = (*i)->pfd;
126        ++i;
127    }
128}
129
130void
131PollQueue::remove(PollEvent *event)
132{
133    eventvec_t::iterator i = events.begin();
134    eventvec_t::iterator end = events.end();
135
136    while (i < end) {
137        if (*i == event) {
138           events.erase(i);
139           copy();
140           event->queue = NULL;
141           return;
142        }
143
144        ++i;
145    }
146
147    panic("Event does not exist.  Cannot remove.");
148}
149
150void
151PollQueue::schedule(PollEvent *event)
152{
153    if (event->queue)
154        panic("Event already scheduled!");
155
156    event->queue = this;
157    events.push_back(event);
158    setupAsyncIO(event->pfd.fd, true);
159
160    // if we ran out of space in the fd array, double the capacity
161    // if this is the first time that we've scheduled an event, create
162    // the array with an initial size of 16
163    if (++num_fds > max_size) {
164        if (max_size > 0) {
165            delete [] poll_fds;
166            max_size *= 2;
167        } else {
168            max_size = 16;
169            setupHandler();
170        }
171
172        poll_fds = new pollfd[max_size];
173    }
174
175    copy();
176}
177
178void
179PollQueue::service()
180{
181    int ret = poll(poll_fds, num_fds, 0);
182
183    if (ret <= 0)
184        return;
185
186    for (int i = 0; i < num_fds; i++) {
187        int revents = poll_fds[i].revents;
188        if (revents) {
189            events[i]->process(revents);
190            if (--ret <= 0)
191                break;
192        }
193    }
194}
195
196struct sigaction PollQueue::oldio;
197struct sigaction PollQueue::oldalrm;
198bool PollQueue::handler = false;
199
200void
201PollQueue::setupAsyncIO(int fd, bool set)
202{
203    int flags = fcntl(fd, F_GETFL);
204    if (flags == -1)
205        panic("Could not set up async IO");
206
207    if (set)
208        flags |= FASYNC;
209    else
210        flags &= ~(FASYNC);
211
212    if (fcntl(fd, F_SETFL, flags) == -1)
213        panic("Could not set up async IO");
214
215    if (set) {
216      if (fcntl(fd, F_SETOWN, getpid()) == -1)
217        panic("Could not set up async IO");
218    }
219}
220
221void
222PollQueue::setupHandler()
223{
224    struct sigaction act;
225
226    act.sa_handler = handleIO;
227    sigemptyset(&act.sa_mask);
228    act.sa_flags = SA_RESTART;
229
230    if (sigaction(SIGIO, &act, &oldio) == -1)
231        panic("could not do sigaction");
232
233    act.sa_handler = handleALRM;
234    sigemptyset(&act.sa_mask);
235    act.sa_flags = SA_RESTART;
236
237    if (sigaction(SIGALRM, &act, &oldalrm) == -1)
238        panic("could not do sigaction");
239
240    alarm(1);
241
242    handler = true;
243}
244
245void
246PollQueue::removeHandler()
247{
248    if (sigaction(SIGIO, &oldio, NULL) == -1)
249        panic("could not remove handler");
250
251    if (sigaction(SIGIO, &oldalrm, NULL) == -1)
252        panic("could not remove handler");
253}
254
255void
256PollQueue::handleIO(int sig)
257{
258    if (sig != SIGIO)
259        panic("Wrong Handler");
260
261    async_event = true;
262    async_io = true;
263}
264
265void
266PollQueue::handleALRM(int sig)
267{
268    if (sig != SIGALRM)
269        panic("Wrong Handler");
270
271    async_event = true;
272    async_alarm = true;
273    alarm(1);
274}
275
276