@@ -69,6 +69,8 @@ typedef mach_port_t dispatch_runloop_handle_t;
69
69
typedef int dispatch_runloop_handle_t ;
70
70
#elif TARGET_OS_WIN32
71
71
typedef HANDLE dispatch_runloop_handle_t ;
72
+ #else
73
+ typedef uint64_t dispatch_runloop_handle_t ;
72
74
#endif
73
75
74
76
#if TARGET_OS_MAC
@@ -110,9 +112,12 @@ DISPATCH_EXPORT void _dispatch_main_queue_callback_4CF(void * _Null_unspecified)
110
112
dispatch_runloop_handle_t _dispatch_get_main_queue_port_4CF (void );
111
113
extern void _dispatch_main_queue_callback_4CF (void * _Null_unspecified msg );
112
114
115
+ #else
116
+ dispatch_runloop_handle_t _dispatch_get_main_queue_port_4CF (void );
117
+ extern void _dispatch_main_queue_callback_4CF (void * _Null_unspecified msg );
113
118
#endif
114
119
115
- #if TARGET_OS_WIN32 || TARGET_OS_LINUX
120
+ #if TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_BSD
116
121
CF_EXPORT _CFThreadRef _CF_pthread_main_thread_np (void );
117
122
#define pthread_main_thread_np () _CF_pthread_main_thread_np()
118
123
#endif
@@ -443,6 +448,267 @@ CF_INLINE kern_return_t __CFPortSetRemove(__CFPort port, __CFPortSet portSet) {
443
448
CF_INLINE void __CFPortSetFree (__CFPortSet portSet ) {
444
449
close (portSet );
445
450
}
451
+ #elif TARGET_OS_BSD
452
+
453
+ #include <sys/types.h>
454
+ #include <sys/event.h>
455
+ #include <sys/time.h>
456
+ #include <poll.h>
457
+
458
+ typedef uint64_t __CFPort ;
459
+ #define CFPORT_NULL ((__CFPort)-1)
460
+
461
+ // _dispatch_get_main_queue_port_4CF is a uint64_t, i.e., a __CFPort.
462
+ // That is, we can't use one type for the queue handle in Dispatch and a
463
+ // different type for __CFPort in CF.
464
+ #define __CFPORT_PACK (rfd , wfd ) (((uint64_t)(rfd) << 32) | ((uint32_t)(wfd)))
465
+ #define __CFPORT_UNPACK_W (port ) ((uint32_t)((port) & 0xffffffff))
466
+ #define __CFPORT_UNPACK_R (port ) ((uint32_t)((port) >> 32))
467
+
468
+ typedef struct ___CFPortSet {
469
+ int kq ;
470
+ } * __CFPortSet ;
471
+ #define CFPORTSET_NULL NULL
472
+
473
+ #define TIMEOUT_INFINITY UINT64_MAX
474
+
475
+ // Timers are not pipes; they are kevents on a parent kqueue.
476
+ // We must flag these to differentiate them from pipes, but we have
477
+ // to pack the (kqueue, timer ident) pair like a __CFPort.
478
+ #define __CFPORT_TIMER_PACK (ident , kq ) \
479
+ ((1ULL << 63) | ((uint64_t)(ident) << 32) | ((uint32_t)(kq)))
480
+ #define __CFPORT_IS_TIMER (port ) ((port) & (1ULL << 63))
481
+
482
+ static __CFPort __CFPortAllocate (__unused uintptr_t guard ) {
483
+ __CFPort port ;
484
+ int fds [2 ];
485
+ int r = pipe2 (fds , O_CLOEXEC | O_NONBLOCK );
486
+ if (r == -1 ) {
487
+ return CFPORT_NULL ;
488
+ }
489
+
490
+ uint32_t rfd = (uint32_t )fds [0 ], wfd = (uint32_t )fds [1 ];
491
+ port = __CFPORT_PACK (rfd , wfd );
492
+
493
+ if (__CFPORT_IS_TIMER (port )) {
494
+ // This port is not distinguishable from a flagged packed timer.
495
+ close ((int )(__CFPORT_UNPACK_W (port )));
496
+ close ((int )(__CFPORT_UNPACK_R (port )));
497
+ return CFPORT_NULL ;
498
+ }
499
+
500
+ return port ;
501
+ }
502
+
503
+ static void __CFPortTrigger (__CFPort port ) {
504
+ int wfd = (int )__CFPORT_UNPACK_W (port );
505
+ ssize_t result ;
506
+ do {
507
+ result = write (wfd , "x" , 1 );
508
+ } while (result == -1 && errno == EINTR );
509
+ }
510
+
511
+ CF_INLINE void __CFPortFree (__CFPort port , __unused uintptr_t guard ) {
512
+ close ((int )(__CFPORT_UNPACK_W (port )));
513
+ close ((int )(__CFPORT_UNPACK_R (port )));
514
+ }
515
+
516
+ #define __CFPORT_TIMER_UNPACK_ID (port ) (((port) >> 32) & 0x7fffffff)
517
+ #define __CFPORT_TIMER_UNPACK_KQ (port ) ((port) & 0xffffffff)
518
+ #define MAX_TIMERS 16
519
+ uintptr_t ident = 0 ;
520
+
521
+ static __CFPort mk_timer_create (__CFPortSet parent ) {
522
+ if (ident > MAX_TIMERS ) return CFPORT_NULL ;
523
+ ident ++ ;
524
+
525
+ int kq = parent -> kq ;
526
+ __CFPort port = __CFPORT_TIMER_PACK (ident , kq );
527
+
528
+ return port ;
529
+ }
530
+
531
+ static kern_return_t mk_timer_arm (__CFPort timer , int64_t expire_tsr ) {
532
+ uint64_t now = mach_absolute_time ();
533
+ uint64_t expire_time = __CFTSRToNanoseconds (expire_tsr );
534
+ int64_t duration = 0 ;
535
+ if (now <= expire_time ) {
536
+ duration = __CFTSRToTimeInterval (expire_time - now ) * 1000 ;
537
+ }
538
+
539
+ int id = __CFPORT_TIMER_UNPACK_ID (timer );
540
+ struct kevent tev ;
541
+ EV_SET (
542
+ & tev ,
543
+ id ,
544
+ EVFILT_TIMER ,
545
+ EV_ADD | EV_ENABLE ,
546
+ 0 ,
547
+ duration ,
548
+ (void * )timer );
549
+
550
+ int kq = __CFPORT_TIMER_UNPACK_KQ (timer );
551
+ int r = kevent (kq , & tev , 1 , NULL , 0 , NULL );
552
+
553
+ return KERN_SUCCESS ;
554
+ }
555
+
556
+ static kern_return_t mk_timer_cancel (__CFPort timer , const void * unused ) {
557
+ int id = __CFPORT_TIMER_UNPACK_ID (timer );
558
+ struct kevent tev ;
559
+ EV_SET (
560
+ & tev ,
561
+ id ,
562
+ EVFILT_TIMER ,
563
+ EV_DISABLE ,
564
+ 0 ,
565
+ 0 ,
566
+ (void * )timer );
567
+
568
+ int kq = __CFPORT_TIMER_UNPACK_KQ (timer );
569
+ int r = kevent (kq , & tev , 1 , NULL , 0 , NULL );
570
+
571
+ return KERN_SUCCESS ;
572
+ }
573
+
574
+ static kern_return_t mk_timer_destroy (__CFPort timer ) {
575
+ int id = __CFPORT_TIMER_UNPACK_ID (timer );
576
+ struct kevent tev ;
577
+ EV_SET (
578
+ & tev ,
579
+ id ,
580
+ EVFILT_TIMER ,
581
+ EV_DELETE ,
582
+ 0 ,
583
+ 0 ,
584
+ (void * )timer );
585
+
586
+ int kq = __CFPORT_TIMER_UNPACK_KQ (timer );
587
+ int r = kevent (kq , & tev , 1 , NULL , 0 , NULL );
588
+
589
+ ident -- ;
590
+ return KERN_SUCCESS ;
591
+ }
592
+
593
+ CF_INLINE __CFPortSet __CFPortSetAllocate (void ) {
594
+ struct ___CFPortSet * set = malloc (sizeof (struct ___CFPortSet ));
595
+ set -> kq = kqueue ();
596
+ return set ;
597
+ }
598
+
599
+ CF_INLINE kern_return_t __CFPortSetInsert (__CFPort port , __CFPortSet set ) {
600
+ if (__CFPORT_IS_TIMER (port )) {
601
+ return 0 ;
602
+ }
603
+
604
+ struct kevent change ;
605
+ EV_SET (& change ,
606
+ __CFPORT_UNPACK_R (port ),
607
+ EVFILT_READ ,
608
+ EV_ADD | EV_ENABLE | EV_CLEAR | EV_RECEIPT ,
609
+ 0 ,
610
+ 0 ,
611
+ (void * )port );
612
+ struct timespec timeout = {0 , 0 };
613
+ int r = kevent (set -> kq , & change , 1 , NULL , 0 , & timeout );
614
+
615
+ return 0 ;
616
+ }
617
+
618
+ CF_INLINE kern_return_t __CFPortSetRemove (__CFPort port , __CFPortSet set ) {
619
+ if (__CFPORT_IS_TIMER (port )) {
620
+ return 0 ;
621
+ }
622
+
623
+ struct kevent change ;
624
+ EV_SET (& change ,
625
+ __CFPORT_UNPACK_R (port ),
626
+ EVFILT_READ ,
627
+ EV_DELETE | EV_RECEIPT ,
628
+ 0 ,
629
+ 0 ,
630
+ (void * )port );
631
+ struct timespec timeout = {0 , 0 };
632
+ int r = kevent (set -> kq , & change , 1 , NULL , 0 , & timeout );
633
+
634
+ return 0 ;
635
+ }
636
+
637
+ CF_INLINE void __CFPortSetFree (__CFPortSet set ) {
638
+ close (set -> kq );
639
+ free (set );
640
+ }
641
+
642
+ static int __CFPollFileDescriptors (struct pollfd * fds , nfds_t nfds , uint64_t timeout ) {
643
+ uint64_t elapsed = 0 ;
644
+ uint64_t start = mach_absolute_time ();
645
+ int result = 0 ;
646
+ while (1 ) {
647
+ struct timespec ts = {0 };
648
+ struct timespec * tsPtr = & ts ;
649
+ if (timeout == TIMEOUT_INFINITY ) {
650
+ tsPtr = NULL ;
651
+ } else if (elapsed < timeout ) {
652
+ uint64_t delta = timeout - elapsed ;
653
+ ts .tv_sec = delta / 1000000000UL ;
654
+ ts .tv_nsec = delta % 1000000000UL ;
655
+ }
656
+
657
+ result = ppoll (fds , 1 , tsPtr , NULL );
658
+
659
+ if (result == -1 && errno == EINTR ) {
660
+ uint64_t end = mach_absolute_time ();
661
+ elapsed += (end - start );
662
+ start = end ;
663
+ } else {
664
+ return result ;
665
+ }
666
+ }
667
+ }
668
+
669
+ static Boolean __CFRunLoopServiceFileDescriptors (__CFPortSet set , __CFPort port , uint64_t timeout , __CFPort * livePort ) {
670
+ __CFPort awokenPort = CFPORT_NULL ;
671
+
672
+ if (port != CFPORT_NULL ) {
673
+ int rfd = __CFPORT_UNPACK_R (port );
674
+ struct pollfd fdInfo = {
675
+ .fd = rfd ,
676
+ .events = POLLIN ,
677
+ };
678
+
679
+ ssize_t result = __CFPollFileDescriptors (& fdInfo , 1 , timeout );
680
+ if (result == 0 )
681
+ return false;
682
+
683
+ awokenPort = port ;
684
+ } else {
685
+ struct kevent awake ;
686
+ struct timespec timeout = {0 , 0 };
687
+
688
+ int r = kevent (set -> kq , NULL , 0 , & awake , 1 , & timeout );
689
+
690
+ if (r == 0 ) {
691
+ return false;
692
+ }
693
+
694
+ if (awake .flags == EV_ERROR ) {
695
+ return false;
696
+ }
697
+
698
+ if (awake .filter == EVFILT_READ ) {
699
+ char x ;
700
+ r = read (awake .ident , & x , 1 );
701
+ }
702
+
703
+ awokenPort = (__CFPort )awake .udata ;
704
+ }
705
+
706
+ if (livePort )
707
+ * livePort = awokenPort ;
708
+
709
+ return true;
710
+ }
711
+
446
712
#else
447
713
#error "CFPort* stubs for this platform must be implemented
448
714
#endif
@@ -554,6 +820,11 @@ static kern_return_t mk_timer_cancel(HANDLE name, AbsoluteTime *result_time) {
554
820
}
555
821
return (int )res ;
556
822
}
823
+ #elif TARGET_OS_BSD
824
+ /*
825
+ * This implementation of the mk_timer_* stubs is defined with the
826
+ * implementation of the CFPort* stubs.
827
+ */
557
828
#else
558
829
#error "mk_timer_* stubs for this platform must be implemented"
559
830
#endif
@@ -860,9 +1131,13 @@ static CFRunLoopModeRef __CFRunLoopCopyMode(CFRunLoopRef rl, CFStringRef modeNam
860
1131
861
1132
ret = __CFPortSetInsert (queuePort , rlm -> _portSet );
862
1133
if (KERN_SUCCESS != ret ) CRASH ("*** Unable to insert timer port into port set. (%d) ***" , ret );
863
-
864
1134
#endif
1135
+ rlm -> _timerPort = CFPORT_NULL ;
1136
+ #if TARGET_OS_BSD
1137
+ rlm -> _timerPort = mk_timer_create (rlm -> _portSet );
1138
+ #else
865
1139
rlm -> _timerPort = mk_timer_create ();
1140
+ #endif
866
1141
if (rlm -> _timerPort == CFPORT_NULL ) {
867
1142
CRASH ("*** Unable to create timer Port (%d) ***" , rlm -> _timerPort );
868
1143
}
@@ -2717,6 +2992,8 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
2717
2992
Boolean windowsMessageReceived = false;
2718
2993
#elif TARGET_OS_LINUX
2719
2994
int livePort = -1 ;
2995
+ #else
2996
+ __CFPort livePort = CFPORT_NULL ;
2720
2997
#endif
2721
2998
__CFPortSet waitSet = rlm -> _portSet ;
2722
2999
@@ -2754,6 +3031,12 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
2754
3031
if (__CFRunLoopWaitForMultipleObjects (NULL , & dispatchPort , 0 , 0 , & livePort , NULL )) {
2755
3032
goto handle_msg ;
2756
3033
}
3034
+ #elif TARGET_OS_BSD
3035
+ if (__CFRunLoopServiceFileDescriptors (CFPORTSET_NULL , dispatchPort , 0 , & livePort )) {
3036
+ goto handle_msg ;
3037
+ }
3038
+ #else
3039
+ #error "invoking the port select implementation is required"
2757
3040
#endif
2758
3041
}
2759
3042
#endif
@@ -2809,6 +3092,10 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
2809
3092
__CFRunLoopWaitForMultipleObjects (waitSet , NULL , poll ? 0 : TIMEOUT_INFINITY , rlm -> _msgQMask , & livePort , & windowsMessageReceived );
2810
3093
#elif TARGET_OS_LINUX
2811
3094
__CFRunLoopServiceFileDescriptors (waitSet , CFPORT_NULL , poll ? 0 : TIMEOUT_INFINITY , & livePort );
3095
+ #elif TARGET_OS_BSD
3096
+ __CFRunLoopServiceFileDescriptors (waitSet , CFPORT_NULL , poll ? 0 : TIMEOUT_INFINITY , & livePort );
3097
+ #else
3098
+ #error "invoking the port set select implementation is required"
2812
3099
#endif
2813
3100
2814
3101
__CFRunLoopLock (rl );
@@ -2920,7 +3207,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
2920
3207
__CFRunLoopUnlock (rl );
2921
3208
_CFSetTSD (__CFTSDKeyIsInGCDMainQ , (void * )6 , NULL );
2922
3209
2923
- #if TARGET_OS_WIN32 || TARGET_OS_LINUX
3210
+ #if TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_BSD
2924
3211
void * msg = 0 ;
2925
3212
#endif
2926
3213
CFRUNLOOP_ARP_BEGIN (NULL )
@@ -3116,6 +3403,10 @@ void CFRunLoopWakeUp(CFRunLoopRef rl) {
3116
3403
CFAssert1 (0 == ret , __kCFLogAssertion , "%s(): Unable to send wake message to eventfd" , __PRETTY_FUNCTION__ );
3117
3404
#elif TARGET_OS_WIN32
3118
3405
SetEvent (rl -> _wakeUpPort );
3406
+ #elif TARGET_OS_BSD
3407
+ __CFPortTrigger (rl -> _wakeUpPort );
3408
+ #else
3409
+ #error "required"
3119
3410
#endif
3120
3411
3121
3412
cf_trace (KDEBUG_EVENT_CFRL_WAKEUP | DBG_FUNC_END , rl , 0 , 0 , 0 );
0 commit comments