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