ObjFW  Check-in [7460d2ccd8]

Overview
Comment:Delay socket initialization as long as possible

On game consoles, initializing sockets takes a significant amount of
time. When not delaying socket initializing, that time is spent during
startup even when the application might never use sockets.

Worse yet, on Amiga, sockets might not be available at all and the
application will fail to start up, even when the application might never
use sockets.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 7460d2ccd8729705ef3591fd4ff4763b7e4774b023d6b542191d5cb19e261538
User & Date: js on 2024-08-17 17:30:51
Other Links: manifest | tags
References
2024-08-17
17:33 Fixed ticket [31d9fb57cc]: OFRunLoop: Only use OFKernelEventObserver if we have sockets plus 4 other changes artifact: 2b95ba41c1 user: js
Context
2024-08-17
21:13
tests: Fix symlinking libobjfwhid.so.$major.$minor check-in: a791241853 user: js tags: trunk
17:30
Delay socket initialization as long as possible check-in: 7460d2ccd8 user: js tags: trunk
10:46
README.md: Move most of the content to the wiki check-in: ba6455ba6f user: js tags: trunk
Changes

Modified src/OFDNSResolver.m from [152a6730bc] to [d30e19048e].

616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644




645
646
647
648
649
650
651
616
617
618
619
620
621
622












623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643







-
-
-
-
-
-
-
-
-
-
-
-










+
+
+
+







	[_cancelTimer release];

	[super dealloc];
}
@end

@implementation OFDNSResolver
#ifdef OF_AMIGAOS
+ (void)initialize
{
	if (self != [OFDNSResolver class])
		return;

	if (!_OFSocketInit())
		@throw [OFInitializationFailedException
		    exceptionWithClass: self];
}
#endif

+ (instancetype)resolver
{
	return [[[self alloc] init] autorelease];
}

- (instancetype)init
{
	self = [super init];

	@try {
		if (!_OFSocketInit())
			@throw [OFInitializationFailedException
			    exceptionWithClass: self.class];

		_settings = [[OFDNSResolverSettings alloc] init];
		_queries = [[OFMutableDictionary alloc] init];
		_TCPQueries = [[OFMutableDictionary alloc] init];
		_cache = [[OFMutableDictionary alloc] init];

		[_settings reload];
	} @catch (id e) {

Modified src/OFDatagramSocket.m from [9ad188ca92] to [009edc504e].

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82




83
84
85
86
87
88
89
51
52
53
54
55
56
57










58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83







-
-
-
-
-
-
-
-
-
-















+
+
+
+







#if defined(OF_AMIGAOS) && !defined(UNIQUE_ID)
# define UNIQUE_ID -1
#endif

@implementation OFDatagramSocket
@synthesize delegate = _delegate;

+ (void)initialize
{
	if (self != [OFDatagramSocket class])
		return;

	if (!_OFSocketInit())
		@throw [OFInitializationFailedException
		    exceptionWithClass: self];
}

+ (instancetype)socket
{
	return [[[self alloc] init] autorelease];
}

- (instancetype)init
{
	self = [super init];

	@try {
		if (self.class == [OFDatagramSocket class]) {
			[self doesNotRecognizeSelector: _cmd];
			abort();
		}

		if (!_OFSocketInit())
			@throw [OFInitializationFailedException
			    exceptionWithClass: self.class];

		_socket = OFInvalidSocketHandle;
#ifdef OF_HAVE_AMIGAOS
		_socketID = -1;
#endif
		_canBlock = true;
	} @catch (id e) {
		[self release];

Modified src/OFKernelEventObserver.m from [370fb61e6e] to [6e35982883].

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
57
58
59
60
61
62
63










64
65
66
67
68
69
70







-
-
-
-
-
-
-
-
-
-








@implementation OFKernelEventObserver
@synthesize delegate = _delegate;
#ifdef OF_AMIGAOS
@synthesize execSignalMask = _execSignalMask;
#endif

+ (void)initialize
{
	if (self != [OFKernelEventObserver class])
		return;

	if (!_OFSocketInit())
		@throw [OFInitializationFailedException
		    exceptionWithClass: self];
}

+ (instancetype)observer
{
	return [[[self alloc] init] autorelease];
}

+ (instancetype)alloc
{
100
101
102
103
104
105
106




107
108
109
110
111
112
113
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107







+
+
+
+








	@try {
#if !defined(OF_HAVE_PIPE) && !defined(OF_WII) && !defined(OF_AMIGAOS) && \
    !defined(OF_NINTENDO_3DS)
		socklen_t cancelAddrLen;
#endif

		if (!_OFSocketInit())
			@throw [OFInitializationFailedException
			    exceptionWithClass: self.class];

		_readObjects = [[OFMutableArray alloc] init];
		_writeObjects = [[OFMutableArray alloc] init];

#if defined(OF_HAVE_PIPE) && !defined(OF_AMIGAOS)
		if (pipe(_cancelFD))
			@throw [OFInitializationFailedException
			    exceptionWithClass: self.class];

Modified src/OFRunLoop.m from [fbc3913f1e] to [7691af0c6a].

57
58
59
60
61
62
63
64

65
66

67

68
69
70
71
72
73
74
57
58
59
60
61
62
63

64
65
66
67

68
69
70
71
72
73
74
75







-
+


+
-
+







#endif
{
@public
	OFSortedList OF_GENERIC(OFTimer *) *_timersQueue;
#ifdef OF_HAVE_THREADS
	OFMutex *_timersQueueMutex;
#endif
#if defined(OF_HAVE_SOCKETS)
#ifdef OF_HAVE_SOCKETS
	OFKernelEventObserver *_kernelEventObserver;
	OFMutableDictionary *_readQueues, *_writeQueues;
#endif
#elif defined(OF_HAVE_THREADS)
#ifdef OF_HAVE_THREADS
	OFCondition *_condition;
# ifdef OF_AMIGAOS
	ULONG _execSignalMask;
# endif
#endif
#ifdef OF_AMIGAOS
	OFMutableData *_execSignals;
235
236
237
238
239
240
241
242

243
244
245
246
247

248

249
250
251
252
253
254
255
236
237
238
239
240
241
242

243



244
245
246

247
248
249
250
251
252
253
254







-
+
-
-
-


+
-
+








	@try {
		_timersQueue = [[OFSortedList alloc] init];
#ifdef OF_HAVE_THREADS
		_timersQueueMutex = [[OFMutex alloc] init];
#endif

#if defined(OF_HAVE_SOCKETS)
#ifdef OF_HAVE_SOCKETS
		_kernelEventObserver = [[OFKernelEventObserver alloc] init];
		_kernelEventObserver.delegate = self;

		_readQueues = [[OFMutableDictionary alloc] init];
		_writeQueues = [[OFMutableDictionary alloc] init];
#endif
#elif defined(OF_HAVE_THREADS)
#if defined(OF_HAVE_THREADS)
		_condition = [[OFCondition alloc] init];
#endif
#ifdef OF_AMIGAOS
		_execSignals = [[OFMutableData alloc]
		    initWithItemSize: sizeof(ULONG)];
		_execSignalsTargets = [[OFMutableArray alloc] init];
		_execSignalsSelectors = [[OFMutableData alloc]
268
269
270
271
272
273
274
275

276
277
278

279

280
281
282
283
284
285
286
267
268
269
270
271
272
273

274
275
276
277
278

279
280
281
282
283
284
285
286







-
+



+
-
+








- (void)dealloc
{
	[_timersQueue release];
#ifdef OF_HAVE_THREADS
	[_timersQueueMutex release];
#endif
#if defined(OF_HAVE_SOCKETS)
#ifdef OF_HAVE_SOCKETS
	[_kernelEventObserver release];
	[_readQueues release];
	[_writeQueues release];
#endif
#elif defined(OF_HAVE_THREADS)
#ifdef OF_HAVE_THREADS
	[_condition release];
#endif
#ifdef OF_AMIGAOS
	[_execSignals release];
	[_execSignalsTargets release];
	[_execSignalsSelectors release];
# ifdef OF_HAVE_THREADS
1162
1163
1164
1165
1166
1167
1168
1169


1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186








1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
















1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
















1230
1231
1232
1233



1234
1235
1236
1237
1238
1239
1240
1162
1163
1164
1165
1166
1167
1168

1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
















1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
















1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239



1240
1241
1242
1243
1244
1245
1246
1247
1248
1249







-
+
+

















+
+
+
+
+
+
+
+










-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
-
+
+
+








+ (void)of_setMainRunLoop: (OFRunLoop *)runLoop
{
	mainRunLoop = [runLoop retain];
}

static OFRunLoopState *
stateForMode(OFRunLoop *self, OFRunLoopMode mode, bool create)
stateForMode(OFRunLoop *self, OFRunLoopMode mode, bool create,
    bool createObserver)
{
	OFRunLoopState *state;

#ifdef OF_HAVE_THREADS
	[self->_statesMutex lock];
	@try {
#endif
		state = [self->_states objectForKey: mode];

		if (create && state == nil) {
			state = [[OFRunLoopState alloc] init];
			@try {
				[self->_states setObject: state forKey: mode];
			} @finally {
				[state release];
			}
		}

#ifdef OF_HAVE_SOCKETS
		if (createObserver && state->_kernelEventObserver == nil) {
			state->_kernelEventObserver =
			    [[OFKernelEventObserver alloc] init];
			state->_kernelEventObserver.delegate = state;
		}
#endif
#ifdef OF_HAVE_THREADS
	} @finally {
		[self->_statesMutex unlock];
	}
#endif

	return state;
}

#ifdef OF_HAVE_SOCKETS
# define NEW_READ(type, object, mode)					\
	void *pool = objc_autoreleasePoolPush();			\
	OFRunLoop *runLoop = [self currentRunLoop];			\
	OFRunLoopState *state = stateForMode(runLoop, mode, true);	\
	OFList *queue = [state->_readQueues objectForKey: object];	\
	type *queueItem;						\
									\
	if (queue == nil) {						\
		queue = [OFList list];					\
		[state->_readQueues setObject: queue forKey: object];	\
	}								\
									\
	if (queue.count == 0)						\
		[state->_kernelEventObserver				\
		    addObjectForReading: object];			\
									\
# define NEW_READ(type, object, mode)					 \
	void *pool = objc_autoreleasePoolPush();			 \
	OFRunLoop *runLoop = [self currentRunLoop];			 \
	OFRunLoopState *state = stateForMode(runLoop, mode, true, true); \
	OFList *queue = [state->_readQueues objectForKey: object];	 \
	type *queueItem;						 \
									 \
	if (queue == nil) {						 \
		queue = [OFList list];					 \
		[state->_readQueues setObject: queue forKey: object];	 \
	}								 \
									 \
	if (queue.count == 0)						 \
		[state->_kernelEventObserver				 \
		    addObjectForReading: object];			 \
									 \
	queueItem = [[[type alloc] init] autorelease];
# define NEW_WRITE(type, object, mode)					\
	void *pool = objc_autoreleasePoolPush();			\
	OFRunLoop *runLoop = [self currentRunLoop];			\
	OFRunLoopState *state = stateForMode(runLoop, mode, true);	\
	OFList *queue = [state->_writeQueues objectForKey: object];	\
	type *queueItem;						\
									\
	if (queue == nil) {						\
		queue = [OFList list];					\
		[state->_writeQueues setObject: queue forKey: object];	\
	}								\
									\
	if (queue.count == 0)						\
		[state->_kernelEventObserver				\
		    addObjectForWriting: object];			\
									\
# define NEW_WRITE(type, object, mode)					 \
	void *pool = objc_autoreleasePoolPush();			 \
	OFRunLoop *runLoop = [self currentRunLoop];			 \
	OFRunLoopState *state = stateForMode(runLoop, mode, true, true); \
	OFList *queue = [state->_writeQueues objectForKey: object];	 \
	type *queueItem;						 \
									 \
	if (queue == nil) {						 \
		queue = [OFList list];					 \
		[state->_writeQueues setObject: queue forKey: object];	 \
	}								 \
									 \
	if (queue.count == 0)						 \
		[state->_kernelEventObserver				 \
		    addObjectForWriting: object];			 \
									 \
	queueItem = [[[type alloc] init] autorelease];
#define QUEUE_ITEM							\
	[queue appendObject: queueItem];				\
									\
#define QUEUE_ITEM							 \
	[queue appendObject: queueItem];				 \
									 \
	objc_autoreleasePoolPop(pool);

+ (void)of_addAsyncReadForStream: (OFStream <OFReadyForReadingObserving> *)
				      stream
			  buffer: (void *)buffer
			  length: (size_t)length
			    mode: (OFRunLoopMode)mode
1497
1498
1499
1500
1501
1502
1503
1504

1505
1506
1507
1508
1509
1510
1511
1506
1507
1508
1509
1510
1511
1512

1513
1514
1515
1516
1517
1518
1519
1520







-
+







# undef NEW_WRITE
# undef QUEUE_ITEM

+ (void)of_cancelAsyncRequestsForObject: (id)object mode: (OFRunLoopMode)mode
{
	void *pool = objc_autoreleasePoolPush();
	OFRunLoop *runLoop = [self currentRunLoop];
	OFRunLoopState *state = stateForMode(runLoop, mode, false);
	OFRunLoopState *state = stateForMode(runLoop, mode, false, false);
	OFList *queue;

	if (state == nil)
		return;

	if ((queue = [state->_writeQueues objectForKey: object]) != nil) {
		OFAssert(queue.count > 0);
1577
1578
1579
1580
1581
1582
1583
1584

1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599

1600

1601

1602
1603
1604
1605
1606
1607
1608

1609
1610
1611
1612
1613
1614
1615
1586
1587
1588
1589
1590
1591
1592

1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607

1608
1609
1610

1611
1612
1613
1614
1615
1616
1617

1618
1619
1620
1621
1622
1623
1624
1625







-
+














-
+

+
-
+






-
+







- (void)addTimer: (OFTimer *)timer
{
	[self addTimer: timer forMode: OFDefaultRunLoopMode];
}

- (void)addTimer: (OFTimer *)timer forMode: (OFRunLoopMode)mode
{
	OFRunLoopState *state = stateForMode(self, mode, true);
	OFRunLoopState *state = stateForMode(self, mode, true, false);

#ifdef OF_HAVE_THREADS
	[state->_timersQueueMutex lock];
	@try {
#endif
		[state->_timersQueue insertObject: timer];
#ifdef OF_HAVE_THREADS
	} @finally {
		[state->_timersQueueMutex unlock];
	}
#endif

	[timer of_setInRunLoop: self mode: mode];

#if defined(OF_HAVE_SOCKETS)
#ifdef OF_HAVE_SOCKETS
	[state->_kernelEventObserver cancel];
#endif
#elif defined(OF_HAVE_THREADS)
#ifdef OF_HAVE_THREADS
	[state->_condition signal];
#endif
}

- (void)of_removeTimer: (OFTimer *)timer forMode: (OFRunLoopMode)mode
{
	OFRunLoopState *state = stateForMode(self, mode, false);
	OFRunLoopState *state = stateForMode(self, mode, false, false);

	/* {} required to avoid -Wmisleading-indentation false positive. */
	if (state == nil) {
		return;
	}

#ifdef OF_HAVE_THREADS
1640
1641
1642
1643
1644
1645
1646
1647

1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658

1659

1660
1661
1662
1663
1664
1665
1666
1667
1668

1669

1670

1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690

1691
1692
1693
1694
1695
1696
1697
1650
1651
1652
1653
1654
1655
1656

1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669

1670
1671
1672
1673
1674
1675
1676
1677
1678

1679
1680
1681

1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701

1702
1703
1704
1705
1706
1707
1708
1709







-
+











+
-
+








-
+

+
-
+



















-
+







}

- (void)addExecSignal: (ULONG)signal
	      forMode: (OFRunLoopMode)mode
	       target: (id)target
	     selector: (SEL)selector
{
	OFRunLoopState *state = stateForMode(self, mode, true);
	OFRunLoopState *state = stateForMode(self, mode, true, false);

# ifdef OF_HAVE_THREADS
	[state->_execSignalsMutex lock];
	@try {
# endif
		[state->_execSignals addItem: &signal];
		[state->_execSignalsTargets addObject: target];
		[state->_execSignalsSelectors addItem: &selector];

# ifdef OF_HAVE_SOCKETS
		state->_kernelEventObserver.execSignalMask |= (1ul << signal);
# endif
# elif defined(OF_HAVE_THREADS)
# ifdef OF_HAVE_THREADS
		state->_execSignalMask |= (1ul << signal);
# endif
# ifdef OF_HAVE_THREADS
	} @finally {
		[state->_execSignalsMutex unlock];
	}
# endif

# if defined(OF_HAVE_SOCKETS)
# ifdef OF_HAVE_SOCKETS
	[state->_kernelEventObserver cancel];
# endif
# elif defined(OF_HAVE_THREADS)
# ifdef OF_HAVE_THREADS
	[state->_condition signal];
# endif
}

- (void)removeExecSignal: (ULONG)signal
		  target: (id)target
		selector: (SEL)selector
{
	[self removeExecSignal: signal
		       forMode: OFDefaultRunLoopMode
			target: target
		      selector: selector];
}

- (void)removeExecSignal: (ULONG)signal
		 forMode: (OFRunLoopMode)mode
		  target: (id)target
		selector: (SEL)selector
{
	OFRunLoopState *state = stateForMode(self, mode, false);
	OFRunLoopState *state = stateForMode(self, mode, false, false);

	if (state == nil)
		return;

# ifdef OF_HAVE_THREADS
	[state->_execSignalsMutex lock];
	@try {
1715
1716
1717
1718
1719
1720
1721

1722

1723
1724
1725
1726
1727
1728
1729
1730
1731

1732

1733

1734
1735
1736
1737
1738
1739
1740
1727
1728
1729
1730
1731
1732
1733
1734

1735
1736
1737
1738
1739
1740
1741
1742
1743

1744
1745
1746

1747
1748
1749
1750
1751
1752
1753
1754







+
-
+








-
+

+
-
+







				found = true;
			} else
				newMask |= (1ul << signals[i]);
		}

# ifdef OF_HAVE_SOCKETS
		state->_kernelEventObserver.execSignalMask = newMask;
# endif
# elif defined(OF_HAVE_THREADS)
# ifdef OF_HAVE_THREADS
		state->_execSignalMask = newMask;
# endif
# ifdef OF_HAVE_THREADS
	} @finally {
		[state->_execSignalsMutex unlock];
	}
# endif

# if defined(OF_HAVE_SOCKETS)
# ifdef OF_HAVE_SOCKETS
	[state->_kernelEventObserver cancel];
# endif
# elif defined(OF_HAVE_THREADS)
# ifdef OF_HAVE_THREADS
	[state->_condition signal];
# endif
}
#endif

- (void)run
{
1750
1751
1752
1753
1754
1755
1756
1757

1758
1759
1760
1761
1762
1763
1764
1765

1766
1767
1768
1769
1770
1771
1772
1764
1765
1766
1767
1768
1769
1770

1771
1772
1773
1774
1775
1776
1777
1778

1779
1780
1781
1782
1783
1784
1785
1786







-
+







-
+







		[self runMode: OFDefaultRunLoopMode beforeDate: deadline];
}

- (void)runMode: (OFRunLoopMode)mode beforeDate: (OFDate *)deadline
{
	void *pool = objc_autoreleasePoolPush();
	OFRunLoopMode previousMode = _currentMode;
	OFRunLoopState *state = stateForMode(self, mode, false);
	OFRunLoopState *state = stateForMode(self, mode, false, false);

	if (state == nil)
		return;

	_currentMode = mode;
	@try {
		OFDate *nextTimer;
#if defined(OF_AMIGAOS) && !defined(OF_HAVE_SOCKETS) && defined(OF_HAVE_THREADS)
#if defined(OF_AMIGAOS) && defined(OF_HAVE_THREADS)
		ULONG signalMask;
#endif

		for (;;) {
			OFTimer *timer;

#ifdef OF_HAVE_THREADS
1821
1822
1823
1824
1825
1826
1827
1828

1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
















1841
1842
1843
1844
1845
1846







1847
1848


1849
1850

1851
1852




1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868













1869
1870
1871
1872
1873
1874






1875
1876

1877
1878

1879
1880




1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892


1893
1894
1895
1896
1897
1898
1899

1900

1901

1902
1903
1904
1905
1835
1836
1837
1838
1839
1840
1841

1842
1843











1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860





1861
1862
1863
1864
1865
1866
1867
1868

1869
1870
1871

1872
1873

1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884









1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898





1899
1900
1901
1902
1903
1904
1905

1906
1907

1908
1909

1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924

1925
1926
1927
1928
1929
1930
1931
1932

1933
1934
1935

1936
1937
1938
1939
1940







-
+

-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
-
-
-
+
+
+
+
+
+
+

-
+
+

-
+

-
+
+
+
+







-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
-
-
-
+
+
+
+
+
+

-
+

-
+

-
+
+
+
+











-
+
+






-
+

+
-
+




				timeout = nextTimer.timeIntervalSinceNow;
			else if (nextTimer == nil && deadline != nil)
				timeout = deadline.timeIntervalSinceNow;
			else
				timeout = [nextTimer earlierDate: deadline]
				    .timeIntervalSinceNow;

			if (timeout < 0)
			if (timeout < 0) {
				timeout = 0;

#if defined(OF_HAVE_SOCKETS)
			@try {
				[state->_kernelEventObserver
				    observeForTimeInterval: timeout];
			} @catch (OFObserveKernelEventsFailedException *e) {
				if (e.errNo != EINTR)
					@throw e;
			}
#elif defined(OF_HAVE_THREADS)
			[state->_condition lock];
			}

#ifdef OF_HAVE_SOCKETS
			if (state->_kernelEventObserver != nil) {
				@try {
					[state->_kernelEventObserver
					    observeForTimeInterval: timeout];
				} @catch (OFObserveKernelEventsFailedException
				    *e) {
					if (e.errNo != EINTR)
						@throw e;
				}
			} else {
#endif
#ifdef OF_HAVE_THREADS
				[state->_condition lock];
# ifdef OF_AMIGAOS
			signalMask = state->_execSignalMask;
			[state->_condition waitForTimeInterval: timeout
						  orExecSignal: &signalMask];
			if (signalMask != 0)
				[state execSignalWasReceived: signalMask];
				signalMask = state->_execSignalMask;
				[state->_condition
				    waitForTimeInterval: timeout
					   orExecSignal: &signalMask];
				if (signalMask != 0)
					[state
					    execSignalWasReceived: signalMask];
# else
			[state->_condition waitForTimeInterval: timeout];
				[state->_condition
				    waitForTimeInterval: timeout];
# endif
			[state->_condition unlock];
				[state->_condition unlock];
#else
			[OFThread sleepForTimeInterval: timeout];
				[OFThread sleepForTimeInterval: timeout];
#endif
#ifdef OF_HAVE_SOCKETS
			}
#endif
		} else {
			/*
			 * No more timers and no deadline: Just watch for I/O
			 * until we get an event. If a timer is added by
			 * another thread, it cancels the observe.
			 */
#if defined(OF_HAVE_SOCKETS)
			@try {
				[state->_kernelEventObserver observe];
			} @catch (OFObserveKernelEventsFailedException *e) {
				if (e.errNo != EINTR)
					@throw e;
			}
#elif defined(OF_HAVE_THREADS)
			[state->_condition lock];
#ifdef OF_HAVE_SOCKETS
			if (state->_kernelEventObserver != nil) {
				@try {
					[state->_kernelEventObserver observe];
				} @catch (OFObserveKernelEventsFailedException
				    *e) {
					if (e.errNo != EINTR)
						@throw e;
				}
			} else {
#endif
#ifdef OF_HAVE_THREADS
				[state->_condition lock];
# ifdef OF_AMIGAOS
			signalMask = state->_execSignalMask;
			[state->_condition
			    waitForConditionOrExecSignal: &signalMask];
			if (signalMask != 0)
				[state execSignalWasReceived: signalMask];
				signalMask = state->_execSignalMask;
				[state->_condition
				    waitForConditionOrExecSignal: &signalMask];
				if (signalMask != 0)
					[state
					    execSignalWasReceived: signalMask];
# else
			[state->_condition wait];
				[state->_condition wait];
# endif
			[state->_condition unlock];
				[state->_condition unlock];
#else
			[OFThread sleepForTimeInterval: 86400];
				[OFThread sleepForTimeInterval: 86400];
#endif
#ifdef OF_HAVE_SOCKETS
			}
#endif
		}

		objc_autoreleasePoolPop(pool);
	} @finally {
		_currentMode = previousMode;
	}
}

- (void)stop
{
	OFRunLoopState *state = stateForMode(self, OFDefaultRunLoopMode, false);
	OFRunLoopState *state = stateForMode(self, OFDefaultRunLoopMode,
	    false, false);

	_stop = true;

	if (state == nil)
		return;

#if defined(OF_HAVE_SOCKETS)
#ifdef OF_HAVE_SOCKETS
	[state->_kernelEventObserver cancel];
#endif
#elif defined(OF_HAVE_THREADS)
#ifdef OF_HAVE_THREADS
	[state->_condition signal];
#endif
}
@end

Modified src/OFSequencedPacketSocket.m from [93df6d6776] to [494885f162].

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78




79
80
81
82
83
84
85
47
48
49
50
51
52
53










54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79







-
-
-
-
-
-
-
-
-
-















+
+
+
+







#import "OFReadFailedException.h"
#import "OFSetOptionFailedException.h"
#import "OFWriteFailedException.h"

@implementation OFSequencedPacketSocket
@synthesize listening = _listening, delegate = _delegate;

+ (void)initialize
{
	if (self != [OFSequencedPacketSocket class])
		return;

	if (!_OFSocketInit())
		@throw [OFInitializationFailedException
		    exceptionWithClass: self];
}

+ (instancetype)socket
{
	return [[[self alloc] init] autorelease];
}

- (instancetype)init
{
	self = [super init];

	@try {
		if (self.class == [OFSequencedPacketSocket class]) {
			[self doesNotRecognizeSelector: _cmd];
			abort();
		}

		if (!_OFSocketInit())
			@throw [OFInitializationFailedException
			    exceptionWithClass: self.class];

		_socket = OFInvalidSocketHandle;
		_canBlock = true;
	} @catch (id e) {
		[self release];
		@throw e;
	}

Modified src/OFStreamSocket.m from [53c37659e0] to [6bb8a2cf49].

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82




83
84
85
86
87
88
89
51
52
53
54
55
56
57










58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83







-
-
-
-
-
-
-
-
-
-















+
+
+
+







# define UNIQUE_ID -1
#endif

@implementation OFStreamSocket
@dynamic delegate;
@synthesize listening = _listening;

+ (void)initialize
{
	if (self != [OFStreamSocket class])
		return;

	if (!_OFSocketInit())
		@throw [OFInitializationFailedException
		    exceptionWithClass: self];
}

+ (instancetype)socket
{
	return [[[self alloc] init] autorelease];
}

- (instancetype)init
{
	self = [super init];

	@try {
		if (self.class == [OFStreamSocket class]) {
			[self doesNotRecognizeSelector: _cmd];
			abort();
		}

		if (!_OFSocketInit())
			@throw [OFInitializationFailedException
			    exceptionWithClass: self.class];

		_socket = OFInvalidSocketHandle;
#ifdef OF_AMIGAOS
		_socketID = -1;
#endif
	} @catch (id e) {
		[self release];
		@throw e;