Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -41,10 +41,20 @@ 4B067FBE177BA6F900B8CFDA /* OFChangeOwnerFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B067FB2177BA6F900B8CFDA /* OFChangeOwnerFailedException.m */; }; 4B067FBF177BA6F900B8CFDA /* OFChangePermissionsFailedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B067FB3177BA6F900B8CFDA /* OFChangePermissionsFailedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B067FC0177BA6F900B8CFDA /* OFChangePermissionsFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B067FB4177BA6F900B8CFDA /* OFChangePermissionsFailedException.m */; }; 4B067FC1177BA6F900B8CFDA /* OFCreateSymbolicLinkFailedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B067FB5177BA6F900B8CFDA /* OFCreateSymbolicLinkFailedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B067FC2177BA6F900B8CFDA /* OFCreateSymbolicLinkFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B067FB6177BA6F900B8CFDA /* OFCreateSymbolicLinkFailedException.m */; }; + 4B0EA91B1898690E00F573A4 /* OFKernelEventObserver_kqueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B0EA9121898690E00F573A4 /* OFKernelEventObserver_kqueue.h */; }; + 4B0EA91C1898690E00F573A4 /* OFKernelEventObserver_kqueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B0EA9131898690E00F573A4 /* OFKernelEventObserver_kqueue.m */; }; + 4B0EA91D1898690E00F573A4 /* OFKernelEventObserver_poll.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B0EA9141898690E00F573A4 /* OFKernelEventObserver_poll.h */; }; + 4B0EA91E1898690E00F573A4 /* OFKernelEventObserver_poll.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B0EA9151898690E00F573A4 /* OFKernelEventObserver_poll.m */; }; + 4B0EA91F1898690E00F573A4 /* OFKernelEventObserver_select.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B0EA9161898690E00F573A4 /* OFKernelEventObserver_select.h */; }; + 4B0EA9201898690E00F573A4 /* OFKernelEventObserver_select.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B0EA9171898690E00F573A4 /* OFKernelEventObserver_select.m */; }; + 4B0EA9211898690E00F573A4 /* OFKernelEventObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B0EA9181898690E00F573A4 /* OFKernelEventObserver.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4B0EA9221898690E00F573A4 /* OFKernelEventObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B0EA9191898690E00F573A4 /* OFKernelEventObserver.m */; }; + 4B0EA9231898690E00F573A4 /* OFKernelEventObserver+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B0EA91A1898690E00F573A4 /* OFKernelEventObserver+Private.h */; }; + 4B0EA925189869D900F573A4 /* OFUDPSocketTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B0EA924189869D900F573A4 /* OFUDPSocketTests.m */; }; 4B11005C14329B9A003A45D8 /* OFXMLNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B11005A14329B9A003A45D8 /* OFXMLNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B11005D14329B9A003A45D8 /* OFXMLNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B11005B14329B9A003A45D8 /* OFXMLNode.m */; }; 4B141BA415FCDF74000C21A8 /* OFSortedList.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B141BA215FCDF74000C21A8 /* OFSortedList.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B141BA515FCDF74000C21A8 /* OFSortedList.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B141BA315FCDF74000C21A8 /* OFSortedList.m */; }; 4B1473CB17E6391900B46BB8 /* OFAutoreleasePool+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B1473CA17E6391900B46BB8 /* OFAutoreleasePool+Private.h */; }; @@ -159,11 +169,10 @@ 4B3D239F1337FC0D00DD29B8 /* OFObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B6799781099E7C50041064A /* OFObject.m */; }; 4B3D23A01337FC0D00DD29B8 /* OFPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B67997A1099E7C50041064A /* OFPlugin.m */; }; 4B3D23A11337FC0D00DD29B8 /* OFSeekableStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B981CDF116F71DD00294DB7 /* OFSeekableStream.m */; }; 4B3D23A21337FC0D00DD29B8 /* OFSHA1Hash.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF1BCC511C9663F0025511F /* OFSHA1Hash.m */; }; 4B3D23A31337FC0D00DD29B8 /* OFStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B67997E1099E7C50041064A /* OFStream.m */; }; - 4B3D23A41337FC0D00DD29B8 /* OFStreamObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BAF5F48123460C900F4E111 /* OFStreamObserver.m */; }; 4B3D23A51337FC0D00DD29B8 /* OFStreamSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BAF5F4A123460C900F4E111 /* OFStreamSocket.m */; }; 4B3D23A61337FC0D00DD29B8 /* OFString.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B6799801099E7C50041064A /* OFString.m */; }; 4B3D23A71337FC0D00DD29B8 /* OFString+Hashing.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF1BCC711C9663F0025511F /* OFString+Hashing.m */; }; 4B3D23A81337FC0D00DD29B8 /* OFString+URLEncoding.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF1BCC911C9663F0025511F /* OFString+URLEncoding.m */; }; 4B3D23A91337FC0D00DD29B8 /* OFString+XMLEscaping.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF1BCCB11C9663F0025511F /* OFString+XMLEscaping.m */; }; @@ -203,11 +212,10 @@ 4B3D23D11337FCB000DD29B8 /* OFObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B6799771099E7C50041064A /* OFObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B3D23D21337FCB000DD29B8 /* OFPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B6799791099E7C50041064A /* OFPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B3D23D31337FCB000DD29B8 /* OFSeekableStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B981CDE116F71DD00294DB7 /* OFSeekableStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B3D23D41337FCB000DD29B8 /* OFSHA1Hash.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF1BCC411C9663F0025511F /* OFSHA1Hash.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B3D23D51337FCB000DD29B8 /* OFStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B67997D1099E7C50041064A /* OFStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4B3D23D61337FCB000DD29B8 /* OFStreamObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BAF5F47123460C900F4E111 /* OFStreamObserver.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B3D23D71337FCB000DD29B8 /* OFStreamSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BAF5F49123460C900F4E111 /* OFStreamSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B3D23D81337FCB000DD29B8 /* OFString.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B67997F1099E7C50041064A /* OFString.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B3D23D91337FCB000DD29B8 /* OFString+Hashing.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF1BCC611C9663F0025511F /* OFString+Hashing.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B3D23DA1337FCB000DD29B8 /* OFString+URLEncoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF1BCC811C9663F0025511F /* OFString+URLEncoding.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B3D23DB1337FCB000DD29B8 /* OFString+XMLEscaping.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BF1BCCA11C9663F0025511F /* OFString+XMLEscaping.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -264,14 +272,10 @@ 4B5C112F17E9AB3E003C917F /* forwarding.S in Sources */ = {isa = PBXBuildFile; fileRef = 4B5C112C17E9AAED003C917F /* forwarding.S */; }; 4B5CF8F914940BD2007AA324 /* OFString+JSONValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B5CF8F614940BD2007AA324 /* OFString+JSONValue.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B5CF8FA14940BD2007AA324 /* OFString+JSONValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B5CF8F714940BD2007AA324 /* OFString+JSONValue.m */; }; 4B62ED1518566FCA0004E0E3 /* OFCopyItemFailedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B62ED1318566FCA0004E0E3 /* OFCopyItemFailedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B62ED1618566FCA0004E0E3 /* OFCopyItemFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B62ED1418566FCA0004E0E3 /* OFCopyItemFailedException.m */; }; - 4B64D6EF1425381E007BDFB1 /* OFStreamObserver_poll.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B64D6EB1425381E007BDFB1 /* OFStreamObserver_poll.h */; }; - 4B64D6F01425381E007BDFB1 /* OFStreamObserver_poll.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B64D6EC1425381E007BDFB1 /* OFStreamObserver_poll.m */; }; - 4B64D6F11425381E007BDFB1 /* OFStreamObserver_select.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B64D6ED1425381E007BDFB1 /* OFStreamObserver_select.h */; }; - 4B64D6F21425381E007BDFB1 /* OFStreamObserver_select.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B64D6EE1425381E007BDFB1 /* OFStreamObserver_select.m */; }; 4B66B636182ADC45000A69E3 /* OFDeflate64Stream.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B66B634182ADC45000A69E3 /* OFDeflate64Stream.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B66B637182ADC45000A69E3 /* OFDeflate64Stream.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B66B635182ADC45000A69E3 /* OFDeflate64Stream.m */; }; 4B6743F1163C384A00EB1E59 /* OFLockFailedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B6743EB163C384A00EB1E59 /* OFLockFailedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B6743F2163C384A00EB1E59 /* OFLockFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B6743EC163C384A00EB1E59 /* OFLockFailedException.m */; }; 4B6743F3163C384A00EB1E59 /* OFStillLockedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B6743ED163C384A00EB1E59 /* OFStillLockedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -285,11 +289,10 @@ 4B674404163C395900EB1E59 /* OFMutex.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B6743FB163C395900EB1E59 /* OFMutex.m */; }; 4B674405163C395900EB1E59 /* OFRecursiveMutex.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B6743FC163C395900EB1E59 /* OFRecursiveMutex.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B674406163C395900EB1E59 /* OFRecursiveMutex.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B6743FD163C395900EB1E59 /* OFRecursiveMutex.m */; }; 4B6C8AD817BD5C2E00B194F2 /* OFRunLoop+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B6C8AD117BD5C2E00B194F2 /* OFRunLoop+Private.h */; }; 4B6C8AD917BD5C2E00B194F2 /* OFStream+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B6C8AD217BD5C2E00B194F2 /* OFStream+Private.h */; }; - 4B6C8ADA17BD5C2E00B194F2 /* OFStreamObserver+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B6C8AD317BD5C2E00B194F2 /* OFStreamObserver+Private.h */; }; 4B6C8ADB17BD5C2E00B194F2 /* OFString_UTF8+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B6C8AD417BD5C2E00B194F2 /* OFString_UTF8+Private.h */; }; 4B6C8ADC17BD5C2E00B194F2 /* OFThread+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B6C8AD517BD5C2E00B194F2 /* OFThread+Private.h */; }; 4B6C8ADD17BD5C2E00B194F2 /* OFTimer+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B6C8AD617BD5C2E00B194F2 /* OFTimer+Private.h */; }; 4B6C8ADE17BD5C2E00B194F2 /* OFZIPArchiveEntry+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B6C8AD717BD5C2E00B194F2 /* OFZIPArchiveEntry+Private.h */; }; 4B7161AD17A6FC7600B74970 /* OFHTTPResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B7161AB17A6FC7600B74970 /* OFHTTPResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -306,12 +309,10 @@ 4B7DD58818943D4A00990FD6 /* socket.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B7DD58718943D4A00990FD6 /* socket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B7FF3B4133CED6200000324 /* OFConditionStillWaitingException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B7FF3B2133CED6100000324 /* OFConditionStillWaitingException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B7FF3B5133CED6200000324 /* OFConditionStillWaitingException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7FF3B3133CED6100000324 /* OFConditionStillWaitingException.m */; }; 4B837D7916829C5F007A3E83 /* block.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B837D7716829C5F007A3E83 /* block.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B837D7A16829C5F007A3E83 /* instance.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B837D7816829C5F007A3E83 /* instance.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4B83F0F4142FDEFD00E4A821 /* OFStreamObserver_kqueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B83F0F2142FDEFD00E4A821 /* OFStreamObserver_kqueue.h */; }; - 4B83F0F5142FDEFD00E4A821 /* OFStreamObserver_kqueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B83F0F3142FDEFD00E4A821 /* OFStreamObserver_kqueue.m */; }; 4B86E7CB17F8B98200ACA680 /* OFDeflateStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B86E7C917F8B98200ACA680 /* OFDeflateStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B86E7CC17F8B98200ACA680 /* OFDeflateStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B86E7CA17F8B98200ACA680 /* OFDeflateStream.m */; }; 4B879A8C177231F000EBCEA4 /* OFDataArray+MessagePackValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B879A89177231F000EBCEA4 /* OFDataArray+MessagePackValue.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B879A8D177231F000EBCEA4 /* OFDataArray+MessagePackValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B879A8A177231F000EBCEA4 /* OFDataArray+MessagePackValue.m */; }; 4B879A8E177231F000EBCEA4 /* OFMessagePackRepresentation.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B879A8B177231F000EBCEA4 /* OFMessagePackRepresentation.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -497,10 +498,20 @@ 4B067FB4177BA6F900B8CFDA /* OFChangePermissionsFailedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFChangePermissionsFailedException.m; path = src/exceptions/OFChangePermissionsFailedException.m; sourceTree = ""; }; 4B067FB5177BA6F900B8CFDA /* OFCreateSymbolicLinkFailedException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFCreateSymbolicLinkFailedException.h; path = src/exceptions/OFCreateSymbolicLinkFailedException.h; sourceTree = ""; }; 4B067FB6177BA6F900B8CFDA /* OFCreateSymbolicLinkFailedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFCreateSymbolicLinkFailedException.m; path = src/exceptions/OFCreateSymbolicLinkFailedException.m; sourceTree = ""; }; 4B0D249411DFAA3D00ED6FFC /* OFXMLElementBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFXMLElementBuilder.h; path = src/OFXMLElementBuilder.h; sourceTree = ""; }; 4B0D249511DFAA3D00ED6FFC /* OFXMLElementBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFXMLElementBuilder.m; path = src/OFXMLElementBuilder.m; sourceTree = ""; }; + 4B0EA9121898690E00F573A4 /* OFKernelEventObserver_kqueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFKernelEventObserver_kqueue.h; path = src/OFKernelEventObserver_kqueue.h; sourceTree = ""; }; + 4B0EA9131898690E00F573A4 /* OFKernelEventObserver_kqueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFKernelEventObserver_kqueue.m; path = src/OFKernelEventObserver_kqueue.m; sourceTree = ""; }; + 4B0EA9141898690E00F573A4 /* OFKernelEventObserver_poll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFKernelEventObserver_poll.h; path = src/OFKernelEventObserver_poll.h; sourceTree = ""; }; + 4B0EA9151898690E00F573A4 /* OFKernelEventObserver_poll.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFKernelEventObserver_poll.m; path = src/OFKernelEventObserver_poll.m; sourceTree = ""; }; + 4B0EA9161898690E00F573A4 /* OFKernelEventObserver_select.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFKernelEventObserver_select.h; path = src/OFKernelEventObserver_select.h; sourceTree = ""; }; + 4B0EA9171898690E00F573A4 /* OFKernelEventObserver_select.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFKernelEventObserver_select.m; path = src/OFKernelEventObserver_select.m; sourceTree = ""; }; + 4B0EA9181898690E00F573A4 /* OFKernelEventObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFKernelEventObserver.h; path = src/OFKernelEventObserver.h; sourceTree = ""; }; + 4B0EA9191898690E00F573A4 /* OFKernelEventObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFKernelEventObserver.m; path = src/OFKernelEventObserver.m; sourceTree = ""; }; + 4B0EA91A1898690E00F573A4 /* OFKernelEventObserver+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFKernelEventObserver+Private.h"; path = "src/OFKernelEventObserver+Private.h"; sourceTree = ""; }; + 4B0EA924189869D900F573A4 /* OFUDPSocketTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFUDPSocketTests.m; path = tests/OFUDPSocketTests.m; sourceTree = ""; }; 4B11005A14329B9A003A45D8 /* OFXMLNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFXMLNode.h; path = src/OFXMLNode.h; sourceTree = ""; }; 4B11005B14329B9A003A45D8 /* OFXMLNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFXMLNode.m; path = src/OFXMLNode.m; sourceTree = ""; }; 4B141BA215FCDF74000C21A8 /* OFSortedList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFSortedList.h; path = src/OFSortedList.h; sourceTree = ""; }; 4B141BA315FCDF74000C21A8 /* OFSortedList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFSortedList.m; path = src/OFSortedList.m; sourceTree = ""; }; 4B1473CA17E6391900B46BB8 /* OFAutoreleasePool+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFAutoreleasePool+Private.h"; path = "src/OFAutoreleasePool+Private.h"; sourceTree = ""; }; @@ -643,14 +654,10 @@ 4B5C112E17E9AB0C003C917F /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; name = Makefile; path = src/forwarding/Makefile; sourceTree = ""; }; 4B5CF8F614940BD2007AA324 /* OFString+JSONValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFString+JSONValue.h"; path = "src/OFString+JSONValue.h"; sourceTree = ""; }; 4B5CF8F714940BD2007AA324 /* OFString+JSONValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OFString+JSONValue.m"; path = "src/OFString+JSONValue.m"; sourceTree = ""; }; 4B62ED1318566FCA0004E0E3 /* OFCopyItemFailedException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFCopyItemFailedException.h; path = src/exceptions/OFCopyItemFailedException.h; sourceTree = ""; }; 4B62ED1418566FCA0004E0E3 /* OFCopyItemFailedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFCopyItemFailedException.m; path = src/exceptions/OFCopyItemFailedException.m; sourceTree = ""; }; - 4B64D6EB1425381E007BDFB1 /* OFStreamObserver_poll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFStreamObserver_poll.h; path = src/OFStreamObserver_poll.h; sourceTree = ""; }; - 4B64D6EC1425381E007BDFB1 /* OFStreamObserver_poll.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFStreamObserver_poll.m; path = src/OFStreamObserver_poll.m; sourceTree = ""; }; - 4B64D6ED1425381E007BDFB1 /* OFStreamObserver_select.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFStreamObserver_select.h; path = src/OFStreamObserver_select.h; sourceTree = ""; }; - 4B64D6EE1425381E007BDFB1 /* OFStreamObserver_select.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFStreamObserver_select.m; path = src/OFStreamObserver_select.m; sourceTree = ""; }; 4B66B634182ADC45000A69E3 /* OFDeflate64Stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFDeflate64Stream.h; path = src/OFDeflate64Stream.h; sourceTree = ""; }; 4B66B635182ADC45000A69E3 /* OFDeflate64Stream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFDeflate64Stream.m; path = src/OFDeflate64Stream.m; sourceTree = ""; }; 4B6743EB163C384A00EB1E59 /* OFLockFailedException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFLockFailedException.h; path = src/exceptions/OFLockFailedException.h; sourceTree = ""; }; 4B6743EC163C384A00EB1E59 /* OFLockFailedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFLockFailedException.m; path = src/exceptions/OFLockFailedException.m; sourceTree = ""; }; 4B6743ED163C384A00EB1E59 /* OFStillLockedException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFStillLockedException.h; path = src/exceptions/OFStillLockedException.h; sourceTree = ""; }; @@ -707,11 +714,10 @@ 4B6AF96F10A8D40E0003FB0A /* iso_8859_15.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = iso_8859_15.m; path = src/iso_8859_15.m; sourceTree = ""; }; 4B6AF97210A8D42E0003FB0A /* windows_1252.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = windows_1252.m; path = src/windows_1252.m; sourceTree = ""; }; 4B6AF97310A8D4450003FB0A /* ObjFW.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjFW.h; path = src/ObjFW.h; sourceTree = ""; }; 4B6C8AD117BD5C2E00B194F2 /* OFRunLoop+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFRunLoop+Private.h"; path = "src/OFRunLoop+Private.h"; sourceTree = ""; }; 4B6C8AD217BD5C2E00B194F2 /* OFStream+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFStream+Private.h"; path = "src/OFStream+Private.h"; sourceTree = ""; }; - 4B6C8AD317BD5C2E00B194F2 /* OFStreamObserver+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFStreamObserver+Private.h"; path = "src/OFStreamObserver+Private.h"; sourceTree = ""; }; 4B6C8AD417BD5C2E00B194F2 /* OFString_UTF8+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFString_UTF8+Private.h"; path = "src/OFString_UTF8+Private.h"; sourceTree = ""; }; 4B6C8AD517BD5C2E00B194F2 /* OFThread+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFThread+Private.h"; path = "src/OFThread+Private.h"; sourceTree = ""; }; 4B6C8AD617BD5C2E00B194F2 /* OFTimer+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFTimer+Private.h"; path = "src/OFTimer+Private.h"; sourceTree = ""; }; 4B6C8AD717BD5C2E00B194F2 /* OFZIPArchiveEntry+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFZIPArchiveEntry+Private.h"; path = "src/OFZIPArchiveEntry+Private.h"; sourceTree = ""; }; 4B6EF66E1235358D0076B512 /* OFArrayTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFArrayTests.m; path = tests/OFArrayTests.m; sourceTree = SOURCE_ROOT; }; @@ -749,12 +755,10 @@ 4B7DD58918944A7900990FD6 /* apple-forwarding-arm64.S */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; name = "apple-forwarding-arm64.S"; path = "src/forwarding/apple-forwarding-arm64.S"; sourceTree = ""; }; 4B7FF3B2133CED6100000324 /* OFConditionStillWaitingException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFConditionStillWaitingException.h; path = src/exceptions/OFConditionStillWaitingException.h; sourceTree = ""; }; 4B7FF3B3133CED6100000324 /* OFConditionStillWaitingException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFConditionStillWaitingException.m; path = src/exceptions/OFConditionStillWaitingException.m; sourceTree = ""; }; 4B837D7716829C5F007A3E83 /* block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = block.h; path = src/block.h; sourceTree = ""; }; 4B837D7816829C5F007A3E83 /* instance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = instance.h; path = src/instance.h; sourceTree = ""; }; - 4B83F0F2142FDEFD00E4A821 /* OFStreamObserver_kqueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFStreamObserver_kqueue.h; path = src/OFStreamObserver_kqueue.h; sourceTree = ""; }; - 4B83F0F3142FDEFD00E4A821 /* OFStreamObserver_kqueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFStreamObserver_kqueue.m; path = src/OFStreamObserver_kqueue.m; sourceTree = ""; }; 4B86E7C917F8B98200ACA680 /* OFDeflateStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFDeflateStream.h; path = src/OFDeflateStream.h; sourceTree = ""; }; 4B86E7CA17F8B98200ACA680 /* OFDeflateStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFDeflateStream.m; path = src/OFDeflateStream.m; sourceTree = ""; }; 4B879A89177231F000EBCEA4 /* OFDataArray+MessagePackValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFDataArray+MessagePackValue.h"; path = "src/OFDataArray+MessagePackValue.h"; sourceTree = ""; }; 4B879A8A177231F000EBCEA4 /* OFDataArray+MessagePackValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OFDataArray+MessagePackValue.m"; path = "src/OFDataArray+MessagePackValue.m"; sourceTree = ""; }; 4B879A8B177231F000EBCEA4 /* OFMessagePackRepresentation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFMessagePackRepresentation.h; path = src/OFMessagePackRepresentation.h; sourceTree = ""; }; @@ -812,12 +816,10 @@ 4BA85BC9140ECCE800E91D51 /* OFSet_hashtable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFSet_hashtable.m; path = src/OFSet_hashtable.m; sourceTree = ""; }; 4BA9CFA315E129D30076DC74 /* autorelease.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = autorelease.h; path = src/autorelease.h; sourceTree = ""; }; 4BAA60C714D09699006F068D /* OFJSONTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFJSONTests.m; path = tests/OFJSONTests.m; sourceTree = ""; }; 4BAE7353139C507F00F682ED /* serialization.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = serialization.xml; path = tests/serialization.xml; sourceTree = ""; }; 4BAF5F46123460C900F4E111 /* OFCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFCollection.h; path = src/OFCollection.h; sourceTree = ""; }; - 4BAF5F47123460C900F4E111 /* OFStreamObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFStreamObserver.h; path = src/OFStreamObserver.h; sourceTree = ""; }; - 4BAF5F48123460C900F4E111 /* OFStreamObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFStreamObserver.m; path = src/OFStreamObserver.m; sourceTree = ""; }; 4BAF5F49123460C900F4E111 /* OFStreamSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFStreamSocket.h; path = src/OFStreamSocket.h; sourceTree = ""; }; 4BAF5F4A123460C900F4E111 /* OFStreamSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFStreamSocket.m; path = src/OFStreamSocket.m; sourceTree = ""; }; 4BAFC166182EAA7800BE5E57 /* OFOptionsParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFOptionsParser.h; path = src/OFOptionsParser.h; sourceTree = ""; }; 4BAFC167182EAA7800BE5E57 /* OFOptionsParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFOptionsParser.m; path = src/OFOptionsParser.m; sourceTree = ""; }; 4BB25E82139C388A00F574EA /* OFObject+Serialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFObject+Serialization.h"; path = "src/OFObject+Serialization.h"; sourceTree = ""; }; @@ -1206,10 +1208,19 @@ 4BB4B54116775FF4002A2DCE /* OFHTTPServer.h */, 4BB4B54216775FF4002A2DCE /* OFHTTPServer.m */, 4BA49D8E13DB113B00381CDB /* OFIntrospection.h */, 4BA49D8F13DB113B00381CDB /* OFIntrospection.m */, 4BA02B9F15041F5900002F84 /* OFJSONRepresentation.h */, + 4B0EA9181898690E00F573A4 /* OFKernelEventObserver.h */, + 4B0EA9191898690E00F573A4 /* OFKernelEventObserver.m */, + 4B0EA91A1898690E00F573A4 /* OFKernelEventObserver+Private.h */, + 4B0EA9121898690E00F573A4 /* OFKernelEventObserver_kqueue.h */, + 4B0EA9131898690E00F573A4 /* OFKernelEventObserver_kqueue.m */, + 4B0EA9141898690E00F573A4 /* OFKernelEventObserver_poll.h */, + 4B0EA9151898690E00F573A4 /* OFKernelEventObserver_poll.m */, + 4B0EA9161898690E00F573A4 /* OFKernelEventObserver_select.h */, + 4B0EA9171898690E00F573A4 /* OFKernelEventObserver_select.m */, 4B67996C1099E7C50041064A /* OFList.h */, 4B67996D1099E7C50041064A /* OFList.m */, 4B6743F9163C395900EB1E59 /* OFLocking.h */, 4B3B0796166978780044E634 /* OFMapTable.h */, 4B3B0797166978780044E634 /* OFMapTable.m */, @@ -1270,19 +1281,10 @@ 4B0256E2172B60400062B5F1 /* OFStdIOStream.h */, 4B0256E3172B60400062B5F1 /* OFStdIOStream.m */, 4B67997D1099E7C50041064A /* OFStream.h */, 4B67997E1099E7C50041064A /* OFStream.m */, 4B6C8AD217BD5C2E00B194F2 /* OFStream+Private.h */, - 4BAF5F47123460C900F4E111 /* OFStreamObserver.h */, - 4BAF5F48123460C900F4E111 /* OFStreamObserver.m */, - 4B6C8AD317BD5C2E00B194F2 /* OFStreamObserver+Private.h */, - 4B83F0F2142FDEFD00E4A821 /* OFStreamObserver_kqueue.h */, - 4B83F0F3142FDEFD00E4A821 /* OFStreamObserver_kqueue.m */, - 4B64D6EB1425381E007BDFB1 /* OFStreamObserver_poll.h */, - 4B64D6EC1425381E007BDFB1 /* OFStreamObserver_poll.m */, - 4B64D6ED1425381E007BDFB1 /* OFStreamObserver_select.h */, - 4B64D6EE1425381E007BDFB1 /* OFStreamObserver_select.m */, 4BAF5F49123460C900F4E111 /* OFStreamSocket.h */, 4BAF5F4A123460C900F4E111 /* OFStreamSocket.m */, 4B67997F1099E7C50041064A /* OFString.h */, 4B6799801099E7C50041064A /* OFString.m */, 4BF1BCC611C9663F0025511F /* OFString+Hashing.h */, @@ -1398,10 +1400,11 @@ 4B6EF6771235358D0076B512 /* OFSHA1HashTests.m */, 4B6EF6781235358D0076B512 /* OFStreamTests.m */, 4B6EF6791235358D0076B512 /* OFStringTests.m */, 4B6EF67A1235358D0076B512 /* OFTCPSocketTests.m */, 4B6EF67B1235358D0076B512 /* OFThreadTests.m */, + 4B0EA924189869D900F573A4 /* OFUDPSocketTests.m */, 4BF0749512DFAFCA00A4ADD1 /* OFURLTests.m */, 4B6EF67C1235358D0076B512 /* OFXMLElementBuilderTests.m */, 4B49EA65143B39CE0005BBC6 /* OFXMLNodeTests.m */, 4B6EF67E1235358D0076B512 /* OFXMLParserTests.m */, 4B6EF67F1235358D0076B512 /* PropertiesTests.m */, @@ -1505,10 +1508,11 @@ 4B3D23CA1337FCB000DD29B8 /* OFHTTPRequest.h in Headers */, 4B7161AD17A6FC7600B74970 /* OFHTTPResponse.h in Headers */, 4BB4B54616775FF4002A2DCE /* OFHTTPServer.h in Headers */, 4BA49D9013DB113B00381CDB /* OFIntrospection.h in Headers */, 4BA02BA115041F5900002F84 /* OFJSONRepresentation.h in Headers */, + 4B0EA9211898690E00F573A4 /* OFKernelEventObserver.h in Headers */, 4B3D23CB1337FCB000DD29B8 /* OFList.h in Headers */, 4B674402163C395900EB1E59 /* OFLocking.h in Headers */, 4B3B0798166978780044E634 /* OFMapTable.h in Headers */, 4B3D23CC1337FCB000DD29B8 /* OFMD5Hash.h in Headers */, 4BCAA9AF1772432F003EF859 /* OFMessagePackExtension.h in Headers */, @@ -1532,11 +1536,10 @@ 4B39844213D3A24600E6F825 /* OFSet.h in Headers */, 4B3D23D41337FCB000DD29B8 /* OFSHA1Hash.h in Headers */, 4B141BA415FCDF74000C21A8 /* OFSortedList.h in Headers */, 4B0256E4172B60400062B5F1 /* OFStdIOStream.h in Headers */, 4B3D23D51337FCB000DD29B8 /* OFStream.h in Headers */, - 4B3D23D61337FCB000DD29B8 /* OFStreamObserver.h in Headers */, 4B3D23D71337FCB000DD29B8 /* OFStreamSocket.h in Headers */, 4B3D23D81337FCB000DD29B8 /* OFString.h in Headers */, 4B3D23D91337FCB000DD29B8 /* OFString+Hashing.h in Headers */, 4B5CF8F914940BD2007AA324 /* OFString+JSONValue.h in Headers */, 4BB25E8A139C388A00F574EA /* OFString+Serialization.h in Headers */, @@ -1635,22 +1638,22 @@ 4B2B3E7D140D430500EC2F7C /* OFArray_adjacent.h in Headers */, 4B9BB7BD141CDE2D000AD1CC /* OFArray_adjacentSubarray.h in Headers */, 4B1473CB17E6391900B46BB8 /* OFAutoreleasePool+Private.h in Headers */, 4BA85BCA140ECCE800E91D51 /* OFCountedSet_hashtable.h in Headers */, 4B2B3E7F140D430500EC2F7C /* OFDictionary_hashtable.h in Headers */, + 4B0EA9231898690E00F573A4 /* OFKernelEventObserver+Private.h in Headers */, + 4B0EA91B1898690E00F573A4 /* OFKernelEventObserver_kqueue.h in Headers */, + 4B0EA91D1898690E00F573A4 /* OFKernelEventObserver_poll.h in Headers */, + 4B0EA91F1898690E00F573A4 /* OFKernelEventObserver_select.h in Headers */, 4BC1C3EB184B5EB200BBF50F /* OFMapTable+Private.h in Headers */, 4B2B3E81140D430500EC2F7C /* OFMutableArray_adjacent.h in Headers */, 4B2B3E83140D430500EC2F7C /* OFMutableDictionary_hashtable.h in Headers */, 4BA85BCC140ECCE800E91D51 /* OFMutableSet_hashtable.h in Headers */, 4B552552147AA5DB0003BF47 /* OFMutableString_UTF8.h in Headers */, 4B6C8AD817BD5C2E00B194F2 /* OFRunLoop+Private.h in Headers */, 4BA85BCE140ECCE800E91D51 /* OFSet_hashtable.h in Headers */, 4B6C8AD917BD5C2E00B194F2 /* OFStream+Private.h in Headers */, - 4B6C8ADA17BD5C2E00B194F2 /* OFStreamObserver+Private.h in Headers */, - 4B83F0F4142FDEFD00E4A821 /* OFStreamObserver_kqueue.h in Headers */, - 4B64D6EF1425381E007BDFB1 /* OFStreamObserver_poll.h in Headers */, - 4B64D6F11425381E007BDFB1 /* OFStreamObserver_select.h in Headers */, 4B552554147AA5DB0003BF47 /* OFString_UTF8.h in Headers */, 4B6C8ADB17BD5C2E00B194F2 /* OFString_UTF8+Private.h in Headers */, 4BD653C5143B8489006182F0 /* OFTCPSocket+SOCKS5.h in Headers */, 4B6C8ADC17BD5C2E00B194F2 /* OFThread+Private.h in Headers */, 4B6C8ADD17BD5C2E00B194F2 /* OFTimer+Private.h in Headers */, @@ -1874,10 +1877,14 @@ 4BB4B54516775FF4002A2DCE /* OFHTTPClient.m in Sources */, 4B3D23981337FC0D00DD29B8 /* OFHTTPRequest.m in Sources */, 4B7161AE17A6FC7600B74970 /* OFHTTPResponse.m in Sources */, 4BB4B54716775FF4002A2DCE /* OFHTTPServer.m in Sources */, 4BA49D9113DB113B00381CDB /* OFIntrospection.m in Sources */, + 4B0EA9221898690E00F573A4 /* OFKernelEventObserver.m in Sources */, + 4B0EA91C1898690E00F573A4 /* OFKernelEventObserver_kqueue.m in Sources */, + 4B0EA91E1898690E00F573A4 /* OFKernelEventObserver_poll.m in Sources */, + 4B0EA9201898690E00F573A4 /* OFKernelEventObserver_select.m in Sources */, 4B3D23991337FC0D00DD29B8 /* OFList.m in Sources */, 4B3B0799166978780044E634 /* OFMapTable.m in Sources */, 4B3D239A1337FC0D00DD29B8 /* OFMD5Hash.m in Sources */, 4BCAA9B01772432F003EF859 /* OFMessagePackExtension.m in Sources */, 4B3D239B1337FC0D00DD29B8 /* OFMutableArray.m in Sources */, @@ -1903,14 +1910,10 @@ 4BA85BCF140ECCE800E91D51 /* OFSet_hashtable.m in Sources */, 4B3D23A21337FC0D00DD29B8 /* OFSHA1Hash.m in Sources */, 4B141BA515FCDF74000C21A8 /* OFSortedList.m in Sources */, 4B0256E5172B60400062B5F1 /* OFStdIOStream.m in Sources */, 4B3D23A31337FC0D00DD29B8 /* OFStream.m in Sources */, - 4B3D23A41337FC0D00DD29B8 /* OFStreamObserver.m in Sources */, - 4B83F0F5142FDEFD00E4A821 /* OFStreamObserver_kqueue.m in Sources */, - 4B64D6F01425381E007BDFB1 /* OFStreamObserver_poll.m in Sources */, - 4B64D6F21425381E007BDFB1 /* OFStreamObserver_select.m in Sources */, 4B3D23A51337FC0D00DD29B8 /* OFStreamSocket.m in Sources */, 4B3D23A61337FC0D00DD29B8 /* OFString.m in Sources */, 4B3D23A71337FC0D00DD29B8 /* OFString+Hashing.m in Sources */, 4B5CF8FA14940BD2007AA324 /* OFString+JSONValue.m in Sources */, 4BB25E8B139C388A00F574EA /* OFString+Serialization.m in Sources */, @@ -2027,10 +2030,11 @@ 4BF33B08133807A20059CEF7 /* OFSHA1HashTests.m in Sources */, 4BF33B09133807A20059CEF7 /* OFStreamTests.m in Sources */, 4BF33B0A133807A20059CEF7 /* OFStringTests.m in Sources */, 4BF33B0B133807A20059CEF7 /* OFTCPSocketTests.m in Sources */, 4BF33B0C133807A20059CEF7 /* OFThreadTests.m in Sources */, + 4B0EA925189869D900F573A4 /* OFUDPSocketTests.m in Sources */, 4BF33B0D133807A20059CEF7 /* OFURLTests.m in Sources */, 4BF33B0E133807A20059CEF7 /* OFXMLElementBuilderTests.m in Sources */, 4B49EA66143B39CE0005BBC6 /* OFXMLNodeTests.m in Sources */, 4BF33B10133807A20059CEF7 /* OFXMLParserTests.m in Sources */, 4BF33B11133807A20059CEF7 /* PropertiesTests.m in Sources */, Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -632,30 +632,34 @@ ]) AC_CHECK_HEADERS([netinet/in.h arpa/inet.h netdb.h]) AC_CHECK_FUNC(kqueue, [ AC_DEFINE(HAVE_KQUEUE, 1, [Whether we have kqueue]) - AC_SUBST(OFSTREAMOBSERVER_KQUEUE_M, "OFStreamObserver_kqueue.m") + AC_SUBST(OFKERNELEVENTOBSERVER_KQUEUE_M, + "OFKernelEventObserver_kqueue.m") ]) AC_CHECK_HEADER(poll.h, [ AC_DEFINE(HAVE_POLL_H, 1, [Whether we have poll.h]) - AC_SUBST(OFSTREAMOBSERVER_POLL_M, "OFStreamObserver_poll.m") + AC_SUBST(OFKERNELEVENTOBSERVER_POLL_M, + "OFKernelEventObserver_poll.m") ]) AC_CHECK_HEADER(sys/select.h, [ AC_DEFINE(HAVE_SYS_SELECT_H, 1, [Whether we have sys/select.h]) - AC_SUBST(OFSTREAMOBSERVER_SELECT_M, "OFStreamObserver_select.m") + AC_SUBST(OFKERNELEVENTOBSERVER_SELECT_M, + "OFKernelEventObserver_select.m") ]) case "$host_os" in mingw*) - AC_SUBST(OFSTREAMOBSERVER_SELECT_M, - "OFStreamObserver_select.m") + AC_SUBST(OFKERNELEVENTOBSERVER_SELECT_M, + "OFKernelEventObserver_select.m") ;; esac AS_IF([test x"$with_wii" = x"yes"], [ - AC_SUBST(OFSTREAMOBSERVER_POLL_M, "OFStreamObserver_poll.m") + AC_SUBST(OFKERNELEVENTOBSERVER_POLL_M, + "OFKernelEventObserver_poll.m") ]) AC_MSG_CHECKING(for getaddrinfo) AC_TRY_COMPILE([ #include Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -30,13 +30,13 @@ LOOKUP_ASM_LOOKUP_ASM_LIB_A = @LOOKUP_ASM_LOOKUP_ASM_LIB_A@ MAP_LDFLAGS = @MAP_LDFLAGS@ OFBLOCKTESTS_M = @OFBLOCKTESTS_M@ OFHTTPCLIENTTESTS_M = @OFHTTPCLIENTTESTS_M@ OFPROCESS_M = @OFPROCESS_M@ -OFSTREAMOBSERVER_KQUEUE_M = @OFSTREAMOBSERVER_KQUEUE_M@ -OFSTREAMOBSERVER_POLL_M = @OFSTREAMOBSERVER_POLL_M@ -OFSTREAMOBSERVER_SELECT_M = @OFSTREAMOBSERVER_SELECT_M@ +OFKERNELEVENTOBSERVER_KQUEUE_M = @OFKERNELEVENTOBSERVER_KQUEUE_M@ +OFKERNELEVENTOBSERVER_POLL_M = @OFKERNELEVENTOBSERVER_POLL_M@ +OFKERNELEVENTOBSERVER_SELECT_M = @OFKERNELEVENTOBSERVER_SELECT_M@ OFZIP = @OFZIP@ PROPERTIESTESTS_M = @PROPERTIESTESTS_M@ REEXPORT_LIBOBJC = @REEXPORT_LIBOBJC@ RUNTIME = @RUNTIME@ RUNTIME_A = @RUNTIME_A@ Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -81,11 +81,11 @@ SRCS_PLUGINS = OFPlugin.m SRCS_SOCKETS = OFHTTPClient.m \ OFHTTPRequest.m \ OFHTTPResponse.m \ OFHTTPServer.m \ - OFStreamObserver.m \ + OFKernelEventObserver.m \ OFStreamSocket.m \ OFTCPSocket.m \ OFUDPSocket.m \ resolver.m SRCS_THREADS = OFCondition.m \ @@ -129,13 +129,13 @@ codepage_437.m \ ${FOUNDATION_COMPAT_M} \ ${INSTANCE_M} \ iso_8859_15.m \ windows_1252.m -SRCS_SOCKETS += ${OFSTREAMOBSERVER_KQUEUE_M} \ - ${OFSTREAMOBSERVER_POLL_M} \ - ${OFSTREAMOBSERVER_SELECT_M} \ +SRCS_SOCKETS += ${OFKERNELEVENTOBSERVER_KQUEUE_M} \ + ${OFKERNELEVENTOBSERVER_POLL_M} \ + ${OFKERNELEVENTOBSERVER_SELECT_M} \ OFTCPSocket+SOCKS5.m OBJS_EXTRA = ${RUNTIME_RUNTIME_A} \ ${EXCEPTIONS_EXCEPTIONS_A} \ ${FORWARDING_FORWARDING_A} ADDED src/OFKernelEventObserver+Private.h Index: src/OFKernelEventObserver+Private.h ================================================================== --- src/OFKernelEventObserver+Private.h +++ src/OFKernelEventObserver+Private.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 + * 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 + * 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. + */ + +#import "OFKernelEventObserver.h" + +#import "macros.h" + +@interface OFKernelEventObserver (OF_PRIVATE_CATEGORY) +- (void)OF_addFileDescriptorForReading: (int)fd; +- (void)OF_addFileDescriptorForWriting: (int)fd; +- (void)OF_removeFileDescriptorForReading: (int)fd; +- (void)OF_removeFileDescriptorForWriting: (int)fd; +- (void)OF_processQueue; +- (bool)OF_processCache; +@end ADDED src/OFKernelEventObserver.h Index: src/OFKernelEventObserver.h ================================================================== --- src/OFKernelEventObserver.h +++ src/OFKernelEventObserver.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 + * 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 + * 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. + */ + +#import "OFObject.h" + +#import "socket.h" + +@class OFStream; +@class OFMutableArray; +@class OFMutableDictionary; +@class OFDataArray; +#ifdef OF_HAVE_THREADS +@class OFMutex; +#endif +@class OFDate; + +/*! + * @brief A protocol that needs to be implemented by delegates for + * OFKernelEventObserver. + */ +@protocol OFKernelEventObserverDelegate +#ifdef OF_HAVE_OPTIONAL_PROTOCOLS +@optional +#endif +/*! + * @brief This callback is called when a stream did get ready for reading. + * + * @note When @ref OFStream::tryReadLine or + * @ref OFStream::tryReadTillDelimiter: has been called on the stream, + * this callback will not be called again until new data has been + * received, even though there is still data in the cache. The reason for + * this is to prevent spinning in a loop when there is an incomplete + * string in the cache. Once the string is complete, the callback will be + * called again if there is data in the cache. + * + * @param stream The stream which did become ready for reading + */ +- (void)streamIsReadyForReading: (OFStream*)stream; + +/*! + * @brief This callback is called when a stream did get ready for writing. + * + * @param stream The stream which did become ready for writing + */ +- (void)streamIsReadyForWriting: (OFStream*)stream; + +/*! + * @brief This callback is called when an exception occurred on the stream. + * + * @param stream The stream on which an exception occurred + */ +- (void)streamDidReceiveException: (OFStream*)stream; +@end + +/*! + * @brief A class that can observe multiple kernel events (e.g. streams being + * ready to read) at once. + * + * @note Currently, Win32 can only observe sockets and not files! + */ +@interface OFKernelEventObserver: OFObject +{ + OFMutableArray *_readStreams; + OFMutableArray *_writeStreams; + __unsafe_unretained OFStream **_FDToStream; + size_t _maxFD; + OFMutableArray *_queue; + OFDataArray *_queueInfo, *_queueFDs; + id _delegate; + int _cancelFD[2]; +#ifndef OF_HAVE_PIPE + struct sockaddr_in _cancelAddr; +#endif +#ifdef OF_HAVE_THREADS + OFMutex *_mutex; +#endif +} + +#ifdef OF_HAVE_PROPERTIES +@property (assign) id delegate; +#endif + +/*! + * @brief Creates a new OFKernelEventObserver. + * + * @return A new, autoreleased OFKernelEventObserver + */ ++ (instancetype)observer; + +/*! + * @brief Returns the delegate for the OFKernelEventObserver. + * + * @return The delegate for the OFKernelEventObserver + */ +- (id )delegate; + +/*! + * @brief Sets the delegate for the OFKernelEventObserver. + * + * @param delegate The delegate for the OFKernelEventObserver + */ +- (void)setDelegate: (id )delegate; + +/*! + * @brief Adds a stream to observe for reading. + * + * This is also used to observe a listening socket for incoming connections, + * which then triggers a read event for the observed stream. + * + * It is recommended that the stream you add is set to non-blocking mode. + * + * If there is an @ref observe call blocking, it will be canceled. The reason + * for this is to prevent blocking even though the new added stream is ready. + * + * @param stream The stream to observe for reading + */ +- (void)addStreamForReading: (OFStream*)stream; + +/*! + * @brief Adds a stream to observe for writing. + * + * It is recommended that the stream you add is set to non-blocking mode. + * + * If there is an @ref observe call blocking, it will be canceled. The reason + * for this is to prevent blocking even though the new added stream is ready. + * + * @param stream The stream to observe for writing + */ +- (void)addStreamForWriting: (OFStream*)stream; + +/*! + * @brief Removes a stream to observe for reading. + * + * If there is an @ref observe call blocking, it will be canceled. The reason + * for this is to prevent the removed stream from still being observed. + * + * @param stream The stream to remove from observing for reading + */ +- (void)removeStreamForReading: (OFStream*)stream; + +/*! + * @brief Removes a stream to observe for writing. + * + * If there is an @ref observe call blocking, it will be canceled. The reason + * for this is to prevent the removed stream from still being observed. + * + * @param stream The stream to remove from observing for writing + */ +- (void)removeStreamForWriting: (OFStream*)stream; + +/*! + * @brief Observes all streams and blocks until an event happens on a stream. + */ +- (void)observe; + +/*! + * @brief Observes all streams until an event happens on a stream 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 + */ +- (bool)observeForTimeInterval: (of_time_interval_t)timeInterval; + +/*! + * @brief Observes all streams until an event happens on a stream or the + * timeout is reached. + * + * @param date The until which to observe + * @return A boolean whether events occurred until the specified date + */ +- (bool)observeUntilDate: (OFDate*)date; + +/*! + * @brief Cancels the currently blocking observe call. + * + * This is automatically done when a new stream is added or removed by another + * thread, but in some circumstances, it might be desirable for a thread to + * manually stop the observe running in another thread. + */ +- (void)cancel; +@end + +@interface OFObject (OFKernelEventObserverDelegate) + +@end ADDED src/OFKernelEventObserver.m Index: src/OFKernelEventObserver.m ================================================================== --- src/OFKernelEventObserver.m +++ src/OFKernelEventObserver.m @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 + * 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 + * 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 + +#import "OFKernelEventObserver.h" +#import "OFKernelEventObserver+Private.h" +#import "OFArray.h" +#import "OFDictionary.h" +#import "OFStream.h" +#import "OFStream+Private.h" +#import "OFDataArray.h" +#ifndef OF_HAVE_PIPE +# import "OFStreamSocket.h" +#endif +#ifdef OF_HAVE_THREADS +# import "OFMutex.h" +#endif +#import "OFDate.h" + +#ifdef HAVE_KQUEUE +# import "OFKernelEventObserver_kqueue.h" +#endif +#if defined(HAVE_POLL_H) || defined(__wii__) +# import "OFKernelEventObserver_poll.h" +#endif +#if defined(HAVE_SYS_SELECT_H) || defined(_WIN32) +# import "OFKernelEventObserver_select.h" +#endif + +#import "OFInitializationFailedException.h" +#import "OFOutOfRangeException.h" + +#import "autorelease.h" +#import "macros.h" +#import "socket_helpers.h" + +enum { + QUEUE_ADD = 0, + QUEUE_REMOVE = 1, + QUEUE_READ = 0, + QUEUE_WRITE = 2 +}; +#define QUEUE_ACTION (QUEUE_ADD | QUEUE_REMOVE) + +@implementation OFKernelEventObserver ++ (instancetype)observer +{ + return [[[self alloc] init] autorelease]; +} + +#if defined(HAVE_KQUEUE) ++ alloc +{ + if (self == [OFKernelEventObserver class]) + return [OFKernelEventObserver_kqueue alloc]; + + return [super alloc]; +} +#elif defined(HAVE_POLL_H) || defined(__wii__) ++ alloc +{ + if (self == [OFKernelEventObserver class]) + return [OFKernelEventObserver_poll alloc]; + + return [super alloc]; +} +#elif defined(HAVE_SYS_SELECT_H) || defined(_WIN32) ++ alloc +{ + if (self == [OFKernelEventObserver class]) + return [OFKernelEventObserver_select alloc]; + + return [super alloc]; +} +#endif + +- init +{ + self = [super init]; + + @try { +#ifndef OF_HAVE_PIPE + struct sockaddr_in cancelAddr2; +# ifndef __wii__ + socklen_t cancelAddrLen; +# endif +#endif + + _readStreams = [[OFMutableArray alloc] init]; + _writeStreams = [[OFMutableArray alloc] init]; + _queue = [[OFMutableArray alloc] init]; + _queueInfo = [[OFDataArray alloc] + initWithItemSize: sizeof(int)]; + _queueFDs = [[OFDataArray alloc] initWithItemSize: sizeof(int)]; + +#ifdef OF_HAVE_PIPE + if (pipe(_cancelFD)) + @throw [OFInitializationFailedException + exceptionWithClass: [self class]]; +#else + /* Make sure network has been initialized */ + [OFStreamSocket class]; + + _cancelFD[0] = socket(AF_INET, SOCK_DGRAM, 0); + _cancelFD[1] = socket(AF_INET, SOCK_DGRAM, 0); + + if (_cancelFD[0] == INVALID_SOCKET || + _cancelFD[1] == INVALID_SOCKET) + @throw [OFInitializationFailedException + exceptionWithClass: [self class]]; + + _cancelAddr.sin_family = AF_INET; + _cancelAddr.sin_port = 0; + _cancelAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + cancelAddr2 = _cancelAddr; + +# ifdef __wii__ + /* The Wii does not accept port 0 as "choose any free port" */ + _cancelAddr.sin_port = 65533; + cancelAddr2.sin_port = 65534; +# endif + + if (bind(_cancelFD[0], (struct sockaddr*)&_cancelAddr, + sizeof(_cancelAddr)) || bind(_cancelFD[1], + (struct sockaddr*)&cancelAddr2, sizeof(cancelAddr2))) + @throw [OFInitializationFailedException + exceptionWithClass: [self class]]; + +# ifndef __wii__ + cancelAddrLen = sizeof(_cancelAddr); + if (getsockname(_cancelFD[0], (struct sockaddr*)&_cancelAddr, + &cancelAddrLen)) + @throw [OFInitializationFailedException + exceptionWithClass: [self class]]; +# endif +#endif + + _maxFD = _cancelFD[0]; + _FDToStream = [self allocMemoryWithSize: sizeof(OFStream*) + count: _maxFD + 1]; + _FDToStream[_cancelFD[0]] = nil; + +#ifdef OF_HAVE_THREADS + _mutex = [[OFMutex alloc] init]; +#endif + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + close(_cancelFD[0]); + close(_cancelFD[1]); + + [_readStreams release]; + [_writeStreams release]; + [_queue release]; + [_queueInfo release]; + [_queueFDs release]; +#ifdef OF_HAVE_THREADS + [_mutex release]; +#endif + + [super dealloc]; +} + +- (id )delegate +{ + return _delegate; +} + +- (void)setDelegate: (id )delegate +{ + _delegate = delegate; +} + +- (void)addStreamForReading: (OFStream*)stream +{ +#ifdef OF_HAVE_THREADS + [_mutex lock]; +#endif + @try { + int qi = QUEUE_ADD | QUEUE_READ; + int fd = [stream fileDescriptorForReading]; + + [_queue addObject: stream]; + [_queueInfo addItem: &qi]; + [_queueFDs addItem: &fd]; + } @finally { +#ifdef OF_HAVE_THREADS + [_mutex unlock]; +#endif + } + + [self cancel]; +} + +- (void)addStreamForWriting: (OFStream*)stream +{ +#ifdef OF_HAVE_THREADS + [_mutex lock]; +#endif + @try { + int qi = QUEUE_ADD | QUEUE_WRITE; + int fd = [stream fileDescriptorForWriting]; + + [_queue addObject: stream]; + [_queueInfo addItem: &qi]; + [_queueFDs addItem: &fd]; + } @finally { +#ifdef OF_HAVE_THREADS + [_mutex unlock]; +#endif + } + + [self cancel]; +} + +- (void)removeStreamForReading: (OFStream*)stream +{ +#ifdef OF_HAVE_THREADS + [_mutex lock]; +#endif + @try { + int qi = QUEUE_REMOVE | QUEUE_READ; + int fd = [stream fileDescriptorForReading]; + + [_queue addObject: stream]; + [_queueInfo addItem: &qi]; + [_queueFDs addItem: &fd]; + } @finally { +#ifdef OF_HAVE_THREADS + [_mutex unlock]; +#endif + } + + [self cancel]; +} + +- (void)removeStreamForWriting: (OFStream*)stream +{ +#ifdef OF_HAVE_THREADS + [_mutex lock]; +#endif + @try { + int qi = QUEUE_REMOVE | QUEUE_WRITE; + int fd = [stream fileDescriptorForWriting]; + + [_queue addObject: stream]; + [_queueInfo addItem: &qi]; + [_queueFDs addItem: &fd]; + } @finally { +#ifdef OF_HAVE_THREADS + [_mutex unlock]; +#endif + } + + [self cancel]; +} + +- (void)OF_addFileDescriptorForReading: (int)fd +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)OF_addFileDescriptorForWriting: (int)fd +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)OF_removeFileDescriptorForReading: (int)fd +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)OF_removeFileDescriptorForWriting: (int)fd +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)OF_processQueue +{ +#ifdef OF_HAVE_THREADS + [_mutex lock]; +#endif + @try { + OFStream **queueObjects = [_queue objects]; + int *queueInfoItems = [_queueInfo items]; + int *queueFDsItems = [_queueFDs items]; + size_t i, count = [_queue count]; + + for (i = 0; i < count; i++) { + OFStream *stream = queueObjects[i]; + int action = queueInfoItems[i]; + int fd = queueFDsItems[i]; + + if ((action & QUEUE_ACTION) == QUEUE_ADD) { + if (fd > _maxFD) { + _maxFD = fd; + _FDToStream = [self + resizeMemory: _FDToStream + size: sizeof(OFStream*) + count: _maxFD + 1]; + } + + _FDToStream[fd] = stream; + } + + if ((action & QUEUE_ACTION) == QUEUE_REMOVE) { + /* FIXME: Maybe downsize? */ + _FDToStream[fd] = nil; + } + + switch (action) { + case QUEUE_ADD | QUEUE_READ: + [_readStreams addObject: stream]; + + [self OF_addFileDescriptorForReading: fd]; + + break; + case QUEUE_ADD | QUEUE_WRITE: + [_writeStreams addObject: stream]; + + [self OF_addFileDescriptorForWriting: fd]; + + break; + case QUEUE_REMOVE | QUEUE_READ: + [_readStreams removeObjectIdenticalTo: stream]; + + [self OF_removeFileDescriptorForReading: fd]; + + break; + case QUEUE_REMOVE | QUEUE_WRITE: + [_writeStreams removeObjectIdenticalTo: stream]; + + [self OF_removeFileDescriptorForWriting: fd]; + + break; + default: + assert(0); + } + } + + [_queue removeAllObjects]; + [_queueInfo removeAllItems]; + [_queueFDs removeAllItems]; + } @finally { +#ifdef OF_HAVE_THREADS + [_mutex unlock]; +#endif + } +} + +- (void)observe +{ + [self observeForTimeInterval: -1]; +} + +- (bool)observeForTimeInterval: (of_time_interval_t)timeInterval +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (bool)observeUntilDate: (OFDate*)date +{ + return [self observeForTimeInterval: [date timeIntervalSinceNow]]; +} + +- (void)cancel +{ +#ifdef OF_HAVE_PIPE + OF_ENSURE(write(_cancelFD[1], "", 1) > 0); +#else + OF_ENSURE(sendto(_cancelFD[1], "", 1, 0, (struct sockaddr*)&_cancelAddr, + sizeof(_cancelAddr)) > 0); +#endif +} + +- (bool)OF_processCache +{ + OFStream **objects = [_readStreams objects]; + size_t i, count = [_readStreams count]; + bool foundInCache = false; + + for (i = 0; i < count; i++) { + if ([objects[i] numberOfBytesInReadBuffer] > 0 && + ![objects[i] OF_isWaitingForDelimiter]) { + void *pool = objc_autoreleasePoolPush(); + + if ([_delegate respondsToSelector: + @selector(streamIsReadyForReading:)]) + [_delegate streamIsReadyForReading: objects[i]]; + + foundInCache = true; + + objc_autoreleasePoolPop(pool); + } + } + + /* + * As long as we have data in the cache for any stream, we don't want + * to block. + */ + if (foundInCache) + return true; + + return false; +} +@end ADDED src/OFKernelEventObserver_kqueue.h Index: src/OFKernelEventObserver_kqueue.h ================================================================== --- src/OFKernelEventObserver_kqueue.h +++ src/OFKernelEventObserver_kqueue.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 + * 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 + * 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. + */ + +#import "OFKernelEventObserver.h" + +@class OFDataArray; + +@interface OFKernelEventObserver_kqueue: OFKernelEventObserver +{ + int _kernelQueue; + OFDataArray *_changeList; +} +@end ADDED src/OFKernelEventObserver_kqueue.m Index: src/OFKernelEventObserver_kqueue.m ================================================================== --- src/OFKernelEventObserver_kqueue.m +++ src/OFKernelEventObserver_kqueue.m @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 + * 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 + * 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" + +#include +#include + +#include + +#include +#include +#include + +#import "OFKernelEventObserver.h" +#import "OFKernelEventObserver+Private.h" +#import "OFKernelEventObserver_kqueue.h" +#import "OFDataArray.h" + +#import "OFInitializationFailedException.h" +#import "OFOutOfMemoryException.h" +#import "OFOutOfRangeException.h" + +#import "autorelease.h" +#import "macros.h" +#import "socket_helpers.h" + +#define EVENTLIST_SIZE 64 + +@implementation OFKernelEventObserver_kqueue +- init +{ + self = [super init]; + + @try { + if ((_kernelQueue = kqueue()) == -1) + @throw [OFInitializationFailedException + exceptionWithClass: [self class]]; + + _changeList = [[OFDataArray alloc] initWithItemSize: + sizeof(struct kevent)]; + + [self OF_addFileDescriptorForReading: _cancelFD[0]]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + close(_kernelQueue); + [_changeList release]; + + [super dealloc]; +} + +- (void)OF_addFileDescriptorForReading: (int)fd +{ + struct kevent event; + + if ([_changeList count] >= INT_MAX) + @throw [OFOutOfRangeException exception]; + + EV_SET(&event, fd, EVFILT_READ, EV_ADD, 0, 0, 0); + [_changeList addItem: &event]; +} + +- (void)OF_addFileDescriptorForWriting: (int)fd +{ + struct kevent event; + + if ([_changeList count] >= INT_MAX) + @throw [OFOutOfRangeException exception]; + + EV_SET(&event, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); + [_changeList addItem: &event]; +} + +- (void)OF_removeFileDescriptorForReading: (int)fd +{ + struct kevent event; + + EV_SET(&event, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); + [_changeList addItem: &event]; +} + +- (void)OF_removeFileDescriptorForWriting: (int)fd +{ + struct kevent event; + + EV_SET(&event, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); + [_changeList addItem: &event]; +} + +- (bool)observeForTimeInterval: (of_time_interval_t)timeInterval +{ + void *pool = objc_autoreleasePoolPush(); + struct timespec timeout; + struct kevent eventList[EVENTLIST_SIZE]; + int i, events, realEvents = 0; + + timeout.tv_sec = (time_t)timeInterval; + timeout.tv_nsec = lrint((timeInterval - timeout.tv_sec) * 1000000000); + + [self OF_processQueue]; + + if ([self OF_processCache]) { + objc_autoreleasePoolPop(pool); + return true; + } + + objc_autoreleasePoolPop(pool); + + events = kevent(_kernelQueue, [_changeList items], + (int)[_changeList count], eventList, EVENTLIST_SIZE, + (timeInterval == -1 ? NULL : &timeout)); + + if (events < 0) + return false; + + [_changeList removeAllItems]; + + if (events == 0) + return false; + + for (i = 0; i < events; i++) { + if (eventList[i].ident == _cancelFD[0]) { + char buffer; + + OF_ENSURE(read(_cancelFD[0], &buffer, 1) > 0); + + continue; + } + + realEvents++; + + pool = objc_autoreleasePoolPush(); + + if (eventList[i].flags & EV_ERROR) { + if ([_delegate respondsToSelector: + @selector(streamDidReceiveException:)]) + [_delegate streamDidReceiveException: + _FDToStream[eventList[i].ident]]; + + objc_autoreleasePoolPop(pool); + continue; + } + + switch (eventList[i].filter) { + case EVFILT_READ: + if ([_delegate respondsToSelector: + @selector(streamIsReadyForReading:)]) + [_delegate streamIsReadyForReading: + _FDToStream[eventList[i].ident]]; + break; + case EVFILT_WRITE: + if ([_delegate respondsToSelector: + @selector(streamIsReadyForWriting:)]) + [_delegate streamIsReadyForWriting: + _FDToStream[eventList[i].ident]]; + break; + default: + assert(0); + } + + objc_autoreleasePoolPop(pool); + } + + if (realEvents == 0) + return false; + + return true; +} +@end ADDED src/OFKernelEventObserver_poll.h Index: src/OFKernelEventObserver_poll.h ================================================================== --- src/OFKernelEventObserver_poll.h +++ src/OFKernelEventObserver_poll.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 + * 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 + * 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. + */ + +#import "OFKernelEventObserver.h" + +@class OFDataArray; + +@interface OFKernelEventObserver_poll: OFKernelEventObserver +{ + OFDataArray *_FDs; +} +@end ADDED src/OFKernelEventObserver_poll.m Index: src/OFKernelEventObserver_poll.m ================================================================== --- src/OFKernelEventObserver_poll.m +++ src/OFKernelEventObserver_poll.m @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 + * 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 + * 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 + +#ifdef HAVE_POLL_H +# include +#endif + +#import "OFKernelEventObserver.h" +#import "OFKernelEventObserver+Private.h" +#import "OFKernelEventObserver_poll.h" +#import "OFDataArray.h" + +#import "OFOutOfRangeException.h" + +#import "autorelease.h" +#import "macros.h" +#import "socket_helpers.h" + +#ifdef __wii__ +# define pollfd pollsd +# define fd socket +#endif + +@implementation OFKernelEventObserver_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: (of_time_interval_t)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 ADDED src/OFKernelEventObserver_select.h Index: src/OFKernelEventObserver_select.h ================================================================== --- src/OFKernelEventObserver_select.h +++ src/OFKernelEventObserver_select.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 + * 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 + * 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. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#ifdef HAVE_SYS_SELECT_H +# include +#endif + +#import "OFKernelEventObserver.h" + +@interface OFKernelEventObserver_select: OFKernelEventObserver +{ + fd_set _readFDs, _writeFDs, _exceptFDs; +} +@end ADDED src/OFKernelEventObserver_select.m Index: src/OFKernelEventObserver_select.m ================================================================== --- src/OFKernelEventObserver_select.m +++ src/OFKernelEventObserver_select.m @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 + * 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 + * 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 +#include + +#include + +#import "OFKernelEventObserver.h" +#import "OFKernelEventObserver+Private.h" +#import "OFKernelEventObserver_select.h" +#import "OFStream.h" +#import "OFArray.h" + +#import "autorelease.h" +#import "macros.h" +#import "socket_helpers.h" + +@implementation OFKernelEventObserver_select +- init +{ + self = [super init]; + + FD_ZERO(&_readFDs); + FD_ZERO(&_writeFDs); + + FD_SET(_cancelFD[0], &_readFDs); + + return self; +} + +- (void)OF_addFileDescriptorForReading: (int)fd +{ + FD_SET(fd, &_readFDs); + FD_SET(fd, &_exceptFDs); +} + +- (void)OF_addFileDescriptorForWriting: (int)fd +{ + FD_SET(fd, &_writeFDs); + FD_SET(fd, &_exceptFDs); +} + +- (void)OF_removeFileDescriptorForReading: (int)fd +{ + FD_CLR(fd, &_readFDs); + + if (!FD_ISSET(fd, &_writeFDs)) + FD_CLR(fd, &_exceptFDs); +} + +- (void)OF_removeFileDescriptorForWriting: (int)fd +{ + FD_CLR(fd, &_writeFDs); + + if (!FD_ISSET(fd, &_readFDs)) + FD_CLR(fd, &_exceptFDs); +} + +- (bool)observeForTimeInterval: (of_time_interval_t)timeInterval +{ + void *pool = objc_autoreleasePoolPush(); + OFStream **objects; + fd_set readFDs; + fd_set writeFDs; + fd_set exceptFDs; + struct timeval timeout; + size_t i, count, realEvents = 0; + + [self OF_processQueue]; + + if ([self OF_processCache]) { + objc_autoreleasePoolPop(pool); + return true; + } + + objc_autoreleasePoolPop(pool); + +#ifdef FD_COPY + FD_COPY(&_readFDs, &readFDs); + FD_COPY(&_writeFDs, &writeFDs); + FD_COPY(&_exceptFDs, &exceptFDs); +#else + readFDs = _readFDs; + writeFDs = _writeFDs; + exceptFDs = _exceptFDs; +#endif + + /* + * We cast to int before assigning to tv_usec in order to avoid a + * warning with Apple GCC on PPC. POSIX defines this as suseconds_t, + * however, this is not available on Win32. As an int should always + * satisfy the required range, we just cast to int. + */ + timeout.tv_sec = (time_t)timeInterval; + timeout.tv_usec = (int)lrint((timeInterval - timeout.tv_sec) * 1000); + + if (select((int)_maxFD + 1, &readFDs, &writeFDs, &exceptFDs, + (timeInterval != -1 ? &timeout : NULL)) < 1) + return false; + + if (FD_ISSET(_cancelFD[0], &readFDs)) { + char buffer; +#ifndef _WIN32 + OF_ENSURE(read(_cancelFD[0], &buffer, 1) > 0); +#else + OF_ENSURE(recvfrom(_cancelFD[0], &buffer, 1, 0, NULL, + NULL) > 0); +#endif + } + + objects = [_readStreams objects]; + count = [_readStreams count]; + + for (i = 0; i < count; i++) { + int fd = [objects[i] fileDescriptorForReading]; + + pool = objc_autoreleasePoolPush(); + + if (FD_ISSET(fd, &readFDs)) { + if ([_delegate respondsToSelector: + @selector(streamIsReadyForReading:)]) + [_delegate streamIsReadyForReading: objects[i]]; + + realEvents++; + } + + if (FD_ISSET(fd, &exceptFDs)) { + if ([_delegate respondsToSelector: + @selector(streamDidReceiveException:)]) + [_delegate streamDidReceiveException: + objects[i]]; + + /* + * Prevent calling it twice in case the FD is in both + * sets. + */ + FD_CLR(fd, &exceptFDs); + + realEvents++; + } + + objc_autoreleasePoolPop(pool); + } + + objects = [_writeStreams objects]; + count = [_writeStreams count]; + + for (i = 0; i < count; i++) { + int fd = [objects[i] fileDescriptorForWriting]; + + pool = objc_autoreleasePoolPush(); + + if (FD_ISSET(fd, &writeFDs)) { + if ([_delegate respondsToSelector: + @selector(streamIsReadyForWriting:)]) + [_delegate streamIsReadyForWriting: objects[i]]; + + realEvents++; + } + + if (FD_ISSET(fd, &exceptFDs)) { + if ([_delegate respondsToSelector: + @selector(streamDidReceiveException:)]) + [_delegate streamDidReceiveException: + objects[i]]; + + realEvents++; + } + + objc_autoreleasePoolPop(pool); + } + + if (realEvents == 0) + return false; + + return true; +} +@end Index: src/OFRunLoop.h ================================================================== --- src/OFRunLoop.h +++ src/OFRunLoop.h @@ -24,11 +24,11 @@ #ifdef OF_HAVE_THREADS @class OFMutex; @class OFCondition; #endif #ifdef OF_HAVE_SOCKETS -@class OFStreamObserver; +@class OFKernelEventObserver; #endif @class OFMutableDictionary; @class OFTimer; /*! @@ -39,11 +39,11 @@ OFSortedList *_timersQueue; #ifdef OF_HAVE_THREADS OFMutex *_timersQueueLock; #endif #if defined(OF_HAVE_SOCKETS) - OFStreamObserver *_streamObserver; + OFKernelEventObserver *_kernelEventObserver; OFMutableDictionary *_readQueues; #elif defined(OF_HAVE_THREADS) OFCondition *_condition; #endif volatile bool _running; Index: src/OFRunLoop.m ================================================================== --- src/OFRunLoop.m +++ src/OFRunLoop.m @@ -20,11 +20,11 @@ #import "OFRunLoop.h" #import "OFRunLoop+Private.h" #import "OFDictionary.h" #ifdef OF_HAVE_SOCKETS -# import "OFStreamObserver.h" +# import "OFKernelEventObserver.h" #endif #import "OFThread.h" #ifdef OF_HAVE_THREADS # import "OFMutex.h" # import "OFCondition.h" @@ -175,11 +175,12 @@ [runLoop->_readQueues setObject: queue \ forKey: stream]; \ } \ \ if ([queue count] == 0) \ - [runLoop->_streamObserver addStreamForReading: stream]; \ + [runLoop->_kernelEventObserver \ + addStreamForReading: stream]; \ \ queueItem = [[[type alloc] init] autorelease]; \ code \ [queue appendObject: queueItem]; \ \ @@ -287,11 +288,11 @@ OFList *queue; if ((queue = [runLoop->_readQueues objectForKey: stream]) != nil) { assert([queue count] > 0); - [runLoop->_streamObserver removeStreamForReading: stream]; + [runLoop->_kernelEventObserver removeStreamForReading: stream]; [runLoop->_readQueues removeObjectForKey: stream]; } objc_autoreleasePoolPop(pool); } @@ -306,12 +307,12 @@ #ifdef OF_HAVE_THREADS _timersQueueLock = [[OFMutex alloc] init]; #endif #if defined(OF_HAVE_SOCKETS) - _streamObserver = [[OFStreamObserver alloc] init]; - [_streamObserver setDelegate: self]; + _kernelEventObserver = [[OFKernelEventObserver alloc] init]; + [_kernelEventObserver setDelegate: self]; _readQueues = [[OFMutableDictionary alloc] init]; #elif defined(OF_HAVE_THREADS) _condition = [[OFCondition alloc] init]; #endif @@ -328,11 +329,11 @@ [_timersQueue release]; #ifdef OF_HAVE_THREADS [_timersQueueLock release]; #endif #if defined(OF_HAVE_SOCKETS) - [_streamObserver release]; + [_kernelEventObserver release]; [_readQueues release]; #elif defined(OF_HAVE_THREADS) [_condition release]; #endif @@ -353,11 +354,11 @@ #endif [timer OF_setInRunLoop: self]; #if defined(OF_HAVE_SOCKETS) - [_streamObserver cancel]; + [_kernelEventObserver cancel]; #elif defined(OF_HAVE_THREADS) [_condition lock]; [_condition signal]; [_condition unlock]; #endif @@ -414,11 +415,11 @@ if (!queueItem->_block(stream, queueItem->_buffer, length, exception)) { [queue removeListObject: listObject]; if ([queue count] == 0) { - [_streamObserver + [_kernelEventObserver removeStreamForReading: stream]; [_readQueues removeObjectForKey: stream]; } } @@ -433,11 +434,11 @@ if (!func(queueItem->_target, queueItem->_selector, stream, queueItem->_buffer, length, exception)) { [queue removeListObject: listObject]; if ([queue count] == 0) { - [_streamObserver + [_kernelEventObserver removeStreamForReading: stream]; [_readQueues removeObjectForKey: stream]; } } @@ -472,11 +473,11 @@ queueItem->_readLength = 0; else { [queue removeListObject: listObject]; if ([queue count] == 0) { - [_streamObserver + [_kernelEventObserver removeStreamForReading: stream]; [_readQueues removeObjectForKey: stream]; } @@ -496,11 +497,11 @@ queueItem->_readLength = 0; else { [queue removeListObject: listObject]; if ([queue count] == 0) { - [_streamObserver + [_kernelEventObserver removeStreamForReading: stream]; [_readQueues removeObjectForKey: stream]; } @@ -530,11 +531,11 @@ if (!queueItem->_block(stream, line, exception)) { [queue removeListObject: listObject]; if ([queue count] == 0) { - [_streamObserver + [_kernelEventObserver removeStreamForReading: stream]; [_readQueues removeObjectForKey: stream]; } @@ -551,11 +552,11 @@ queueItem->_selector, stream, line, exception)) { [queue removeListObject: listObject]; if ([queue count] == 0) { - [_streamObserver + [_kernelEventObserver removeStreamForReading: stream]; [_readQueues removeObjectForKey: stream]; } @@ -582,11 +583,11 @@ if (!queueItem->_block((OFTCPSocket*)stream, newSocket, exception)) { [queue removeListObject: listObject]; if ([queue count] == 0) { - [_streamObserver + [_kernelEventObserver removeStreamForReading: stream]; [_readQueues removeObjectForKey: stream]; } } @@ -602,11 +603,11 @@ if (!func(queueItem->_target, queueItem->_selector, (OFTCPSocket*)stream, newSocket, exception)) { [queue removeListObject: listObject]; if ([queue count] == 0) { - [_streamObserver + [_kernelEventObserver removeStreamForReading: stream]; [_readQueues removeObjectForKey: stream]; } } @@ -677,11 +678,11 @@ of_time_interval_t timeout = [nextTimer timeIntervalSinceNow]; if (timeout > 0) { #if defined(OF_HAVE_SOCKETS) - [_streamObserver + [_kernelEventObserver observeForTimeInterval: timeout]; #elif defined(OF_HAVE_THREADS) [_condition lock]; [_condition waitForTimeInterval: timeout]; [_condition unlock]; @@ -694,11 +695,11 @@ * No more timers: Just watch for streams until we get * an event. If a timer is added by another thread, it * cancels the observe. */ #if defined(OF_HAVE_SOCKETS) - [_streamObserver observe]; + [_kernelEventObserver observe]; #elif defined(OF_HAVE_THREADS) [_condition lock]; [_condition wait]; [_condition unlock]; #else @@ -712,13 +713,13 @@ - (void)stop { _running = false; #if defined(OF_HAVE_SOCKETS) - [_streamObserver cancel]; + [_kernelEventObserver cancel]; #elif defined(OF_HAVE_THREADS) [_condition lock]; [_condition signal]; [_condition unlock]; #endif } @end DELETED src/OFStreamObserver+Private.h Index: src/OFStreamObserver+Private.h ================================================================== --- src/OFStreamObserver+Private.h +++ src/OFStreamObserver+Private.h @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 - * 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 - * 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. - */ - -#import "OFStreamObserver.h" - -#import "macros.h" - -@interface OFStreamObserver (OF_PRIVATE_CATEGORY) -- (void)OF_addFileDescriptorForReading: (int)fd; -- (void)OF_addFileDescriptorForWriting: (int)fd; -- (void)OF_removeFileDescriptorForReading: (int)fd; -- (void)OF_removeFileDescriptorForWriting: (int)fd; -- (void)OF_processQueue; -- (bool)OF_processCache; -@end DELETED src/OFStreamObserver.h Index: src/OFStreamObserver.h ================================================================== --- src/OFStreamObserver.h +++ src/OFStreamObserver.h @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 - * 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 - * 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. - */ - -#import "OFObject.h" - -#import "socket.h" - -@class OFStream; -@class OFMutableArray; -@class OFMutableDictionary; -@class OFDataArray; -#ifdef OF_HAVE_THREADS -@class OFMutex; -#endif -@class OFDate; - -/*! - * @brief A protocol that needs to be implemented by delegates for - * OFStreamObserver. - */ -@protocol OFStreamObserverDelegate -#ifdef OF_HAVE_OPTIONAL_PROTOCOLS -@optional -#endif -/*! - * @brief This callback is called when a stream did get ready for reading. - * - * @note When @ref OFStream::tryReadLine or - * @ref OFStream::tryReadTillDelimiter: has been called on the stream, - * this callback will not be called again until new data has been - * received, even though there is still data in the cache. The reason for - * this is to prevent spinning in a loop when there is an incomplete - * string in the cache. Once the string is complete, the callback will be - * called again if there is data in the cache. - * - * @param stream The stream which did become ready for reading - */ -- (void)streamIsReadyForReading: (OFStream*)stream; - -/*! - * @brief This callback is called when a stream did get ready for writing. - * - * @param stream The stream which did become ready for writing - */ -- (void)streamIsReadyForWriting: (OFStream*)stream; - -/*! - * @brief This callback is called when an exception occurred on the stream. - * - * @param stream The stream on which an exception occurred - */ -- (void)streamDidReceiveException: (OFStream*)stream; -@end - -/*! - * @brief A class that can observe multiple streams at once. - * - * @note Currently, Win32 can only observe sockets and not files! - */ -@interface OFStreamObserver: OFObject -{ - OFMutableArray *_readStreams; - OFMutableArray *_writeStreams; - __unsafe_unretained OFStream **_FDToStream; - size_t _maxFD; - OFMutableArray *_queue; - OFDataArray *_queueInfo, *_queueFDs; - id _delegate; - int _cancelFD[2]; -#ifndef OF_HAVE_PIPE - struct sockaddr_in _cancelAddr; -#endif -#ifdef OF_HAVE_THREADS - OFMutex *_mutex; -#endif -} - -#ifdef OF_HAVE_PROPERTIES -@property (assign) id delegate; -#endif - -/*! - * @brief Creates a new OFStreamObserver. - * - * @return A new, autoreleased OFStreamObserver - */ -+ (instancetype)observer; - -/*! - * @brief Returns the delegate for the OFStreamObserver. - * - * @return The delegate for the OFStreamObserver - */ -- (id )delegate; - -/*! - * @brief Sets the delegate for the OFStreamObserver. - * - * @param delegate The delegate for the OFStreamObserver - */ -- (void)setDelegate: (id )delegate; - -/*! - * @brief Adds a stream to observe for reading. - * - * This is also used to observe a listening socket for incoming connections, - * which then triggers a read event for the observed stream. - * - * It is recommended that the stream you add is set to non-blocking mode. - * - * If there is an @ref observe call blocking, it will be canceled. The reason - * for this is to prevent blocking even though the new added stream is ready. - * - * @param stream The stream to observe for reading - */ -- (void)addStreamForReading: (OFStream*)stream; - -/*! - * @brief Adds a stream to observe for writing. - * - * It is recommended that the stream you add is set to non-blocking mode. - * - * If there is an @ref observe call blocking, it will be canceled. The reason - * for this is to prevent blocking even though the new added stream is ready. - * - * @param stream The stream to observe for writing - */ -- (void)addStreamForWriting: (OFStream*)stream; - -/*! - * @brief Removes a stream to observe for reading. - * - * If there is an @ref observe call blocking, it will be canceled. The reason - * for this is to prevent the removed stream from still being observed. - * - * @param stream The stream to remove from observing for reading - */ -- (void)removeStreamForReading: (OFStream*)stream; - -/*! - * @brief Removes a stream to observe for writing. - * - * If there is an @ref observe call blocking, it will be canceled. The reason - * for this is to prevent the removed stream from still being observed. - * - * @param stream The stream to remove from observing for writing - */ -- (void)removeStreamForWriting: (OFStream*)stream; - -/*! - * @brief Observes all streams and blocks until an event happens on a stream. - */ -- (void)observe; - -/*! - * @brief Observes all streams until an event happens on a stream 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 - */ -- (bool)observeForTimeInterval: (of_time_interval_t)timeInterval; - -/*! - * @brief Observes all streams until an event happens on a stream or the - * timeout is reached. - * - * @param date The until which to observe - * @return A boolean whether events occurred until the specified date - */ -- (bool)observeUntilDate: (OFDate*)date; - -/*! - * @brief Cancels the currently blocking observe call. - * - * This is automatically done when a new stream is added or removed by another - * thread, but in some circumstances, it might be desirable for a thread to - * manually stop the observe running in another thread. - */ -- (void)cancel; -@end - -@interface OFObject (OFStreamObserverDelegate) -@end DELETED src/OFStreamObserver.m Index: src/OFStreamObserver.m ================================================================== --- src/OFStreamObserver.m +++ src/OFStreamObserver.m @@ -1,431 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 - * 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 - * 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 - -#import "OFStreamObserver.h" -#import "OFStreamObserver+Private.h" -#import "OFArray.h" -#import "OFDictionary.h" -#import "OFStream.h" -#import "OFStream+Private.h" -#import "OFDataArray.h" -#ifndef OF_HAVE_PIPE -# import "OFStreamSocket.h" -#endif -#ifdef OF_HAVE_THREADS -# import "OFMutex.h" -#endif -#import "OFDate.h" - -#ifdef HAVE_KQUEUE -# import "OFStreamObserver_kqueue.h" -#endif -#if defined(HAVE_POLL_H) || defined(__wii__) -# import "OFStreamObserver_poll.h" -#endif -#if defined(HAVE_SYS_SELECT_H) || defined(_WIN32) -# import "OFStreamObserver_select.h" -#endif - -#import "OFInitializationFailedException.h" -#import "OFOutOfRangeException.h" - -#import "autorelease.h" -#import "macros.h" -#import "socket_helpers.h" - -enum { - QUEUE_ADD = 0, - QUEUE_REMOVE = 1, - QUEUE_READ = 0, - QUEUE_WRITE = 2 -}; -#define QUEUE_ACTION (QUEUE_ADD | QUEUE_REMOVE) - -@implementation OFStreamObserver -+ (instancetype)observer -{ - return [[[self alloc] init] autorelease]; -} - -#if defined(HAVE_KQUEUE) -+ alloc -{ - if (self == [OFStreamObserver class]) - return [OFStreamObserver_kqueue alloc]; - - return [super alloc]; -} -#elif defined(HAVE_POLL_H) || defined(__wii__) -+ alloc -{ - if (self == [OFStreamObserver class]) - return [OFStreamObserver_poll alloc]; - - return [super alloc]; -} -#elif defined(HAVE_SYS_SELECT_H) || defined(_WIN32) -+ alloc -{ - if (self == [OFStreamObserver class]) - return [OFStreamObserver_select alloc]; - - return [super alloc]; -} -#endif - -- init -{ - self = [super init]; - - @try { -#ifndef OF_HAVE_PIPE - struct sockaddr_in cancelAddr2; -# ifndef __wii__ - socklen_t cancelAddrLen; -# endif -#endif - - _readStreams = [[OFMutableArray alloc] init]; - _writeStreams = [[OFMutableArray alloc] init]; - _queue = [[OFMutableArray alloc] init]; - _queueInfo = [[OFDataArray alloc] - initWithItemSize: sizeof(int)]; - _queueFDs = [[OFDataArray alloc] initWithItemSize: sizeof(int)]; - -#ifdef OF_HAVE_PIPE - if (pipe(_cancelFD)) - @throw [OFInitializationFailedException - exceptionWithClass: [self class]]; -#else - /* Make sure network has been initialized */ - [OFStreamSocket class]; - - _cancelFD[0] = socket(AF_INET, SOCK_DGRAM, 0); - _cancelFD[1] = socket(AF_INET, SOCK_DGRAM, 0); - - if (_cancelFD[0] == INVALID_SOCKET || - _cancelFD[1] == INVALID_SOCKET) - @throw [OFInitializationFailedException - exceptionWithClass: [self class]]; - - _cancelAddr.sin_family = AF_INET; - _cancelAddr.sin_port = 0; - _cancelAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); - cancelAddr2 = _cancelAddr; - -# ifdef __wii__ - /* The Wii does not accept port 0 as "choose any free port" */ - _cancelAddr.sin_port = 65533; - cancelAddr2.sin_port = 65534; -# endif - - if (bind(_cancelFD[0], (struct sockaddr*)&_cancelAddr, - sizeof(_cancelAddr)) || bind(_cancelFD[1], - (struct sockaddr*)&cancelAddr2, sizeof(cancelAddr2))) - @throw [OFInitializationFailedException - exceptionWithClass: [self class]]; - -# ifndef __wii__ - cancelAddrLen = sizeof(_cancelAddr); - if (getsockname(_cancelFD[0], (struct sockaddr*)&_cancelAddr, - &cancelAddrLen)) - @throw [OFInitializationFailedException - exceptionWithClass: [self class]]; -# endif -#endif - - _maxFD = _cancelFD[0]; - _FDToStream = [self allocMemoryWithSize: sizeof(OFStream*) - count: _maxFD + 1]; - _FDToStream[_cancelFD[0]] = nil; - -#ifdef OF_HAVE_THREADS - _mutex = [[OFMutex alloc] init]; -#endif - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - close(_cancelFD[0]); - close(_cancelFD[1]); - - [_readStreams release]; - [_writeStreams release]; - [_queue release]; - [_queueInfo release]; - [_queueFDs release]; -#ifdef OF_HAVE_THREADS - [_mutex release]; -#endif - - [super dealloc]; -} - -- (id )delegate -{ - return _delegate; -} - -- (void)setDelegate: (id )delegate -{ - _delegate = delegate; -} - -- (void)addStreamForReading: (OFStream*)stream -{ -#ifdef OF_HAVE_THREADS - [_mutex lock]; -#endif - @try { - int qi = QUEUE_ADD | QUEUE_READ; - int fd = [stream fileDescriptorForReading]; - - [_queue addObject: stream]; - [_queueInfo addItem: &qi]; - [_queueFDs addItem: &fd]; - } @finally { -#ifdef OF_HAVE_THREADS - [_mutex unlock]; -#endif - } - - [self cancel]; -} - -- (void)addStreamForWriting: (OFStream*)stream -{ -#ifdef OF_HAVE_THREADS - [_mutex lock]; -#endif - @try { - int qi = QUEUE_ADD | QUEUE_WRITE; - int fd = [stream fileDescriptorForWriting]; - - [_queue addObject: stream]; - [_queueInfo addItem: &qi]; - [_queueFDs addItem: &fd]; - } @finally { -#ifdef OF_HAVE_THREADS - [_mutex unlock]; -#endif - } - - [self cancel]; -} - -- (void)removeStreamForReading: (OFStream*)stream -{ -#ifdef OF_HAVE_THREADS - [_mutex lock]; -#endif - @try { - int qi = QUEUE_REMOVE | QUEUE_READ; - int fd = [stream fileDescriptorForReading]; - - [_queue addObject: stream]; - [_queueInfo addItem: &qi]; - [_queueFDs addItem: &fd]; - } @finally { -#ifdef OF_HAVE_THREADS - [_mutex unlock]; -#endif - } - - [self cancel]; -} - -- (void)removeStreamForWriting: (OFStream*)stream -{ -#ifdef OF_HAVE_THREADS - [_mutex lock]; -#endif - @try { - int qi = QUEUE_REMOVE | QUEUE_WRITE; - int fd = [stream fileDescriptorForWriting]; - - [_queue addObject: stream]; - [_queueInfo addItem: &qi]; - [_queueFDs addItem: &fd]; - } @finally { -#ifdef OF_HAVE_THREADS - [_mutex unlock]; -#endif - } - - [self cancel]; -} - -- (void)OF_addFileDescriptorForReading: (int)fd -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)OF_addFileDescriptorForWriting: (int)fd -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)OF_removeFileDescriptorForReading: (int)fd -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)OF_removeFileDescriptorForWriting: (int)fd -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)OF_processQueue -{ -#ifdef OF_HAVE_THREADS - [_mutex lock]; -#endif - @try { - OFStream **queueObjects = [_queue objects]; - int *queueInfoItems = [_queueInfo items]; - int *queueFDsItems = [_queueFDs items]; - size_t i, count = [_queue count]; - - for (i = 0; i < count; i++) { - OFStream *stream = queueObjects[i]; - int action = queueInfoItems[i]; - int fd = queueFDsItems[i]; - - if ((action & QUEUE_ACTION) == QUEUE_ADD) { - if (fd > _maxFD) { - _maxFD = fd; - _FDToStream = [self - resizeMemory: _FDToStream - size: sizeof(OFStream*) - count: _maxFD + 1]; - } - - _FDToStream[fd] = stream; - } - - if ((action & QUEUE_ACTION) == QUEUE_REMOVE) { - /* FIXME: Maybe downsize? */ - _FDToStream[fd] = nil; - } - - switch (action) { - case QUEUE_ADD | QUEUE_READ: - [_readStreams addObject: stream]; - - [self OF_addFileDescriptorForReading: fd]; - - break; - case QUEUE_ADD | QUEUE_WRITE: - [_writeStreams addObject: stream]; - - [self OF_addFileDescriptorForWriting: fd]; - - break; - case QUEUE_REMOVE | QUEUE_READ: - [_readStreams removeObjectIdenticalTo: stream]; - - [self OF_removeFileDescriptorForReading: fd]; - - break; - case QUEUE_REMOVE | QUEUE_WRITE: - [_writeStreams removeObjectIdenticalTo: stream]; - - [self OF_removeFileDescriptorForWriting: fd]; - - break; - default: - assert(0); - } - } - - [_queue removeAllObjects]; - [_queueInfo removeAllItems]; - [_queueFDs removeAllItems]; - } @finally { -#ifdef OF_HAVE_THREADS - [_mutex unlock]; -#endif - } -} - -- (void)observe -{ - [self observeForTimeInterval: -1]; -} - -- (bool)observeForTimeInterval: (of_time_interval_t)timeInterval -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (bool)observeUntilDate: (OFDate*)date -{ - return [self observeForTimeInterval: [date timeIntervalSinceNow]]; -} - -- (void)cancel -{ -#ifdef OF_HAVE_PIPE - OF_ENSURE(write(_cancelFD[1], "", 1) > 0); -#else - OF_ENSURE(sendto(_cancelFD[1], "", 1, 0, (struct sockaddr*)&_cancelAddr, - sizeof(_cancelAddr)) > 0); -#endif -} - -- (bool)OF_processCache -{ - OFStream **objects = [_readStreams objects]; - size_t i, count = [_readStreams count]; - bool foundInCache = false; - - for (i = 0; i < count; i++) { - if ([objects[i] numberOfBytesInReadBuffer] > 0 && - ![objects[i] OF_isWaitingForDelimiter]) { - void *pool = objc_autoreleasePoolPush(); - - if ([_delegate respondsToSelector: - @selector(streamIsReadyForReading:)]) - [_delegate streamIsReadyForReading: objects[i]]; - - foundInCache = true; - - objc_autoreleasePoolPop(pool); - } - } - - /* - * As long as we have data in the cache for any stream, we don't want - * to block. - */ - if (foundInCache) - return true; - - return false; -} -@end DELETED src/OFStreamObserver_kqueue.h Index: src/OFStreamObserver_kqueue.h ================================================================== --- src/OFStreamObserver_kqueue.h +++ src/OFStreamObserver_kqueue.h @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 - * 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 - * 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. - */ - -#import "OFStreamObserver.h" - -@class OFDataArray; - -@interface OFStreamObserver_kqueue: OFStreamObserver -{ - int _kernelQueue; - OFDataArray *_changeList; -} -@end DELETED src/OFStreamObserver_kqueue.m Index: src/OFStreamObserver_kqueue.m ================================================================== --- src/OFStreamObserver_kqueue.m +++ src/OFStreamObserver_kqueue.m @@ -1,190 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 - * 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 - * 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" - -#include -#include - -#include - -#include -#include -#include - -#import "OFStreamObserver.h" -#import "OFStreamObserver+Private.h" -#import "OFStreamObserver_kqueue.h" -#import "OFDataArray.h" - -#import "OFInitializationFailedException.h" -#import "OFOutOfMemoryException.h" -#import "OFOutOfRangeException.h" - -#import "autorelease.h" -#import "macros.h" -#import "socket_helpers.h" - -#define EVENTLIST_SIZE 64 - -@implementation OFStreamObserver_kqueue -- init -{ - self = [super init]; - - @try { - if ((_kernelQueue = kqueue()) == -1) - @throw [OFInitializationFailedException - exceptionWithClass: [self class]]; - - _changeList = [[OFDataArray alloc] initWithItemSize: - sizeof(struct kevent)]; - - [self OF_addFileDescriptorForReading: _cancelFD[0]]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - close(_kernelQueue); - [_changeList release]; - - [super dealloc]; -} - -- (void)OF_addFileDescriptorForReading: (int)fd -{ - struct kevent event; - - if ([_changeList count] >= INT_MAX) - @throw [OFOutOfRangeException exception]; - - EV_SET(&event, fd, EVFILT_READ, EV_ADD, 0, 0, 0); - [_changeList addItem: &event]; -} - -- (void)OF_addFileDescriptorForWriting: (int)fd -{ - struct kevent event; - - if ([_changeList count] >= INT_MAX) - @throw [OFOutOfRangeException exception]; - - EV_SET(&event, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); - [_changeList addItem: &event]; -} - -- (void)OF_removeFileDescriptorForReading: (int)fd -{ - struct kevent event; - - EV_SET(&event, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); - [_changeList addItem: &event]; -} - -- (void)OF_removeFileDescriptorForWriting: (int)fd -{ - struct kevent event; - - EV_SET(&event, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); - [_changeList addItem: &event]; -} - -- (bool)observeForTimeInterval: (of_time_interval_t)timeInterval -{ - void *pool = objc_autoreleasePoolPush(); - struct timespec timeout; - struct kevent eventList[EVENTLIST_SIZE]; - int i, events, realEvents = 0; - - timeout.tv_sec = (time_t)timeInterval; - timeout.tv_nsec = lrint((timeInterval - timeout.tv_sec) * 1000000000); - - [self OF_processQueue]; - - if ([self OF_processCache]) { - objc_autoreleasePoolPop(pool); - return true; - } - - objc_autoreleasePoolPop(pool); - - events = kevent(_kernelQueue, [_changeList items], - (int)[_changeList count], eventList, EVENTLIST_SIZE, - (timeInterval == -1 ? NULL : &timeout)); - - if (events < 0) - return false; - - [_changeList removeAllItems]; - - if (events == 0) - return false; - - for (i = 0; i < events; i++) { - if (eventList[i].ident == _cancelFD[0]) { - char buffer; - - OF_ENSURE(read(_cancelFD[0], &buffer, 1) > 0); - - continue; - } - - realEvents++; - - pool = objc_autoreleasePoolPush(); - - if (eventList[i].flags & EV_ERROR) { - if ([_delegate respondsToSelector: - @selector(streamDidReceiveException:)]) - [_delegate streamDidReceiveException: - _FDToStream[eventList[i].ident]]; - - objc_autoreleasePoolPop(pool); - continue; - } - - switch (eventList[i].filter) { - case EVFILT_READ: - if ([_delegate respondsToSelector: - @selector(streamIsReadyForReading:)]) - [_delegate streamIsReadyForReading: - _FDToStream[eventList[i].ident]]; - break; - case EVFILT_WRITE: - if ([_delegate respondsToSelector: - @selector(streamIsReadyForWriting:)]) - [_delegate streamIsReadyForWriting: - _FDToStream[eventList[i].ident]]; - break; - default: - assert(0); - } - - objc_autoreleasePoolPop(pool); - } - - if (realEvents == 0) - return false; - - return true; -} -@end DELETED src/OFStreamObserver_poll.h Index: src/OFStreamObserver_poll.h ================================================================== --- src/OFStreamObserver_poll.h +++ src/OFStreamObserver_poll.h @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 - * 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 - * 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. - */ - -#import "OFStreamObserver.h" - -@class OFDataArray; - -@interface OFStreamObserver_poll: OFStreamObserver -{ - OFDataArray *_FDs; -} -@end DELETED src/OFStreamObserver_poll.m Index: src/OFStreamObserver_poll.m ================================================================== --- src/OFStreamObserver_poll.m +++ src/OFStreamObserver_poll.m @@ -1,209 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 - * 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 - * 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 - -#ifdef HAVE_POLL_H -# include -#endif - -#import "OFStreamObserver.h" -#import "OFStreamObserver+Private.h" -#import "OFStreamObserver_poll.h" -#import "OFDataArray.h" - -#import "OFOutOfRangeException.h" - -#import "autorelease.h" -#import "macros.h" -#import "socket_helpers.h" - -#ifdef __wii__ -# define pollfd pollsd -# define fd socket -#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: (of_time_interval_t)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 DELETED src/OFStreamObserver_select.h Index: src/OFStreamObserver_select.h ================================================================== --- src/OFStreamObserver_select.h +++ src/OFStreamObserver_select.h @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 - * 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 - * 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. - */ - -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS -#endif -#ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS -#endif - -#ifdef HAVE_SYS_SELECT_H -# include -#endif - -#import "OFStreamObserver.h" - -@interface OFStreamObserver_select: OFStreamObserver -{ - fd_set _readFDs, _writeFDs, _exceptFDs; -} -@end DELETED src/OFStreamObserver_select.m Index: src/OFStreamObserver_select.m ================================================================== --- src/OFStreamObserver_select.m +++ src/OFStreamObserver_select.m @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 - * 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 - * 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 -#include - -#include - -#import "OFStreamObserver.h" -#import "OFStreamObserver+Private.h" -#import "OFStreamObserver_select.h" -#import "OFStream.h" -#import "OFArray.h" - -#import "autorelease.h" -#import "macros.h" -#import "socket_helpers.h" - -@implementation OFStreamObserver_select -- init -{ - self = [super init]; - - FD_ZERO(&_readFDs); - FD_ZERO(&_writeFDs); - - FD_SET(_cancelFD[0], &_readFDs); - - return self; -} - -- (void)OF_addFileDescriptorForReading: (int)fd -{ - FD_SET(fd, &_readFDs); - FD_SET(fd, &_exceptFDs); -} - -- (void)OF_addFileDescriptorForWriting: (int)fd -{ - FD_SET(fd, &_writeFDs); - FD_SET(fd, &_exceptFDs); -} - -- (void)OF_removeFileDescriptorForReading: (int)fd -{ - FD_CLR(fd, &_readFDs); - - if (!FD_ISSET(fd, &_writeFDs)) - FD_CLR(fd, &_exceptFDs); -} - -- (void)OF_removeFileDescriptorForWriting: (int)fd -{ - FD_CLR(fd, &_writeFDs); - - if (!FD_ISSET(fd, &_readFDs)) - FD_CLR(fd, &_exceptFDs); -} - -- (bool)observeForTimeInterval: (of_time_interval_t)timeInterval -{ - void *pool = objc_autoreleasePoolPush(); - OFStream **objects; - fd_set readFDs; - fd_set writeFDs; - fd_set exceptFDs; - struct timeval timeout; - size_t i, count, realEvents = 0; - - [self OF_processQueue]; - - if ([self OF_processCache]) { - objc_autoreleasePoolPop(pool); - return true; - } - - objc_autoreleasePoolPop(pool); - -#ifdef FD_COPY - FD_COPY(&_readFDs, &readFDs); - FD_COPY(&_writeFDs, &writeFDs); - FD_COPY(&_exceptFDs, &exceptFDs); -#else - readFDs = _readFDs; - writeFDs = _writeFDs; - exceptFDs = _exceptFDs; -#endif - - /* - * We cast to int before assigning to tv_usec in order to avoid a - * warning with Apple GCC on PPC. POSIX defines this as suseconds_t, - * however, this is not available on Win32. As an int should always - * satisfy the required range, we just cast to int. - */ - timeout.tv_sec = (time_t)timeInterval; - timeout.tv_usec = (int)lrint((timeInterval - timeout.tv_sec) * 1000); - - if (select((int)_maxFD + 1, &readFDs, &writeFDs, &exceptFDs, - (timeInterval != -1 ? &timeout : NULL)) < 1) - return false; - - if (FD_ISSET(_cancelFD[0], &readFDs)) { - char buffer; -#ifndef _WIN32 - OF_ENSURE(read(_cancelFD[0], &buffer, 1) > 0); -#else - OF_ENSURE(recvfrom(_cancelFD[0], &buffer, 1, 0, NULL, - NULL) > 0); -#endif - } - - objects = [_readStreams objects]; - count = [_readStreams count]; - - for (i = 0; i < count; i++) { - int fd = [objects[i] fileDescriptorForReading]; - - pool = objc_autoreleasePoolPush(); - - if (FD_ISSET(fd, &readFDs)) { - if ([_delegate respondsToSelector: - @selector(streamIsReadyForReading:)]) - [_delegate streamIsReadyForReading: objects[i]]; - - realEvents++; - } - - if (FD_ISSET(fd, &exceptFDs)) { - if ([_delegate respondsToSelector: - @selector(streamDidReceiveException:)]) - [_delegate streamDidReceiveException: - objects[i]]; - - /* - * Prevent calling it twice in case the FD is in both - * sets. - */ - FD_CLR(fd, &exceptFDs); - - realEvents++; - } - - objc_autoreleasePoolPop(pool); - } - - objects = [_writeStreams objects]; - count = [_writeStreams count]; - - for (i = 0; i < count; i++) { - int fd = [objects[i] fileDescriptorForWriting]; - - pool = objc_autoreleasePoolPush(); - - if (FD_ISSET(fd, &writeFDs)) { - if ([_delegate respondsToSelector: - @selector(streamIsReadyForWriting:)]) - [_delegate streamIsReadyForWriting: objects[i]]; - - realEvents++; - } - - if (FD_ISSET(fd, &exceptFDs)) { - if ([_delegate respondsToSelector: - @selector(streamDidReceiveException:)]) - [_delegate streamDidReceiveException: - objects[i]]; - - realEvents++; - } - - objc_autoreleasePoolPop(pool); - } - - if (realEvents == 0) - return false; - - return true; -} -@end Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -55,11 +55,11 @@ #ifdef OF_HAVE_SOCKETS # import "OFStreamSocket.h" # import "OFTCPSocket.h" # import "OFUDPSocket.h" # import "OFTLSSocket.h" -# import "OFStreamObserver.h" +# import "OFKernelEventObserver.h" # import "OFHTTPRequest.h" # import "OFHTTPResponse.h" # import "OFHTTPClient.h" # import "OFHTTPServer.h"