/* * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 * Jonathan Schleifer <js@webkeks.org> * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #define __NO_EXT_QNX #include <unistd.h> #ifdef HAVE_POLL_H # include <poll.h> #endif #import "OFStreamObserver.h" #import "OFStreamObserver+Private.h" #import "OFStreamObserver_poll.h" #import "OFDataArray.h" #import "OFOutOfRangeException.h" #import "autorelease.h" #import "macros.h" #ifdef __wii__ # define BOOL OGC_BOOL # include <network.h> # undef BOOL # define poll(fds, nfds, timeout) net_poll(fds, nfds, timeout) # define pollfd pollsd # define fd socket typedef u32 nfds_t; #endif @implementation OFStreamObserver_poll - init { self = [super init]; @try { struct pollfd p = { 0, POLLIN, 0 }; _FDs = [[OFDataArray alloc] initWithItemSize: sizeof(struct pollfd)]; p.fd = _cancelFD[0]; [_FDs addItem: &p]; } @catch (id e) { [self release]; @throw e; } return self; } - (void)dealloc { [_FDs release]; [super dealloc]; } - (void)OF_addFileDescriptor: (int)fd withEvents: (short)events { struct pollfd *FDs = [_FDs items]; size_t i, count = [_FDs count]; bool found = false; for (i = 0; i < count; i++) { if (FDs[i].fd == fd) { FDs[i].events |= events; found = true; break; } } if (!found) { struct pollfd p = { fd, events | POLLERR, 0 }; [_FDs addItem: &p]; } } - (void)OF_removeFileDescriptor: (int)fd withEvents: (short)events { struct pollfd *FDs = [_FDs items]; size_t i, nFDs = [_FDs count]; for (i = 0; i < nFDs; i++) { if (FDs[i].fd == fd) { FDs[i].events &= ~events; if ((FDs[i].events & ~POLLERR) == 0) [_FDs removeItemAtIndex: i]; break; } } } - (void)OF_addFileDescriptorForReading: (int)fd { [self OF_addFileDescriptor: fd withEvents: POLLIN]; } - (void)OF_addFileDescriptorForWriting: (int)fd { [self OF_addFileDescriptor: fd withEvents: POLLOUT]; } - (void)OF_removeFileDescriptorForReading: (int)fd { [self OF_removeFileDescriptor: fd withEvents: POLLIN]; } - (void)OF_removeFileDescriptorForWriting: (int)fd { [self OF_removeFileDescriptor: fd withEvents: POLLOUT]; } - (bool)observeForTimeInterval: (double)timeInterval { void *pool = objc_autoreleasePoolPush(); struct pollfd *FDs; size_t i, nFDs, realEvents = 0; [self OF_processQueue]; if ([self OF_processCache]) { objc_autoreleasePoolPop(pool); return true; } objc_autoreleasePoolPop(pool); FDs = [_FDs items]; nFDs = [_FDs count]; #ifdef OPEN_MAX if (nFDs > OPEN_MAX) @throw [OFOutOfRangeException exception]; #endif if (poll(FDs, (nfds_t)nFDs, (int)(timeInterval != -1 ? timeInterval * 1000 : -1)) < 1) return false; for (i = 0; i < nFDs; i++) { pool = objc_autoreleasePoolPush(); if (FDs[i].revents & POLLIN) { if (FDs[i].fd == _cancelFD[0]) { char buffer; OF_ENSURE(read(_cancelFD[0], &buffer, 1) > 0); FDs[i].revents = 0; objc_autoreleasePoolPop(pool); continue; } if ([_delegate respondsToSelector: @selector(streamIsReadyForReading:)]) [_delegate streamIsReadyForReading: _FDToStream[FDs[i].fd]]; realEvents++; } if (FDs[i].revents & POLLOUT) { if ([_delegate respondsToSelector: @selector(streamIsReadyForWriting:)]) [_delegate streamIsReadyForWriting: _FDToStream[FDs[i].fd]]; realEvents++; } if (FDs[i].revents & POLLERR) { if ([_delegate respondsToSelector: @selector(streamDidReceiveException:)]) [_delegate streamDidReceiveException: _FDToStream[FDs[i].fd]]; realEvents++; } FDs[i].revents = 0; objc_autoreleasePoolPop(pool); } if (realEvents == 0) return false; return true; } @end