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