pollevent.cc revision 10360:919c02740209
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#if defined(__sun__) || defined(__SUNPRO_CC)
34#include <sys/file.h>
35#endif
36
37#include <fcntl.h>
38#include <unistd.h>
39
40#include <csignal>
41
42#include "base/misc.hh"
43#include "base/pollevent.hh"
44#include "base/types.hh"
45#include "sim/async.hh"
46#include "sim/core.hh"
47#include "sim/serialize.hh"
48
49using namespace std;
50
51PollQueue pollQueue;
52
53/////////////////////////////////////////////////////
54//
55PollEvent::PollEvent(int _fd, int _events)
56    : queue(NULL), enabled(true)
57{
58    pfd.fd = _fd;
59    pfd.events = _events;
60    pfd.revents = 0;
61}
62
63PollEvent::~PollEvent()
64{
65    if (queue)
66        queue->remove(this);
67}
68
69void
70PollEvent::disable()
71{
72    if (!enabled) return;
73    enabled = false;
74
75    if (queue)
76        queue->copy();
77}
78
79void
80PollEvent::enable()
81{
82    if (enabled) return;
83    enabled = true;
84
85    if (queue)
86        queue->copy();
87}
88
89void
90PollEvent::serialize(ostream &os)
91{
92    SERIALIZE_SCALAR(pfd.fd);
93    SERIALIZE_SCALAR(pfd.events);
94    SERIALIZE_SCALAR(enabled);
95}
96
97void
98PollEvent::unserialize(Checkpoint *cp, const std::string &section)
99{
100    UNSERIALIZE_SCALAR(pfd.fd);
101    UNSERIALIZE_SCALAR(pfd.events);
102    UNSERIALIZE_SCALAR(enabled);
103}
104
105/////////////////////////////////////////////////////
106//
107PollQueue::PollQueue()
108    : poll_fds(NULL), max_size(0), num_fds(0)
109{ }
110
111PollQueue::~PollQueue()
112{
113    for (int i = 0; i < num_fds; i++)
114        setupAsyncIO(poll_fds[0].fd, false);
115
116    delete [] poll_fds;
117}
118
119void
120PollQueue::copy()
121{
122    eventvec_t::iterator i = events.begin();
123    eventvec_t::iterator end = events.end();
124
125    num_fds = 0;
126
127    while (i < end) {
128        if ((*i)->enabled)
129            poll_fds[num_fds++] = (*i)->pfd;
130        ++i;
131    }
132}
133
134void
135PollQueue::remove(PollEvent *event)
136{
137    eventvec_t::iterator i = events.begin();
138    eventvec_t::iterator end = events.end();
139
140    while (i < end) {
141        if (*i == event) {
142           events.erase(i);
143           copy();
144           event->queue = NULL;
145           return;
146        }
147
148        ++i;
149    }
150
151    panic("Event does not exist.  Cannot remove.");
152}
153
154void
155PollQueue::schedule(PollEvent *event)
156{
157    if (event->queue)
158        panic("Event already scheduled!");
159
160    event->queue = this;
161    events.push_back(event);
162    setupAsyncIO(event->pfd.fd, true);
163
164    // if we ran out of space in the fd array, double the capacity
165    // if this is the first time that we've scheduled an event, create
166    // the array with an initial size of 16
167    if (++num_fds > max_size) {
168        if (max_size > 0) {
169            delete [] poll_fds;
170            max_size *= 2;
171        } else {
172            max_size = 16;
173        }
174
175        poll_fds = new pollfd[max_size];
176    }
177
178    copy();
179}
180
181void
182PollQueue::service()
183{
184    int ret = poll(poll_fds, num_fds, 0);
185
186    if (ret <= 0)
187        return;
188
189    for (int i = 0; i < num_fds; i++) {
190        int revents = poll_fds[i].revents;
191        if (revents) {
192            events[i]->process(revents);
193            if (--ret <= 0)
194                break;
195        }
196    }
197}
198
199void
200PollQueue::setupAsyncIO(int fd, bool set)
201{
202    int flags = fcntl(fd, F_GETFL);
203    if (flags == -1)
204        panic("Could not set up async IO");
205
206    if (set)
207        flags |= FASYNC;
208    else
209        flags &= ~(FASYNC);
210
211    if (set) {
212      if (fcntl(fd, F_SETOWN, getpid()) == -1)
213        panic("Could not set up async IO");
214    }
215
216    if (fcntl(fd, F_SETFL, flags) == -1)
217        panic("Could not set up async IO");
218
219    // The file descriptor might already have events pending. We won't
220    // see them if they occurred before we set the FASYNC
221    // flag. Simulate a SIGIO to ensure that the FD will be polled in
222    // next iteration of the simulation loop. We could just poll it,
223    // but this is much simpler.
224    if (set) {
225        async_event = true;
226        async_io = true;
227    }
228}
229