Differences From Artifact [f76ad8e6f6]:
- File
src/OFRunLoop.m
— part of check-in
[ab89c47f42]
at
2019-01-07 22:59:58
on branch trunk
— Partially fix sockets on Nintendo 3DS/Wii
This does not fully fix it yet, but at least the socket tests in the
test suite pass on 3DS now. (user: js, size: 28332) [annotate] [blame] [check-ins using]
To Artifact [355a023a1d]:
- File src/OFRunLoop.m — part of check-in [bceb7ed4c9] at 2019-03-08 00:35:48 on branch trunk — Use dot syntax (user: js, size: 28279) [annotate] [blame] [check-ins using]
︙ | ︙ | |||
179 180 181 182 183 184 185 | self = [super init]; @try { _timersQueue = [[OFSortedList alloc] init]; #if defined(OF_HAVE_SOCKETS) _kernelEventObserver = [[OFKernelEventObserver alloc] init]; | | | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | self = [super init]; @try { _timersQueue = [[OFSortedList alloc] init]; #if defined(OF_HAVE_SOCKETS) _kernelEventObserver = [[OFKernelEventObserver alloc] init]; _kernelEventObserver.delegate = self; _readQueues = [[OFMutableDictionary alloc] init]; _writeQueues = [[OFMutableDictionary alloc] init]; #elif defined(OF_HAVE_THREADS) _condition = [[OFCondition alloc] init]; #endif } @catch (id e) { |
︙ | ︙ | |||
221 222 223 224 225 226 227 | */ OFList OF_GENERIC(OF_KINDOF(OFRunLoop_ReadQueueItem *)) *queue = [[_readQueues objectForKey: object] retain]; assert(queue != nil); @try { | | | | | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | */ OFList OF_GENERIC(OF_KINDOF(OFRunLoop_ReadQueueItem *)) *queue = [[_readQueues objectForKey: object] retain]; assert(queue != nil); @try { if (![queue.firstObject handleObject: object]) { of_list_object_t *listObject = queue.firstListObject; /* * The handler might have called -[cancelAsyncRequests] * so that our queue is now empty, in which case we * should do nothing. */ if (listObject != NULL) { /* * Make sure we keep the target until after we * are done removing the object. The reason for * this is that the target might call * -[cancelAsyncRequests] in its dealloc. */ [[listObject->object retain] autorelease]; [queue removeListObject: listObject]; if (queue.count == 0) { [_kernelEventObserver removeObjectForReading: object]; [_readQueues removeObjectForKey: object]; } } } |
︙ | ︙ | |||
264 265 266 267 268 269 270 | * handler called -[cancelAsyncRequests]. */ OFList *queue = [[_writeQueues objectForKey: object] retain]; assert(queue != nil); @try { | | | | | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | * handler called -[cancelAsyncRequests]. */ OFList *queue = [[_writeQueues objectForKey: object] retain]; assert(queue != nil); @try { if (![queue.firstObject handleObject: object]) { of_list_object_t *listObject = queue.firstListObject; /* * The handler might have called -[cancelAsyncRequests] * so that our queue is now empty, in which case we * should do nothing. */ if (listObject != NULL) { /* * Make sure we keep the target until after we * are done removing the object. The reason for * this is that the target might call * -[cancelAsyncRequests] in its dealloc. */ [[listObject->object retain] autorelease]; [queue removeListObject: listObject]; if (queue.count == 0) { [_kernelEventObserver removeObjectForWriting: object]; [_writeQueues removeObjectForKey: object]; } } } |
︙ | ︙ | |||
459 460 461 462 463 464 465 | @end @implementation OFRunLoop_WriteDataQueueItem - (bool)handleObject: (id)object { size_t length; id exception = nil; | | | | 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 | @end @implementation OFRunLoop_WriteDataQueueItem - (bool)handleObject: (id)object { size_t length; id exception = nil; size_t dataLength = _data.count * _data.itemSize; OFData *newData, *oldData; @try { const char *dataItems = _data.items; length = [object writeBuffer: dataItems + _writtenLength length: dataLength - _writtenLength]; } @catch (id e) { length = 0; exception = e; } |
︙ | ︙ | |||
716 717 718 719 720 721 722 | @implementation OFRunLoop_UDPSendQueueItem - (bool)handleObject: (id)object { id exception = nil; OFData *newData, *oldData; @try { | | | | 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 | @implementation OFRunLoop_UDPSendQueueItem - (bool)handleObject: (id)object { id exception = nil; OFData *newData, *oldData; @try { [object sendBuffer: _data.items length: _data.count * _data.itemSize receiver: &_receiver]; } @catch (id e) { exception = e; } # ifdef OF_HAVE_BLOCKS if (_block != NULL) { |
︙ | ︙ | |||
782 783 784 785 786 787 788 | { return mainRunLoop; } + (OFRunLoop *)currentRunLoop { #ifdef OF_HAVE_THREADS | | | 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 | { return mainRunLoop; } + (OFRunLoop *)currentRunLoop { #ifdef OF_HAVE_THREADS return [OFThread currentThread].runLoop; #else return [self mainRunLoop]; #endif } + (void)of_setMainRunLoop: (OFRunLoop *)runLoop { |
︙ | ︙ | |||
805 806 807 808 809 810 811 | create: true]; \ OFList *queue = [state->_readQueues objectForKey: object]; \ type *queueItem; \ \ if (queue == nil) { \ queue = [OFList list]; \ [state->_readQueues setObject: queue \ | | | | | 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 | create: 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]; \ OFRunLoop_State *state = [runLoop of_stateForMode: mode \ create: 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]; \ \ |
︙ | ︙ | |||
1034 1035 1036 1037 1038 1039 1040 | create: false]; OFList *queue; if (state == nil) return; if ((queue = [state->_writeQueues objectForKey: object]) != nil) { | | | | 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 | create: false]; OFList *queue; if (state == nil) return; if ((queue = [state->_writeQueues objectForKey: object]) != nil) { assert(queue.count > 0); /* * Clear the queue now, in case this has been called from a * handler, as otherwise, we'd do the cleanups below twice. */ [queue removeAllObjects]; [state->_kernelEventObserver removeObjectForWriting: object]; [state->_writeQueues removeObjectForKey: object]; } if ((queue = [state->_readQueues objectForKey: object]) != nil) { assert(queue.count > 0); /* * Clear the queue now, in case this has been called from a * handler, as otherwise, we'd do the cleanups below twice. */ [queue removeAllObjects]; |
︙ | ︙ | |||
1178 1179 1180 1181 1182 1183 1184 | #ifdef OF_HAVE_THREADS [state->_timersQueueMutex lock]; @try { #endif of_list_object_t *iter; | | | 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 | #ifdef OF_HAVE_THREADS [state->_timersQueueMutex lock]; @try { #endif of_list_object_t *iter; for (iter = state->_timersQueue.firstListObject; iter != NULL; iter = iter->next) { if ([iter->object isEqual: timer]) { [state->_timersQueue removeListObject: iter]; break; } } #ifdef OF_HAVE_THREADS |
︙ | ︙ | |||
1202 1203 1204 1205 1206 1207 1208 | } - (void)runUntilDate: (OFDate *)deadline { _stop = false; while (!_stop && | | | 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 | } - (void)runUntilDate: (OFDate *)deadline { _stop = false; while (!_stop && (deadline == nil || deadline.timeIntervalSinceNow >= 0)) [self runMode: of_run_loop_mode_default beforeDate: deadline]; } - (void)runMode: (of_run_loop_mode_t)mode beforeDate: (OFDate *)deadline { |
︙ | ︙ | |||
1230 1231 1232 1233 1234 1235 1236 | OFTimer *timer; #ifdef OF_HAVE_THREADS [state->_timersQueueMutex lock]; @try { #endif of_list_object_t *listObject = | | | | | | 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 | OFTimer *timer; #ifdef OF_HAVE_THREADS [state->_timersQueueMutex lock]; @try { #endif of_list_object_t *listObject = state->_timersQueue.firstListObject; if (listObject != NULL && [listObject->object fireDate].timeIntervalSinceNow <= 0) { timer = [[listObject->object retain] autorelease]; [state->_timersQueue removeListObject: listObject]; [timer of_setInRunLoop: nil mode: nil]; } else break; #ifdef OF_HAVE_THREADS } @finally { [state->_timersQueueMutex unlock]; } #endif if (timer.valid) { [timer fire]; return; } } #ifdef OF_HAVE_THREADS [state->_timersQueueMutex lock]; |
︙ | ︙ | |||
1273 1274 1275 1276 1277 1278 1279 | #endif /* Watch for I/O events until the next timer is due */ if (nextTimer != nil || deadline != nil) { of_time_interval_t timeout; if (nextTimer != nil && deadline == nil) | | | | | | | | 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 | #endif /* Watch for I/O events until the next timer is due */ if (nextTimer != nil || deadline != nil) { of_time_interval_t timeout; if (nextTimer != nil && deadline == nil) timeout = nextTimer.timeIntervalSinceNow; else if (nextTimer == nil && deadline != nil) timeout = deadline.timeIntervalSinceNow; else timeout = [nextTimer earlierDate: deadline] .timeIntervalSinceNow; if (timeout < 0) timeout = 0; #if defined(OF_HAVE_SOCKETS) @try { [state->_kernelEventObserver observeForTimeInterval: timeout]; } @catch (OFObserveFailedException *e) { if (e.errNo != EINTR) @throw e; } #elif defined(OF_HAVE_THREADS) [state->_condition lock]; [state->_condition waitForTimeInterval: timeout]; [state->_condition unlock]; #else [OFThread sleepForTimeInterval: timeout]; #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 (OFObserveFailedException *e) { if (e.errNo != EINTR) @throw e; } #elif defined(OF_HAVE_THREADS) [state->_condition lock]; [state->_condition wait]; [state->_condition unlock]; #else |
︙ | ︙ |