@@ -1,8 +1,8 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 - * Jonathan Schleifer + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 + * Jonathan Schleifer * * 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 @@ -30,10 +30,13 @@ #import "OFKernelEventObserver.h" #import "OFKernelEventObserver+Private.h" #import "OFKernelEventObserver_kqueue.h" #import "OFDataArray.h" #import "OFArray.h" +#ifdef OF_HAVE_THREADS +# import "OFMutex.h" +#endif #import "OFInitializationFailedException.h" #import "OFObserveFailedException.h" #import "OFOutOfRangeException.h" @@ -60,16 +63,15 @@ if ((flags = fcntl(_kernelQueue, F_GETFD, 0)) != -1) fcntl(_kernelQueue, F_SETFD, flags | FD_CLOEXEC); #endif - _changeList = [[OFDataArray alloc] initWithItemSize: - sizeof(struct kevent)]; EV_SET(&event, _cancelFD[0], EVFILT_READ, EV_ADD, 0, 0, 0); - [_changeList addItem: &event]; - _removedArray = [[OFMutableArray alloc] init]; + if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0) + @throw [OFInitializationFailedException + exceptionWithClass: [self class]]; } @catch (id e) { [self release]; @throw e; } @@ -78,23 +80,17 @@ - (void)dealloc { close(_kernelQueue); - [_changeList release]; - [_removedArray release]; - [super dealloc]; } -- (void)OF_addObjectForReading: (id)object +- (void)OF_addObjectForReading: (id )object { struct kevent event; - if ([_changeList count] >= INT_MAX) - @throw [OFOutOfRangeException exception]; - memset(&event, 0, sizeof(event)); event.ident = [object fileDescriptorForReading]; event.filter = EVFILT_READ; event.flags = EV_ADD; #ifndef __NetBSD__ @@ -101,20 +97,19 @@ event.udata = object; #else event.udata = (intptr_t)object; #endif - [_changeList addItem: &event]; + if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0) + @throw [OFObserveFailedException exceptionWithObserver: self + errNo: errno]; } -- (void)OF_addObjectForWriting: (id)object +- (void)OF_addObjectForWriting: (id )object { struct kevent event; - if ([_changeList count] >= INT_MAX) - @throw [OFOutOfRangeException exception]; - memset(&event, 0, sizeof(event)); event.ident = [object fileDescriptorForWriting]; event.filter = EVFILT_WRITE; event.flags = EV_ADD; #ifndef __NetBSD__ @@ -121,67 +116,67 @@ event.udata = object; #else event.udata = (intptr_t)object; #endif - [_changeList addItem: &event]; + if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0) + @throw [OFObserveFailedException exceptionWithObserver: self + errNo: errno]; } -- (void)OF_removeObjectForReading: (id)object +- (void)OF_removeObjectForReading: (id )object { struct kevent event; memset(&event, 0, sizeof(event)); event.ident = [object fileDescriptorForReading]; event.filter = EVFILT_READ; event.flags = EV_DELETE; - [_changeList addItem: &event]; + + if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0) + @throw [OFObserveFailedException exceptionWithObserver: self + errNo: errno]; } -- (void)OF_removeObjectForWriting: (id)object +- (void)OF_removeObjectForWriting: (id )object { struct kevent event; memset(&event, 0, sizeof(event)); event.ident = [object fileDescriptorForWriting]; event.filter = EVFILT_WRITE; event.flags = EV_DELETE; - [_changeList addItem: &event]; + + if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0) + @throw [OFObserveFailedException exceptionWithObserver: self + errNo: errno]; } - (void)observeForTimeInterval: (of_time_interval_t)timeInterval { - void *pool = objc_autoreleasePoolPush(); struct timespec timeout; struct kevent eventList[EVENTLIST_SIZE]; int i, events; + + [self OF_processQueue]; + + if ([self OF_processReadBuffers]) + return; timeout.tv_sec = (time_t)timeInterval; timeout.tv_nsec = lrint((timeInterval - timeout.tv_sec) * 1000000000); - /* - * Make sure to keep the streams retained and thus the file descriptors - * valid until the actual change has been performed. - */ - [self OF_processQueueAndStoreRemovedIn: _removedArray]; - - [self OF_processReadBuffers]; - - objc_autoreleasePoolPop(pool); - - events = kevent(_kernelQueue, [_changeList items], - (int)[_changeList count], eventList, EVENTLIST_SIZE, + events = kevent(_kernelQueue, NULL, 0, eventList, EVENTLIST_SIZE, (timeInterval != -1 ? &timeout : NULL)); if (events < 0) @throw [OFObserveFailedException exceptionWithObserver: self errNo: errno]; - [_changeList removeAllItems]; - [_removedArray removeAllObjects]; - for (i = 0; i < events; i++) { + void *pool; + if (eventList[i].flags & EV_ERROR) @throw [OFObserveFailedException exceptionWithObserver: self errNo: (int)eventList[i].data];