@@ -71,9 +71,18 @@ DISPATCH_EXPORT void _dispatch_main_queue_callback_4CF(void);
71
71
72
72
#define AbsoluteTime LARGE_INTEGER
73
73
74
+ #elif DEPLOYMENT_TARGET_LINUX
75
+ #include <dlfcn.h>
76
+ #include <poll.h>
77
+ #include <sys/epoll.h>
78
+ #include <sys/eventfd.h>
79
+ #include <sys/timerfd.h>
80
+
81
+ #define _dispatch_get_main_queue_port_4CF dispatch_get_main_queue_eventfd_np
82
+ #define _dispatch_main_queue_callback_4CF (x ) dispatch_main_queue_drain_np()
74
83
#endif
75
84
76
- #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_IPHONESIMULATOR
85
+ #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_IPHONESIMULATOR || DEPLOYMENT_TARGET_LINUX
77
86
CF_EXPORT pthread_t _CF_pthread_main_thread_np (void );
78
87
#define pthread_main_thread_np () _CF_pthread_main_thread_np()
79
88
#endif
@@ -117,6 +126,13 @@ static pthread_t kNilPthreadT = { nil, nil };
117
126
typedef int kern_return_t ;
118
127
#define KERN_SUCCESS 0
119
128
129
+ #elif DEPLOYMENT_TARGET_LINUX
130
+
131
+ static pthread_t kNilPthreadT = (pthread_t )0 ;
132
+ #define pthreadPointer (a ) ((void*)a)
133
+ typedef int kern_return_t ;
134
+ #define KERN_SUCCESS 0
135
+
120
136
#else
121
137
122
138
static pthread_t kNilPthreadT = (pthread_t )0 ;
@@ -424,6 +440,50 @@ static kern_return_t __CFPortSetRemove(__CFPort port, __CFPortSet portSet) {
424
440
return KERN_SUCCESS ;
425
441
}
426
442
443
+ #elif DEPLOYMENT_TARGET_LINUX
444
+ // eventfd/timerfd descriptor
445
+ typedef int __CFPort ;
446
+ #define CFPORT_NULL -1
447
+ #define MACH_PORT_NULL CFPORT_NULL
448
+
449
+ // epoll file descriptor
450
+ typedef int __CFPortSet ;
451
+ #define CFPORTSET_NULL -1
452
+
453
+ static __CFPort __CFPortAllocate (void ) {
454
+ return eventfd (0 , EFD_CLOEXEC |EFD_NONBLOCK );
455
+ }
456
+
457
+ CF_INLINE void __CFPortFree (__CFPort port ) {
458
+ close (port );
459
+ }
460
+
461
+ CF_INLINE __CFPortSet __CFPortSetAllocate (void ) {
462
+ return epoll_create1 (EPOLL_CLOEXEC );
463
+ }
464
+
465
+ CF_INLINE kern_return_t __CFPortSetInsert (__CFPort port , __CFPortSet portSet ) {
466
+ if (CFPORT_NULL == port ) {
467
+ return -1 ;
468
+ }
469
+ struct epoll_event event ;
470
+ memset (& event , 0 , sizeof (event ));
471
+ event .data .fd = port ;
472
+ event .events = EPOLLIN |EPOLLET ;
473
+
474
+ return epoll_ctl (portSet , EPOLL_CTL_ADD , port , & event );
475
+ }
476
+
477
+ CF_INLINE kern_return_t __CFPortSetRemove (__CFPort port , __CFPortSet portSet ) {
478
+ if (CFPORT_NULL == port ) {
479
+ return -1 ;
480
+ }
481
+ return epoll_ctl (portSet , EPOLL_CTL_DEL , port , NULL );
482
+ }
483
+
484
+ CF_INLINE void __CFPortSetFree (__CFPortSet portSet ) {
485
+ close (portSet );
486
+ }
427
487
#endif
428
488
429
489
#if !defined(__MACTYPES__ ) && !defined(_OS_OSTYPES_H )
@@ -464,6 +524,36 @@ static uint32_t __CFSendTrivialMachMessage(mach_port_t port, uint32_t msg_id, CF
464
524
if (result == MACH_SEND_TIMED_OUT ) mach_msg_destroy (& header );
465
525
return result ;
466
526
}
527
+ #elif DEPLOYMENT_TARGET_LINUX
528
+
529
+ static int mk_timer_create (void ) {
530
+ return timerfd_create (CLOCK_MONOTONIC , TFD_NONBLOCK |TFD_CLOEXEC );
531
+ }
532
+
533
+ static kern_return_t mk_timer_destroy (int timer ) {
534
+ return close (timer );
535
+ }
536
+
537
+ static kern_return_t mk_timer_arm (int timer , int64_t expire_time ) {
538
+ struct itimerspec ts ;
539
+ ts .it_value .tv_sec = expire_time / 1000000000UL ;
540
+ ts .it_value .tv_nsec = expire_time % 1000000000UL ;
541
+
542
+ // Non-repeating timer
543
+ ts .it_interval .tv_sec = 0 ;
544
+ ts .it_interval .tv_nsec = 0 ;
545
+
546
+ return timerfd_settime (timer , TFD_TIMER_ABSTIME , & ts , NULL );
547
+ }
548
+
549
+ static kern_return_t mk_timer_cancel (int timer , const void * unused ) {
550
+ return mk_timer_arm (timer , 0 );
551
+ }
552
+
553
+ CF_INLINE int64_t __CFUInt64ToAbsoluteTime (int64_t x ) {
554
+ return x ;
555
+ }
556
+
467
557
#elif DEPLOYMENT_TARGET_WINDOWS
468
558
469
559
static HANDLE mk_timer_create (void ) {
@@ -547,7 +637,7 @@ struct __CFRunLoopMode {
547
637
Boolean _dispatchTimerArmed ;
548
638
#endif
549
639
#if USE_MK_TIMER_TOO
550
- mach_port_t _timerPort ;
640
+ __CFPort _timerPort ;
551
641
Boolean _mkTimerArmed ;
552
642
#endif
553
643
#if DEPLOYMENT_TARGET_WINDOWS
@@ -2256,6 +2346,94 @@ static Boolean __CFRunLoopServiceMachPort(mach_port_name_t port, mach_msg_header
2256
2346
return false;
2257
2347
}
2258
2348
2349
+ #elif DEPLOYMENT_TARGET_LINUX
2350
+
2351
+ #define TIMEOUT_INFINITY UINT64_MAX
2352
+
2353
+ static int __CFPollFileDescriptors (struct pollfd * fds , nfds_t nfds , uint64_t timeout ) {
2354
+ uint64_t elapsed = 0 ;
2355
+ uint64_t start = mach_absolute_time ();
2356
+ int result = 0 ;
2357
+ while (1 ) {
2358
+ struct timespec ts = {0 };
2359
+ struct timespec * tsPtr = & ts ;
2360
+ if (timeout == TIMEOUT_INFINITY ) {
2361
+ tsPtr = NULL ;
2362
+
2363
+ } else if (elapsed < timeout ) {
2364
+ uint64_t delta = timeout - elapsed ;
2365
+ ts .tv_sec = delta / 1000000000UL ;
2366
+ ts .tv_nsec = delta % 1000000000UL ;
2367
+ }
2368
+
2369
+ result = ppoll (fds , 1 , tsPtr , NULL );
2370
+
2371
+ if (result == -1 && errno == EINTR ) {
2372
+ uint64_t end = mach_absolute_time ();
2373
+ elapsed += (end - start );
2374
+ start = end ;
2375
+
2376
+ } else {
2377
+ return result ;
2378
+ }
2379
+ }
2380
+ }
2381
+
2382
+ // pass in either a portSet or onePort. portSet is an epollfd, onePort is either a timerfd or an eventfd.
2383
+ // TODO: Better error handling. What should happen if we get an error on a file descriptor?
2384
+ static Boolean __CFRunLoopServiceFileDescriptors (__CFPortSet portSet , __CFPort onePort , uint64_t timeout , int * livePort ) {
2385
+ struct pollfd fdInfo = {
2386
+ .fd = (onePort == CFPORT_NULL ) ? portSet : onePort ,
2387
+ .events = POLLIN
2388
+ };
2389
+
2390
+ ssize_t result = __CFPollFileDescriptors (& fdInfo , 1 , timeout );
2391
+ if (result == 0 )
2392
+ return false;
2393
+
2394
+ CFAssert2 (result != -1 , __kCFLogAssertion , "%s(): error %d from ppoll" , __PRETTY_FUNCTION__ , errno );
2395
+
2396
+ int awokenFd ;
2397
+
2398
+ if (onePort != CFPORT_NULL ) {
2399
+ CFAssert1 (0 == (fdInfo .revents & (POLLERR |POLLHUP )), __kCFLogAssertion , "%s(): ppoll reported error for fd" , __PRETTY_FUNCTION__ );
2400
+ awokenFd = onePort ;
2401
+
2402
+ } else {
2403
+ struct epoll_event event ;
2404
+ do {
2405
+ result = epoll_wait (portSet , & event , 1 /*numEvents*/ , 0 /*timeout*/ );
2406
+ } while (result == -1 && errno == EINTR );
2407
+ CFAssert2 (result >= 0 , __kCFLogAssertion , "%s(): error %d from epoll_wait" , __PRETTY_FUNCTION__ , errno );
2408
+
2409
+ if (result == 0 )
2410
+ return false;
2411
+
2412
+ awokenFd = event .data .fd ;
2413
+ }
2414
+
2415
+ // Now we acknowledge the wakeup. awokenFd is an eventfd (or possibly a
2416
+ // timerfd ?). In either case, we read an 8-byte integer, as per eventfd(2)
2417
+ // and timerfd_create(2).
2418
+ uint64_t value ;
2419
+ do {
2420
+ result = read (awokenFd , & value , sizeof (value ));
2421
+ } while (result == -1 && errno == EINTR );
2422
+
2423
+ if (result == -1 && errno == EAGAIN ) {
2424
+ // Another thread stole the wakeup for this fd. (FIXME Can this actually
2425
+ // happen?)
2426
+ return false;
2427
+ }
2428
+
2429
+ CFAssert2 (result == sizeof (value ), __kCFLogAssertion , "%s(): error %d from read(2) while acknowledging wakeup" , __PRETTY_FUNCTION__ , errno );
2430
+
2431
+ if (livePort )
2432
+ * livePort = awokenFd ;
2433
+
2434
+ return true;
2435
+ }
2436
+
2259
2437
#elif DEPLOYMENT_TARGET_WINDOWS
2260
2438
2261
2439
#define TIMEOUT_INFINITY INFINITE
@@ -2409,6 +2587,8 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
2409
2587
#elif DEPLOYMENT_TARGET_WINDOWS
2410
2588
HANDLE livePort = NULL ;
2411
2589
Boolean windowsMessageReceived = false;
2590
+ #elif DEPLOYMENT_TARGET_LINUX
2591
+ int livePort = -1 ;
2412
2592
#endif
2413
2593
__CFPortSet waitSet = rlm -> _portSet ;
2414
2594
@@ -2433,6 +2613,10 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
2433
2613
if (__CFRunLoopServiceMachPort (dispatchPort , & msg , sizeof (msg_buffer ), & livePort , 0 , & voucherState , NULL )) {
2434
2614
goto handle_msg ;
2435
2615
}
2616
+ #elif DEPLOYMENT_TARGET_LINUX
2617
+ if (__CFRunLoopServiceFileDescriptors (CFPORTSET_NULL , dispatchPort , 0 , & livePort )) {
2618
+ goto handle_msg ;
2619
+ }
2436
2620
#elif DEPLOYMENT_TARGET_WINDOWS
2437
2621
if (__CFRunLoopWaitForMultipleObjects (NULL , & dispatchPort , 0 , 0 , & livePort , NULL )) {
2438
2622
goto handle_msg ;
@@ -2501,6 +2685,8 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
2501
2685
#elif DEPLOYMENT_TARGET_WINDOWS
2502
2686
// Here, use the app-supplied message queue mask. They will set this if they are interested in having this run loop receive windows messages.
2503
2687
__CFRunLoopWaitForMultipleObjects (waitSet , NULL , poll ? 0 : TIMEOUT_INFINITY , rlm -> _msgQMask , & livePort , & windowsMessageReceived );
2688
+ #elif DEPLOYMENT_TARGET_LINUX
2689
+ __CFRunLoopServiceFileDescriptors (waitSet , CFPORT_NULL , TIMEOUT_INFINITY , & livePort );
2504
2690
#endif
2505
2691
2506
2692
__CFRunLoopLock (rl );
@@ -2624,7 +2810,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
2624
2810
(void )mach_msg (reply , MACH_SEND_MSG , reply -> msgh_size , 0 , MACH_PORT_NULL , 0 , MACH_PORT_NULL );
2625
2811
CFAllocatorDeallocate (kCFAllocatorSystemDefault , reply );
2626
2812
}
2627
- #elif DEPLOYMENT_TARGET_WINDOWS
2813
+ #elif DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
2628
2814
sourceHandledThisLoop = __CFRunLoopDoSource1 (rl , rlm , rls ) || sourceHandledThisLoop ;
2629
2815
#endif
2630
2816
}
@@ -2740,6 +2926,13 @@ void CFRunLoopWakeUp(CFRunLoopRef rl) {
2740
2926
* wakeup pending, since the queue length is 1. */
2741
2927
ret = __CFSendTrivialMachMessage (rl -> _wakeUpPort , 0 , MACH_SEND_TIMEOUT , 0 );
2742
2928
if (ret != MACH_MSG_SUCCESS && ret != MACH_SEND_TIMED_OUT ) CRASH ("*** Unable to send message to wake up port. (%d) ***" , ret );
2929
+ #elif DEPLOYMENT_TARGET_LINUX
2930
+ int ret ;
2931
+ do {
2932
+ ret = eventfd_write (rl -> _wakeUpPort , 1 );
2933
+ } while (ret == -1 && errno == EINTR );
2934
+
2935
+ CFAssert1 (0 == ret , __kCFLogAssertion , "%s(): Unable to send wake message to eventfd" , __PRETTY_FUNCTION__ );
2743
2936
#elif DEPLOYMENT_TARGET_WINDOWS
2744
2937
SetEvent (rl -> _wakeUpPort );
2745
2938
#endif
@@ -3278,7 +3471,7 @@ static CFStringRef __CFRunLoopSourceCopyDescription(CFTypeRef cf) { /* DOES CALL
3278
3471
void * addr = rls -> _context .version0 .version == 0 ? (void * )rls -> _context .version0 .perform : (rls -> _context .version0 .version == 1 ? (void * )rls -> _context .version1 .perform : NULL );
3279
3472
#if DEPLOYMENT_TARGET_WINDOWS
3280
3473
contextDesc = CFStringCreateWithFormat (kCFAllocatorSystemDefault , NULL , CFSTR ("<CFRunLoopSource context>{version = %ld, info = %p, callout = %p}" ), rls -> _context .version0 .version , rls -> _context .version0 .info , addr );
3281
- #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3474
+ #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX
3282
3475
Dl_info info ;
3283
3476
const char * name = (dladdr (addr , & info ) && info .dli_saddr == addr && info .dli_sname ) ? info .dli_sname : "???" ;
3284
3477
contextDesc = CFStringCreateWithFormat (kCFAllocatorSystemDefault , NULL , CFSTR ("<CFRunLoopSource context>{version = %ld, info = %p, callout = %s (%p)}" ), rls -> _context .version0 .version , rls -> _context .version0 .info , name , addr );
@@ -3479,7 +3672,7 @@ static CFStringRef __CFRunLoopObserverCopyDescription(CFTypeRef cf) { /* DOES CA
3479
3672
}
3480
3673
#if DEPLOYMENT_TARGET_WINDOWS
3481
3674
result = CFStringCreateWithFormat (kCFAllocatorSystemDefault , NULL , CFSTR ("<CFRunLoopObserver %p [%p]>{valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %p, context = %@}" ), cf , CFGetAllocator (rlo ), __CFIsValid (rlo ) ? "Yes" : "No" , rlo -> _activities , __CFRunLoopObserverRepeats (rlo ) ? "Yes" : "No" , rlo -> _order , rlo -> _callout , contextDesc );
3482
- #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3675
+ #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX
3483
3676
void * addr = rlo -> _callout ;
3484
3677
Dl_info info ;
3485
3678
const char * name = (dladdr (addr , & info ) && info .dli_saddr == addr && info .dli_sname ) ? info .dli_sname : "???" ;
0 commit comments