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