Index: src/OFKernelEventObserver.h ================================================================== --- src/OFKernelEventObserver.h +++ src/OFKernelEventObserver.h @@ -90,11 +90,11 @@ /*! * @brief A class that can observe multiple kernel events (e.g. streams being * ready to read) at once. * - * @note Currently, Win32 can only observe TCP sockets! + * @note Currently, Win32 can only observe TCP and UDP sockets! */ @interface OFKernelEventObserver: OFObject { OFMutableArray *_readObjects; OFMutableArray *_writeObjects; @@ -188,20 +188,20 @@ /*! * @brief Observes all objects until an event happens on an object or the * timeout is reached. * * @param timeInterval The time to wait for an event, in seconds - * @return A boolean whether events occurred during the timeinterval + * @return A boolean whether events occurred before returning */ - (bool)observeForTimeInterval: (of_time_interval_t)timeInterval; /*! * @brief Observes all objects until an event happens on an object or the * specified date is reached. * * @param date The until which to observe - * @return A boolean whether events occurred until the specified date + * @return A boolean whether events occurred before returning */ - (bool)observeUntilDate: (OFDate*)date; /*! * @brief Cancels the currently blocking observe call. Index: src/OFKernelEventObserver.m ================================================================== --- src/OFKernelEventObserver.m +++ src/OFKernelEventObserver.m @@ -353,19 +353,19 @@ [self OF_addFileDescriptorForWriting: fd]; break; case QUEUE_REMOVE | QUEUE_READ: - [_readObjects removeObjectIdenticalTo: object]; - [self OF_removeFileDescriptorForReading: fd]; + + [_readObjects removeObjectIdenticalTo: object]; break; case QUEUE_REMOVE | QUEUE_WRITE: - [_writeObjects removeObjectIdenticalTo: object]; - [self OF_removeFileDescriptorForWriting: fd]; + + [_writeObjects removeObjectIdenticalTo: object]; break; default: assert(0); } Index: src/OFKernelEventObserver_kqueue.m ================================================================== --- src/OFKernelEventObserver_kqueue.m +++ src/OFKernelEventObserver_kqueue.m @@ -150,10 +150,34 @@ realEvents++; pool = objc_autoreleasePoolPush(); + /* + * If a file descriptor has been closed before it is removed + * from the kernel event observer, the file descriptor is not + * valid anymore and causes EBADF. As closing a file descriptor + * automatically removes it from the queue, there is nothing to + * do anymore. + * + * Ideally, a file descriptor should never be closed before it + * is removed from the kernel event observer, as in rare cases, + * it could result in removing the wrong object from the kernel + * event observer, for example if a file descriptor is closed, + * a new one created, added to the kernel event observer and + * then the old one removed, as the new one could now have the + * same file descriptor as the closed one had and thus the new + * one is removed. + * + * For other errors, call the callback like it was successful + * so that the read / write will generate an error and throw an + * exception. + */ + if ((eventList[i].flags & EV_ERROR) && + eventList[i].data == EBADF) + continue; + switch (eventList[i].filter) { case EVFILT_READ: if ([_delegate respondsToSelector: @selector(objectIsReadyForReading:)]) [_delegate objectIsReadyForReading: