/* * Copyright (c) 2002-2005 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Nathan Binkert */ #include #include #include #include #include #include "sim/async.hh" #include "sim/host.hh" #include "base/misc.hh" #include "base/pollevent.hh" #include "sim/root.hh" #include "sim/serialize.hh" using namespace std; PollQueue pollQueue; ///////////////////////////////////////////////////// // PollEvent::PollEvent(int _fd, int _events) : queue(NULL), enabled(true) { pfd.fd = _fd; pfd.events = _events; } PollEvent::~PollEvent() { if (queue) queue->remove(this); } void PollEvent::disable() { if (!enabled) return; enabled = false; if (queue) queue->copy(); } void PollEvent::enable() { if (enabled) return; enabled = true; if (queue) queue->copy(); } void PollEvent::serialize(ostream &os) { SERIALIZE_SCALAR(pfd.fd); SERIALIZE_SCALAR(pfd.events); SERIALIZE_SCALAR(enabled); } void PollEvent::unserialize(Checkpoint *cp, const std::string §ion) { UNSERIALIZE_SCALAR(pfd.fd); UNSERIALIZE_SCALAR(pfd.events); UNSERIALIZE_SCALAR(enabled); } ///////////////////////////////////////////////////// // PollQueue::PollQueue() : poll_fds(NULL), max_size(0), num_fds(0) { } PollQueue::~PollQueue() { removeHandler(); for (int i = 0; i < num_fds; i++) setupAsyncIO(poll_fds[0].fd, false); delete [] poll_fds; } void PollQueue::copy() { eventvec_t::iterator i = events.begin(); eventvec_t::iterator end = events.end(); num_fds = 0; while (i < end) { if ((*i)->enabled) poll_fds[num_fds++] = (*i)->pfd; ++i; } } void PollQueue::remove(PollEvent *event) { eventvec_t::iterator i = events.begin(); eventvec_t::iterator end = events.end(); while (i < end) { if (*i == event) { events.erase(i); copy(); event->queue = NULL; return; } ++i; } panic("Event does not exist. Cannot remove."); } void PollQueue::schedule(PollEvent *event) { if (event->queue) panic("Event already scheduled!"); event->queue = this; events.push_back(event); setupAsyncIO(event->pfd.fd, true); // if we ran out of space in the fd array, double the capacity // if this is the first time that we've scheduled an event, create // the array with an initial size of 16 if (++num_fds > max_size) { if (max_size > 0) { delete [] poll_fds; max_size *= 2; } else { max_size = 16; setupHandler(); } poll_fds = new pollfd[max_size]; } copy(); } void PollQueue::service() { int ret = poll(poll_fds, num_fds, 0); if (ret <= 0) return; for (int i = 0; i < num_fds; i++) { int revents = poll_fds[i].revents; if (revents) { events[i]->process(revents); if (--ret <= 0) break; } } } struct sigaction PollQueue::oldio; struct sigaction PollQueue::oldalrm; bool PollQueue::handler = false; void PollQueue::setupAsyncIO(int fd, bool set) { int flags = fcntl(fd, F_GETFL); if (flags == -1) panic("Could not set up async IO"); if (set) flags |= FASYNC; else flags &= ~(FASYNC); if (fcntl(fd, F_SETFL, flags) == -1) panic("Could not set up async IO"); if (set) { if (fcntl(fd, F_SETOWN, getpid()) == -1) panic("Could not set up async IO"); } } void PollQueue::setupHandler() { struct sigaction act; act.sa_handler = handleIO; sigemptyset(&act.sa_mask); act.sa_flags = SA_RESTART; if (sigaction(SIGIO, &act, &oldio) == -1) panic("could not do sigaction"); act.sa_handler = handleALRM; sigemptyset(&act.sa_mask); act.sa_flags = SA_RESTART; if (sigaction(SIGALRM, &act, &oldalrm) == -1) panic("could not do sigaction"); alarm(1); handler = true; } void PollQueue::removeHandler() { if (sigaction(SIGIO, &oldio, NULL) == -1) panic("could not remove handler"); if (sigaction(SIGIO, &oldalrm, NULL) == -1) panic("could not remove handler"); } void PollQueue::handleIO(int sig) { if (sig != SIGIO) panic("Wrong Handler"); async_event = true; async_io = true; } void PollQueue::handleALRM(int sig) { if (sig != SIGALRM) panic("Wrong Handler"); async_event = true; async_alarm = true; alarm(1); }