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