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